]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into martin-t/rpc-acc
authorMartin Taibr <taibr.martin@gmail.com>
Fri, 15 Jun 2018 18:56:14 +0000 (20:56 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Fri, 15 Jun 2018 18:56:14 +0000 (20:56 +0200)
773 files changed:
.gitlab-ci.yml
.tx/merge-base
CMakeLists.txt
_hud_common.cfg
bal-wep-mario.cfg
bal-wep-nexuiz25.cfg
bal-wep-overkill-nerfed.cfg [new file with mode: 0644]
bal-wep-overkill.cfg [deleted file]
bal-wep-samual.cfg
bal-wep-xdf.cfg
bal-wep-xonotic.cfg
bal-wep-xpm.cfg
balance-mario.cfg
balance-overkill.cfg
balance-xdf.cfg
binds-xonotic.cfg
cmake/qcc.sh
commands.cfg
common.cs.po
common.es.po
common.he.po
common.kk@Cyrl.po
common.kw.po
common.ms.po [new file with mode: 0644]
common.pl.po
common.pt.po
common.pt_BR.po [new file with mode: 0644]
common.ru.po
common.uk.po
common.zh_CN.po
effectinfo.txt
gamemodes-server.cfg
gfx/hud/default/nade_veil.tga [new file with mode: 0644]
gfx/hud/luma/nade_veil.tga [new file with mode: 0644]
hud_luma.cfg
languages.txt
mutators.cfg
physics.cfg
qcsrc/client/_mod.inc
qcsrc/client/_mod.qh
qcsrc/client/announcer.qc
qcsrc/client/bgmscript.qc
qcsrc/client/bgmscript.qh
qcsrc/client/commands/cl_cmd.qc
qcsrc/client/commands/cl_cmd.qh
qcsrc/client/csqcmodel_hooks.qc
qcsrc/client/csqcmodel_hooks.qh
qcsrc/client/hud/hud.qc
qcsrc/client/hud/hud.qh
qcsrc/client/hud/hud_config.qc
qcsrc/client/hud/hud_config.qh
qcsrc/client/hud/panel.qh
qcsrc/client/hud/panel/ammo.qc
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/chat.qc
qcsrc/client/hud/panel/infomessages.qc
qcsrc/client/hud/panel/modicons.qc
qcsrc/client/hud/panel/quickmenu.qc
qcsrc/client/hud/panel/quickmenu.qh
qcsrc/client/hud/panel/radar.qc
qcsrc/client/hud/panel/radar.qh
qcsrc/client/hud/panel/scoreboard.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/mutators/events.qh
qcsrc/client/player_skeleton.qc
qcsrc/client/player_skeleton.qh
qcsrc/client/shownames.qh
qcsrc/client/teamradar.qh
qcsrc/client/view.qc
qcsrc/client/view.qh
qcsrc/client/wall.qc [deleted file]
qcsrc/client/wall.qh [deleted file]
qcsrc/client/weapons/projectile.qc
qcsrc/client/weapons/projectile.qh
qcsrc/common/_all.inc
qcsrc/common/campaign_file.qc
qcsrc/common/constants.qh
qcsrc/common/csqcmodel_settings.qh
qcsrc/common/deathtypes/all.qh
qcsrc/common/debug.qh
qcsrc/common/effects/all.qc
qcsrc/common/effects/effectinfo.inc
qcsrc/common/effects/effectinfo.qc
qcsrc/common/effects/qc/casings.qc
qcsrc/common/effects/qc/damageeffects.qh
qcsrc/common/effects/qc/globalsound.qc
qcsrc/common/effects/qc/modeleffects.qc
qcsrc/common/effects/qc/rubble.qh
qcsrc/common/ent_cs.qc
qcsrc/common/gamemodes/gamemode/_mod.inc
qcsrc/common/gamemodes/gamemode/_mod.qh
qcsrc/common/gamemodes/gamemode/assault/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/assault/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/assault/assault.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/assault/assault.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/clanarena/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/clanarena/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/ctf/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/ctf/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/ctf/ctf.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/ctf/ctf.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/cts/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/cts/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/cts/cts.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/cts/cts.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/deathmatch/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/deathmatch/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/domination/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/domination/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/domination/domination.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/domination/domination.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/freezetag/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/freezetag/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/invasion/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/invasion/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/invasion/invasion.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/invasion/invasion.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keepaway/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keepaway/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keyhunt/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keyhunt/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/lms/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/lms/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/lms/lms.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/lms/lms.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/nexball/nexball.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_onslaught.qc
qcsrc/common/gamemodes/gamemode/race/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/race/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/race/race.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/race/race.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tdm/_mod.inc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tdm/_mod.qh [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tdm/tdm.qc [new file with mode: 0644]
qcsrc/common/gamemodes/gamemode/tdm/tdm.qh [new file with mode: 0644]
qcsrc/common/gamemodes/sv_rules.qh
qcsrc/common/items/inventory.qh
qcsrc/common/items/item.qh
qcsrc/common/items/item/ammo.qh
qcsrc/common/items/item/armor.qh
qcsrc/common/items/item/health.qh
qcsrc/common/items/item/jetpack.qh
qcsrc/common/items/item/pickup.qh
qcsrc/common/items/item/powerup.qh
qcsrc/common/mapinfo.qh
qcsrc/common/mapobjects/_mod.inc [new file with mode: 0644]
qcsrc/common/mapobjects/_mod.qh [new file with mode: 0644]
qcsrc/common/mapobjects/defs.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/_mod.inc [new file with mode: 0644]
qcsrc/common/mapobjects/func/_mod.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/bobbing.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/bobbing.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/breakable.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/breakable.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/button.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/button.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/conveyor.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/conveyor.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/door.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/door.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/door_rotating.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/door_rotating.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/door_secret.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/door_secret.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/fourier.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/fourier.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/ladder.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/ladder.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/pendulum.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/pendulum.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/plat.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/plat.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/pointparticles.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/pointparticles.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/rainsnow.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/rainsnow.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/rotating.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/rotating.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/stardust.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/stardust.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/train.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/train.qh [new file with mode: 0644]
qcsrc/common/mapobjects/func/vectormamamam.qc [new file with mode: 0644]
qcsrc/common/mapobjects/func/vectormamamam.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/_mod.inc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/_mod.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/corner.qc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/corner.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/dynlight.qc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/dynlight.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/follow.qc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/follow.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/laser.qc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/laser.qh [new file with mode: 0644]
qcsrc/common/mapobjects/misc/teleport_dest.qc [new file with mode: 0644]
qcsrc/common/mapobjects/misc/teleport_dest.qh [new file with mode: 0644]
qcsrc/common/mapobjects/models.qc [new file with mode: 0644]
qcsrc/common/mapobjects/models.qh [new file with mode: 0644]
qcsrc/common/mapobjects/platforms.qc [new file with mode: 0644]
qcsrc/common/mapobjects/platforms.qh [new file with mode: 0644]
qcsrc/common/mapobjects/subs.qc [new file with mode: 0644]
qcsrc/common/mapobjects/subs.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/_mod.inc [new file with mode: 0644]
qcsrc/common/mapobjects/target/_mod.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/changelevel.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/changelevel.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/kill.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/kill.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/levelwarp.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/levelwarp.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/location.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/location.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/music.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/music.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/spawn.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/spawn.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/spawnpoint.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/spawnpoint.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/speaker.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/speaker.qh [new file with mode: 0644]
qcsrc/common/mapobjects/target/voicescript.qc [new file with mode: 0644]
qcsrc/common/mapobjects/target/voicescript.qh [new file with mode: 0644]
qcsrc/common/mapobjects/teleporters.qc [new file with mode: 0644]
qcsrc/common/mapobjects/teleporters.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/_mod.inc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/_mod.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/counter.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/counter.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/delay.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/delay.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/disablerelay.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/disablerelay.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/flipflop.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/flipflop.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/gamestart.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/gamestart.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/gravity.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/gravity.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/heal.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/heal.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/hurt.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/hurt.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/impulse.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/impulse.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/jumppads.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/jumppads.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/keylock.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/keylock.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/magicear.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/magicear.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/monoflop.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/monoflop.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/multi.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/multi.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/multivibrator.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/multivibrator.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_activators.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_activators.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_if.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_if.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_teamcheck.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/relay_teamcheck.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/secret.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/secret.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/swamp.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/swamp.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/teleport.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/teleport.qh [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/viewloc.qc [new file with mode: 0644]
qcsrc/common/mapobjects/trigger/viewloc.qh [new file with mode: 0644]
qcsrc/common/mapobjects/triggers.qc [new file with mode: 0644]
qcsrc/common/mapobjects/triggers.qh [new file with mode: 0644]
qcsrc/common/minigames/cl_minigames.qh
qcsrc/common/minigames/cl_minigames_hud.qh
qcsrc/common/minigames/minigame/bd.qc
qcsrc/common/minigames/minigame/c4.qc
qcsrc/common/minigames/minigame/nmm.qc
qcsrc/common/minigames/minigame/pp.qc
qcsrc/common/minigames/minigame/ps.qc
qcsrc/common/minigames/minigame/ttt.qc
qcsrc/common/minigames/sv_minigames.qc
qcsrc/common/models/model.qh
qcsrc/common/monsters/monster/mage.qc
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/sv_monsters.qc
qcsrc/common/monsters/sv_spawn.qc
qcsrc/common/monsters/sv_spawner.qh
qcsrc/common/mutators/base.qh
qcsrc/common/mutators/mutator/buffs/buffs.qh
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qh
qcsrc/common/mutators/mutator/cloaked/sv_cloaked.qc
qcsrc/common/mutators/mutator/damagetext/cl_damagetext.qc
qcsrc/common/mutators/mutator/damagetext/sv_damagetext.qc
qcsrc/common/mutators/mutator/instagib/_mod.qh
qcsrc/common/mutators/mutator/instagib/items.qh
qcsrc/common/mutators/mutator/instagib/sv_instagib.qc
qcsrc/common/mutators/mutator/instagib/sv_instagib.qh
qcsrc/common/mutators/mutator/instagib/sv_items.qc
qcsrc/common/mutators/mutator/instagib/sv_items.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/itemstime/itemstime.qc
qcsrc/common/mutators/mutator/kick_teamkiller/_mod.qh
qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qc
qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/melee_only/sv_melee_only.qc
qcsrc/common/mutators/mutator/nades/effects.inc
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/new_toys/sv_new_toys.qc
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/offhand_blaster/_mod.qh
qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc
qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.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
qcsrc/common/mutators/mutator/overkill/hmg.qc [deleted file]
qcsrc/common/mutators/mutator/overkill/hmg.qh [deleted file]
qcsrc/common/mutators/mutator/overkill/okhmg.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okhmg.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okmachinegun.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okmachinegun.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/oknex.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/oknex.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okrpc.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okrpc.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okshotgun.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/okshotgun.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/overkill/overkill.qc [deleted file]
qcsrc/common/mutators/mutator/overkill/overkill.qh [deleted file]
qcsrc/common/mutators/mutator/overkill/rpc.qh [deleted file]
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qh
qcsrc/common/mutators/mutator/overkill/sv_weapons.qc [new file with mode: 0644]
qcsrc/common/mutators/mutator/pinata/sv_pinata.qc
qcsrc/common/mutators/mutator/random_items/sv_random_items.qc
qcsrc/common/mutators/mutator/random_items/sv_random_items.qh
qcsrc/common/mutators/mutator/rocketminsta/sv_rocketminsta.qc
qcsrc/common/mutators/mutator/sandbox/sv_sandbox.qc
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc
qcsrc/common/mutators/mutator/waypoints/waypointsprites.qh
qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qc
qcsrc/common/mutators/mutator/weaponarena_random/sv_weaponarena_random.qh
qcsrc/common/net_linked.qh
qcsrc/common/net_notice.qh
qcsrc/common/notifications/all.inc
qcsrc/common/notifications/all.qc
qcsrc/common/notifications/all.qh
qcsrc/common/physics/player.qc
qcsrc/common/physics/player.qh
qcsrc/common/playerstats.qc
qcsrc/common/scores.qh
qcsrc/common/sounds/sound.qh
qcsrc/common/stats.qh
qcsrc/common/t_items.qc
qcsrc/common/t_items.qh
qcsrc/common/triggers/_mod.inc [deleted file]
qcsrc/common/triggers/_mod.qh [deleted file]
qcsrc/common/triggers/func/_mod.inc [deleted file]
qcsrc/common/triggers/func/_mod.qh [deleted file]
qcsrc/common/triggers/func/bobbing.qc [deleted file]
qcsrc/common/triggers/func/bobbing.qh [deleted file]
qcsrc/common/triggers/func/breakable.qc [deleted file]
qcsrc/common/triggers/func/breakable.qh [deleted file]
qcsrc/common/triggers/func/button.qc [deleted file]
qcsrc/common/triggers/func/button.qh [deleted file]
qcsrc/common/triggers/func/conveyor.qc [deleted file]
qcsrc/common/triggers/func/conveyor.qh [deleted file]
qcsrc/common/triggers/func/door.qc [deleted file]
qcsrc/common/triggers/func/door.qh [deleted file]
qcsrc/common/triggers/func/door_rotating.qc [deleted file]
qcsrc/common/triggers/func/door_rotating.qh [deleted file]
qcsrc/common/triggers/func/door_secret.qc [deleted file]
qcsrc/common/triggers/func/door_secret.qh [deleted file]
qcsrc/common/triggers/func/fourier.qc [deleted file]
qcsrc/common/triggers/func/fourier.qh [deleted file]
qcsrc/common/triggers/func/include.qc [deleted file]
qcsrc/common/triggers/func/include.qh [deleted file]
qcsrc/common/triggers/func/ladder.qc [deleted file]
qcsrc/common/triggers/func/ladder.qh [deleted file]
qcsrc/common/triggers/func/pendulum.qc [deleted file]
qcsrc/common/triggers/func/pendulum.qh [deleted file]
qcsrc/common/triggers/func/plat.qc [deleted file]
qcsrc/common/triggers/func/plat.qh [deleted file]
qcsrc/common/triggers/func/pointparticles.qc [deleted file]
qcsrc/common/triggers/func/pointparticles.qh [deleted file]
qcsrc/common/triggers/func/rainsnow.qc [deleted file]
qcsrc/common/triggers/func/rainsnow.qh [deleted file]
qcsrc/common/triggers/func/rotating.qc [deleted file]
qcsrc/common/triggers/func/rotating.qh [deleted file]
qcsrc/common/triggers/func/stardust.qc [deleted file]
qcsrc/common/triggers/func/stardust.qh [deleted file]
qcsrc/common/triggers/func/train.qc [deleted file]
qcsrc/common/triggers/func/train.qh [deleted file]
qcsrc/common/triggers/func/vectormamamam.qc [deleted file]
qcsrc/common/triggers/func/vectormamamam.qh [deleted file]
qcsrc/common/triggers/include.qc [deleted file]
qcsrc/common/triggers/include.qh [deleted file]
qcsrc/common/triggers/misc/_mod.inc [deleted file]
qcsrc/common/triggers/misc/_mod.qh [deleted file]
qcsrc/common/triggers/misc/corner.qc [deleted file]
qcsrc/common/triggers/misc/corner.qh [deleted file]
qcsrc/common/triggers/misc/follow.qc [deleted file]
qcsrc/common/triggers/misc/follow.qh [deleted file]
qcsrc/common/triggers/misc/include.qc [deleted file]
qcsrc/common/triggers/misc/include.qh [deleted file]
qcsrc/common/triggers/misc/laser.qc [deleted file]
qcsrc/common/triggers/misc/laser.qh [deleted file]
qcsrc/common/triggers/misc/teleport_dest.qc [deleted file]
qcsrc/common/triggers/misc/teleport_dest.qh [deleted file]
qcsrc/common/triggers/platforms.qc [deleted file]
qcsrc/common/triggers/platforms.qh [deleted file]
qcsrc/common/triggers/subs.qc [deleted file]
qcsrc/common/triggers/subs.qh [deleted file]
qcsrc/common/triggers/target/_mod.inc [deleted file]
qcsrc/common/triggers/target/_mod.qh [deleted file]
qcsrc/common/triggers/target/changelevel.qc [deleted file]
qcsrc/common/triggers/target/changelevel.qh [deleted file]
qcsrc/common/triggers/target/include.qc [deleted file]
qcsrc/common/triggers/target/include.qh [deleted file]
qcsrc/common/triggers/target/kill.qc [deleted file]
qcsrc/common/triggers/target/kill.qh [deleted file]
qcsrc/common/triggers/target/levelwarp.qc [deleted file]
qcsrc/common/triggers/target/levelwarp.qh [deleted file]
qcsrc/common/triggers/target/location.qc [deleted file]
qcsrc/common/triggers/target/location.qh [deleted file]
qcsrc/common/triggers/target/music.qc [deleted file]
qcsrc/common/triggers/target/music.qh [deleted file]
qcsrc/common/triggers/target/spawn.qc [deleted file]
qcsrc/common/triggers/target/spawn.qh [deleted file]
qcsrc/common/triggers/target/spawnpoint.qc [deleted file]
qcsrc/common/triggers/target/spawnpoint.qh [deleted file]
qcsrc/common/triggers/target/speaker.qc [deleted file]
qcsrc/common/triggers/target/speaker.qh [deleted file]
qcsrc/common/triggers/target/voicescript.qc [deleted file]
qcsrc/common/triggers/target/voicescript.qh [deleted file]
qcsrc/common/triggers/teleporters.qc [deleted file]
qcsrc/common/triggers/teleporters.qh [deleted file]
qcsrc/common/triggers/trigger/_mod.inc [deleted file]
qcsrc/common/triggers/trigger/_mod.qh [deleted file]
qcsrc/common/triggers/trigger/counter.qc [deleted file]
qcsrc/common/triggers/trigger/counter.qh [deleted file]
qcsrc/common/triggers/trigger/delay.qc [deleted file]
qcsrc/common/triggers/trigger/delay.qh [deleted file]
qcsrc/common/triggers/trigger/disablerelay.qc [deleted file]
qcsrc/common/triggers/trigger/disablerelay.qh [deleted file]
qcsrc/common/triggers/trigger/flipflop.qc [deleted file]
qcsrc/common/triggers/trigger/flipflop.qh [deleted file]
qcsrc/common/triggers/trigger/gamestart.qc [deleted file]
qcsrc/common/triggers/trigger/gamestart.qh [deleted file]
qcsrc/common/triggers/trigger/gravity.qc [deleted file]
qcsrc/common/triggers/trigger/gravity.qh [deleted file]
qcsrc/common/triggers/trigger/heal.qc [deleted file]
qcsrc/common/triggers/trigger/heal.qh [deleted file]
qcsrc/common/triggers/trigger/hurt.qc [deleted file]
qcsrc/common/triggers/trigger/hurt.qh [deleted file]
qcsrc/common/triggers/trigger/impulse.qc [deleted file]
qcsrc/common/triggers/trigger/impulse.qh [deleted file]
qcsrc/common/triggers/trigger/include.qc [deleted file]
qcsrc/common/triggers/trigger/include.qh [deleted file]
qcsrc/common/triggers/trigger/jumppads.qc [deleted file]
qcsrc/common/triggers/trigger/jumppads.qh [deleted file]
qcsrc/common/triggers/trigger/keylock.qc [deleted file]
qcsrc/common/triggers/trigger/keylock.qh [deleted file]
qcsrc/common/triggers/trigger/magicear.qc [deleted file]
qcsrc/common/triggers/trigger/magicear.qh [deleted file]
qcsrc/common/triggers/trigger/monoflop.qc [deleted file]
qcsrc/common/triggers/trigger/monoflop.qh [deleted file]
qcsrc/common/triggers/trigger/multi.qc [deleted file]
qcsrc/common/triggers/trigger/multi.qh [deleted file]
qcsrc/common/triggers/trigger/multivibrator.qc [deleted file]
qcsrc/common/triggers/trigger/multivibrator.qh [deleted file]
qcsrc/common/triggers/trigger/relay.qc [deleted file]
qcsrc/common/triggers/trigger/relay.qh [deleted file]
qcsrc/common/triggers/trigger/relay_activators.qc [deleted file]
qcsrc/common/triggers/trigger/relay_activators.qh [deleted file]
qcsrc/common/triggers/trigger/relay_if.qc [deleted file]
qcsrc/common/triggers/trigger/relay_if.qh [deleted file]
qcsrc/common/triggers/trigger/relay_teamcheck.qc [deleted file]
qcsrc/common/triggers/trigger/relay_teamcheck.qh [deleted file]
qcsrc/common/triggers/trigger/secret.qc [deleted file]
qcsrc/common/triggers/trigger/secret.qh [deleted file]
qcsrc/common/triggers/trigger/swamp.qc [deleted file]
qcsrc/common/triggers/trigger/swamp.qh [deleted file]
qcsrc/common/triggers/trigger/teleport.qc [deleted file]
qcsrc/common/triggers/trigger/teleport.qh [deleted file]
qcsrc/common/triggers/trigger/viewloc.qc [deleted file]
qcsrc/common/triggers/trigger/viewloc.qh [deleted file]
qcsrc/common/triggers/triggers.qc [deleted file]
qcsrc/common/triggers/triggers.qh [deleted file]
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/sv_turrets.qh
qcsrc/common/turrets/turret/ewheel.qc
qcsrc/common/turrets/turret/plasma.qc
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/turrets/turret/plasma_dual.qh
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/turrets/util.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/common/vehicles/sv_vehicles.qh
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/viewloc.qc
qcsrc/common/weapons/all.qc
qcsrc/common/weapons/all.qh
qcsrc/common/weapons/weapon.qh
qcsrc/common/weapons/weapon/arc.qc
qcsrc/common/weapons/weapon/crylink.qc
qcsrc/common/weapons/weapon/crylink.qh
qcsrc/common/weapons/weapon/devastator.qc
qcsrc/common/weapons/weapon/devastator.qh
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.qh
qcsrc/common/weapons/weapon/porto.qc
qcsrc/common/weapons/weapon/porto.qh
qcsrc/common/weapons/weapon/rifle.qc
qcsrc/common/weapons/weapon/rifle.qh
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/tuba.qh
qcsrc/common/weapons/weapon/vaporizer.qc
qcsrc/common/weapons/weapon/vaporizer.qh
qcsrc/common/weapons/weapon/vortex.qc
qcsrc/common/weapons/weapon/vortex.qh
qcsrc/common/wepent.qc
qcsrc/common/wepent.qh
qcsrc/ecs/systems/physics.qc
qcsrc/ecs/systems/sv_physics.qc
qcsrc/lib/_all.inc
qcsrc/lib/_mod.inc
qcsrc/lib/_mod.qh
qcsrc/lib/accumulate.qh
qcsrc/lib/color.qh
qcsrc/lib/compiler.qh
qcsrc/lib/cvar.qh
qcsrc/lib/defer.qh
qcsrc/lib/math.qh
qcsrc/lib/matrix/command.qc
qcsrc/lib/matrix/matrix.qc
qcsrc/lib/misc.qh
qcsrc/lib/net.qh
qcsrc/lib/noise.qh
qcsrc/lib/oo.qh
qcsrc/lib/promise.qc [new file with mode: 0644]
qcsrc/lib/promise.qh [new file with mode: 0644]
qcsrc/lib/registry.qh
qcsrc/lib/replicate.qh
qcsrc/lib/self.qh
qcsrc/lib/sortlist.qh
qcsrc/lib/spawnfunc.qh
qcsrc/lib/static.qh
qcsrc/lib/stats.qh
qcsrc/lib/string.qh
qcsrc/lib/test.qh
qcsrc/lib/urllib.qc
qcsrc/lib/warpzone/mathlib.qc
qcsrc/lib/warpzone/server.qc
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/item/inputbox.qc
qcsrc/menu/item/label.qc
qcsrc/menu/menu.qc
qcsrc/menu/mutators/_mod.inc
qcsrc/menu/mutators/_mod.qh
qcsrc/menu/mutators/events.qc [new file with mode: 0644]
qcsrc/menu/mutators/events.qh
qcsrc/menu/xonotic/campaign.qc
qcsrc/menu/xonotic/crosshairpreview.qc
qcsrc/menu/xonotic/cvarlist.qc
qcsrc/menu/xonotic/demolist.qc
qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc
qcsrc/menu/xonotic/dialog_hudpanel_ammo.qh
qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc
qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh
qcsrc/menu/xonotic/dialog_hudpanel_chat.qc
qcsrc/menu/xonotic/dialog_hudpanel_chat.qh
qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc
qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qh
qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc
qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh
qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc
qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qh
qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc
qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qh
qcsrc/menu/xonotic/dialog_hudpanel_modicons.qc
qcsrc/menu/xonotic/dialog_hudpanel_modicons.qh
qcsrc/menu/xonotic/dialog_hudpanel_notification.qc
qcsrc/menu/xonotic/dialog_hudpanel_notification.qh
qcsrc/menu/xonotic/dialog_hudpanel_physics.qc
qcsrc/menu/xonotic/dialog_hudpanel_physics.qh
qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc
qcsrc/menu/xonotic/dialog_hudpanel_powerups.qh
qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc
qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qh
qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc
qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qh
qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qc
qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qh
qcsrc/menu/xonotic/dialog_hudpanel_radar.qc
qcsrc/menu/xonotic/dialog_hudpanel_radar.qh
qcsrc/menu/xonotic/dialog_hudpanel_score.qc
qcsrc/menu/xonotic/dialog_hudpanel_score.qh
qcsrc/menu/xonotic/dialog_hudpanel_timer.qc
qcsrc/menu/xonotic/dialog_hudpanel_timer.qh
qcsrc/menu/xonotic/dialog_hudpanel_vote.qc
qcsrc/menu/xonotic/dialog_hudpanel_vote.qh
qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc
qcsrc/menu/xonotic/dialog_hudpanel_weapons.qh
qcsrc/menu/xonotic/dialog_multiplayer_create.qc
qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc
qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc
qcsrc/menu/xonotic/dialog_multiplayer_join.qc
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc
qcsrc/menu/xonotic/hudskinlist.qc
qcsrc/menu/xonotic/keybinder.qc
qcsrc/menu/xonotic/mainwindow.qc
qcsrc/menu/xonotic/maplist.qc
qcsrc/menu/xonotic/playermodel.qc
qcsrc/menu/xonotic/screenshotimage.qc
qcsrc/menu/xonotic/screenshotlist.qc
qcsrc/menu/xonotic/serverlist.qc
qcsrc/menu/xonotic/serverlist.qh
qcsrc/menu/xonotic/soundlist.qc
qcsrc/menu/xonotic/statslist.qc
qcsrc/menu/xonotic/util.qc
qcsrc/menu/xonotic/util.qh
qcsrc/menu/xonotic/weaponarenacheckbox.qc
qcsrc/server/_mod.inc
qcsrc/server/_mod.qh
qcsrc/server/antilag.qc
qcsrc/server/antilag.qh
qcsrc/server/autocvars.qh
qcsrc/server/bot/api.qh
qcsrc/server/bot/default/aim.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/bot/default/cvars.qh
qcsrc/server/bot/default/havocbot/havocbot.qc
qcsrc/server/bot/default/havocbot/roles.qc
qcsrc/server/bot/default/navigation.qc
qcsrc/server/bot/default/scripting.qc
qcsrc/server/bot/default/waypoints.qc
qcsrc/server/bot/default/waypoints.qh
qcsrc/server/campaign.qc
qcsrc/server/cheats.qc
qcsrc/server/cheats.qh
qcsrc/server/client.qc
qcsrc/server/client.qh
qcsrc/server/command/banning.qh
qcsrc/server/command/cmd.qc
qcsrc/server/command/common.qc
qcsrc/server/command/radarmap.qc
qcsrc/server/command/sv_cmd.qc
qcsrc/server/command/vote.qc
qcsrc/server/command/vote.qh
qcsrc/server/compat/quake3.qc
qcsrc/server/compat/quake3.qh
qcsrc/server/constants.qh
qcsrc/server/defs.qh
qcsrc/server/g_damage.qc
qcsrc/server/g_damage.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_hook.qh
qcsrc/server/g_lights.qc [deleted file]
qcsrc/server/g_lights.qh [deleted file]
qcsrc/server/g_models.qc [deleted file]
qcsrc/server/g_models.qh [deleted file]
qcsrc/server/g_subs.qc [deleted file]
qcsrc/server/g_subs.qh [deleted file]
qcsrc/server/g_world.qc
qcsrc/server/g_world.qh
qcsrc/server/ipban.qc
qcsrc/server/ipban.qh
qcsrc/server/item_key.qc
qcsrc/server/items.qc
qcsrc/server/items.qh
qcsrc/server/mapvoting.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/miscfunctions.qh
qcsrc/server/mutators/_mod.inc
qcsrc/server/mutators/_mod.qh
qcsrc/server/mutators/events.qc [new file with mode: 0644]
qcsrc/server/mutators/events.qh
qcsrc/server/mutators/gamemode.qh [deleted file]
qcsrc/server/mutators/mutator.qh [deleted file]
qcsrc/server/mutators/mutator/_mod.inc [deleted file]
qcsrc/server/mutators/mutator/_mod.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_assault.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_assault.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_ca.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_ca.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_ctf.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_ctf.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_cts.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_cts.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_deathmatch.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_deathmatch.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_domination.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_domination.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_freezetag.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_freezetag.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_invasion.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_invasion.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_keepaway.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_keepaway.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_keyhunt.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_keyhunt.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_lms.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_lms.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_race.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_race.qh [deleted file]
qcsrc/server/mutators/mutator/gamemode_tdm.qc [deleted file]
qcsrc/server/mutators/mutator/gamemode_tdm.qh [deleted file]
qcsrc/server/pathlib/debug.qc
qcsrc/server/pathlib/debug.qh
qcsrc/server/pathlib/main.qc
qcsrc/server/pathlib/pathlib.qh
qcsrc/server/player.qc
qcsrc/server/player.qh
qcsrc/server/portals.qc
qcsrc/server/portals.qh
qcsrc/server/race.qc
qcsrc/server/race.qh
qcsrc/server/resources.qc
qcsrc/server/scores.qc
qcsrc/server/scores.qh
qcsrc/server/scores_rules.qc
qcsrc/server/spawnpoints.qc
qcsrc/server/steerlib.qc
qcsrc/server/steerlib.qh
qcsrc/server/sv_main.qc
qcsrc/server/sv_main.qh
qcsrc/server/teamplay.qc
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/common.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/weaponsystem.qc
qcsrc/tools/qcc.sh
randomitems-overkill.cfg [new file with mode: 0644]
randomitems-xonotic.cfg
ruleset-XDF.cfg
ruleset-XPM.cfg
ruleset-nexuiz.cfg [new file with mode: 0644]
ruleset-overkill.cfg
sound/misc/kill.ogg [deleted file]
sound/misc/kill.wav [new file with mode: 0644]
xonotic-client.cfg
xonotic-server.cfg

index 6a842143433c4aad65a2cdaae25dd6aca2212806..e50392ca6a8e1c49df20f3465838b7a6052041c0 100644 (file)
@@ -19,7 +19,7 @@ test_compilation_units:
 test_sv_game:
   stage: test
   script:
-    - git clone --depth=1 --branch=master https://gitlab.com/xonotic/darkplaces.git darkplaces
+    - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces
     - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"
     - cd ..
 
@@ -29,7 +29,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache
     - make
-    - EXPECT=eb10d49149a894afd1c3e8af610dc98f
+    - EXPECT=033546d32426e6409458fb39d0130f56
     - HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
       | tee /dev/stderr
       | grep '^:'
@@ -44,7 +44,7 @@ test_sv_game:
 test_sv_unit:
   stage: test
   script:
-    - git clone --depth=1 --branch=master https://gitlab.com/xonotic/darkplaces.git darkplaces
+    - git clone --depth=1 --branch=div0-stable https://gitlab.com/xonotic/darkplaces.git darkplaces
     - cd darkplaces && make sv-debug -j $(nproc) && export ENGINE="$PWD/darkplaces-dedicated -xonotic"
     - cd ..
 
index 946c98fc60de9289488e12b541a279166d439105..9745f61361ea974460edaf8e9c90a96700d78cb1 100644 (file)
@@ -1 +1 @@
-Fri Mar  2 07:24:40 CET 2018
+Sun Jun  3 07:24:16 CEST 2018
index 9a66f9fd2ef4985cf06e873e7435c6735b8d1f91..f732e5b7afdece143b8c5de31f569375293bcc72 100644 (file)
@@ -125,12 +125,12 @@ copy(progs)
 copy(menu)
 
 function(pack prog)
-    add_custom_target(${prog}.pk3
+    add_custom_target(${prog}.pk3 ALL
             DEPENDS ${prog}-${GIT_DESC}.pk3
             )
     add_custom_command(OUTPUT ${prog}-${GIT_DESC}.pk3
             DEPENDS ${prog}
-            COMMAND ${CMAKE_COMMAND} -E echo "http://xonotic.org" > "${prog}-${GIT_DESC}.txt"
+            COMMAND ${CMAKE_COMMAND} -E echo "https://xonotic.org" > "${prog}-${GIT_DESC}.txt"
             COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:${prog}>/${prog}.dat" "${prog}-${GIT_DESC}.dat"
             COMMAND ${CMAKE_COMMAND} -E copy "$<TARGET_FILE_DIR:${prog}>/${prog}.lno" "${prog}-${GIT_DESC}.lno"
             COMMAND ${CMAKE_COMMAND} -E tar "cfv" "${prog}-${GIT_DESC}.pk3" --format=zip
index 622e581d3b2e5b096a8d7354a350ad6ccec1265a..3631df7eb4882cc7d2dc9d85063c845bff47c887 100644 (file)
@@ -93,7 +93,7 @@ seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_new_weight 0.1 "
 seta hud_panel_engineinfo_framecounter_exponentialmovingaverage_instantupdate_change_threshold 0.5 "threshold for fps change when to update instantly, to make big fps changes update faster"
 
 seta hud_panel_physics_acceleration_movingaverage 1 "use an averaging method for calculating acceleration instead of the real value"
-seta hud_panel_physics_update_interval 0.0666 "how often (in seconds) numeric values get updated on screen"
+seta hud_panel_physics_update_interval 0.016 "how often (in seconds) numeric values get updated on screen"
 seta hud_panel_physics_speed_unit "1" "speed unit (1 = qu/s, 2 = m/s, 3 = km/h, 4 = mph, 5 = knots)"
 
 seta hud_panel_itemstime_progressbar_maxtime "30" "when left time is at least this amount, the status bar is full"
@@ -113,7 +113,7 @@ seta hud_panel_scoreboard_maxheight 0.6 "max height of the scoreboard; a few pla
 seta hud_panel_scoreboard_others_showscore 1 "show scores of players listed in the last row when the scoreboard reaches the max height"
 seta hud_panel_scoreboard_spectators_showping 1 "show ping of spectators"
 seta hud_panel_scoreboard_spectators_aligned 0 "align spectators in columns"
-seta hud_panel_scoreboard_minwidth 0.4 "minimum width of the scoreboard"
+seta hud_panel_scoreboard_minwidth 0.6 "minimum width of the scoreboard"
 
 // hud panel aliases
 alias quickmenu "cl_cmd hud quickmenu ${* ?}"
index 57d5d745df29da9d5b3dfc3cd8f0a7611bbeeeb5..89e2e62fa09ea7c9b968edc9928e4dd6b1828ea0 100644 (file)
@@ -1,6 +1,6 @@
 // {{{ #1: Blaster
 set g_balance_blaster_primary_animtime 0.2
-set g_balance_blaster_primary_damage 25
+set g_balance_blaster_primary_damage 20
 set g_balance_blaster_primary_delay 0
 set g_balance_blaster_primary_edgedamage 12.5
 set g_balance_blaster_primary_force 300
@@ -60,8 +60,8 @@ set g_balance_shotgun_secondary_alt_animtime 0.2
 set g_balance_shotgun_secondary_alt_refire 1.2
 set g_balance_shotgun_switchdelay_drop 0.2
 set g_balance_shotgun_switchdelay_raise 0.2
-set g_balance_shotgun_weaponreplace ""
-set g_balance_shotgun_weaponstart 1
+set g_balance_shotgun_weaponreplace "shockwave"
+set g_balance_shotgun_weaponstart 0
 set g_balance_shotgun_weaponstartoverride -1
 set g_balance_shotgun_weaponthrowable 1
 // }}}
@@ -75,7 +75,7 @@ set g_balance_machinegun_burst_speed 0
 set g_balance_machinegun_first 1
 set g_balance_machinegun_first_ammo 1
 set g_balance_machinegun_first_damage 14
-set g_balance_machinegun_first_force 5
+set g_balance_machinegun_first_force 3
 set g_balance_machinegun_first_refire 0.125
 set g_balance_machinegun_first_spread 0.03
 set g_balance_machinegun_mode 1
@@ -87,12 +87,12 @@ set g_balance_machinegun_spread_max 0.05
 set g_balance_machinegun_spread_min 0.02
 set g_balance_machinegun_sustained_ammo 1
 set g_balance_machinegun_sustained_damage 10
-set g_balance_machinegun_sustained_force 5
+set g_balance_machinegun_sustained_force 3
 set g_balance_machinegun_sustained_refire 0.1
 set g_balance_machinegun_sustained_spread 0.03
 set g_balance_machinegun_switchdelay_drop 0.2
 set g_balance_machinegun_switchdelay_raise 0.2
-set g_balance_machinegun_weaponreplace ""
+set g_balance_machinegun_weaponreplace "arc"
 set g_balance_machinegun_weaponstart 0
 set g_balance_machinegun_weaponstartoverride -1
 set g_balance_machinegun_weaponthrowable 1
@@ -219,7 +219,7 @@ set g_balance_electro_secondary_speed 1000
 set g_balance_electro_secondary_speed_up 200
 set g_balance_electro_secondary_speed_z 0
 set g_balance_electro_secondary_spread 0
-set g_balance_electro_secondary_stick 1
+set g_balance_electro_secondary_stick 0
 set g_balance_electro_secondary_touchexplode 1
 set g_balance_electro_switchdelay_drop 0.2
 set g_balance_electro_switchdelay_raise 0.2
@@ -251,7 +251,7 @@ set g_balance_crylink_primary_other_lifetime 5
 set g_balance_crylink_primary_radius 80
 set g_balance_crylink_primary_refire 0.7
 set g_balance_crylink_primary_shots 6
-set g_balance_crylink_primary_speed 2000
+set g_balance_crylink_primary_speed 4000
 set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
@@ -260,9 +260,9 @@ set g_balance_crylink_secondary_ammo 2
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
-set g_balance_crylink_secondary_damage 10
-set g_balance_crylink_secondary_edgedamage 5
-set g_balance_crylink_secondary_force -250
+set g_balance_crylink_secondary_damage 8
+set g_balance_crylink_secondary_edgedamage 4
+set g_balance_crylink_secondary_force -200
 set g_balance_crylink_secondary_joindelay 0
 set g_balance_crylink_secondary_joinexplode 0
 set g_balance_crylink_secondary_joinexplode_damage 0
@@ -303,7 +303,8 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 6
 set g_balance_vortex_primary_animtime 0.4
-set g_balance_vortex_primary_damage 70
+set g_balance_vortex_primary_armorpierce 0
+set g_balance_vortex_primary_damage 65
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
 set g_balance_vortex_primary_damagefalloff_maxdist 0
@@ -315,6 +316,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -371,7 +373,7 @@ set g_balance_hagar_secondary_speed 2000
 set g_balance_hagar_secondary_spread 0
 set g_balance_hagar_switchdelay_drop 0.2
 set g_balance_hagar_switchdelay_raise 0.2
-set g_balance_hagar_weaponreplace ""
+set g_balance_hagar_weaponreplace "0"
 set g_balance_hagar_weaponstart 0
 set g_balance_hagar_weaponstartoverride -1
 set g_balance_hagar_weaponthrowable 1
@@ -436,6 +438,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -722,7 +725,7 @@ set g_balance_shockwave_melee_traces 10
 set g_balance_shockwave_switchdelay_drop 0.2
 set g_balance_shockwave_switchdelay_raise 0.2
 set g_balance_shockwave_weaponreplace ""
-set g_balance_shockwave_weaponstart 0
+set g_balance_shockwave_weaponstart 1
 set g_balance_shockwave_weaponstartoverride -1
 set g_balance_shockwave_weaponthrowable 0
 // }}}
@@ -750,7 +753,7 @@ set g_balance_arc_beam_heat 0
 set g_balance_arc_burst_heat 5
 set g_balance_arc_beam_maxangle 10
 set g_balance_arc_beam_nonplayerdamage 80
-set g_balance_arc_beam_range 1000
+set g_balance_arc_beam_range 1250
 set g_balance_arc_beam_refire 0.25
 set g_balance_arc_beam_returnspeed 8
 set g_balance_arc_beam_tightness 0.5
@@ -777,44 +780,183 @@ set g_balance_arc_weaponstart 0
 set g_balance_arc_weaponstartoverride -1
 set g_balance_arc_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
+// }}}
+// {{{ Overkill Shotgun
+set g_balance_okshotgun_primary_ammo 3
+set g_balance_okshotgun_primary_animtime 0.65
+set g_balance_okshotgun_primary_bot_range 512
+set g_balance_okshotgun_primary_bullets 10
+set g_balance_okshotgun_primary_damage 17
+set g_balance_okshotgun_primary_force 80
+set g_balance_okshotgun_primary_refire 0.75
+set g_balance_okshotgun_primary_solidpenetration 3.8
+set g_balance_okshotgun_primary_spread 0.07
+set g_balance_okshotgun_reload_ammo 24
+set g_balance_okshotgun_reload_time 2
+set g_balance_okshotgun_secondary_animtime 0.2
+set g_balance_okshotgun_secondary_damage 25
+set g_balance_okshotgun_secondary_delay 0
+set g_balance_okshotgun_secondary_edgedamage 12.5
+set g_balance_okshotgun_secondary_force 300
+set g_balance_okshotgun_secondary_lifetime 5
+set g_balance_okshotgun_secondary_radius 70
+set g_balance_okshotgun_secondary_refire 0.7
+set g_balance_okshotgun_secondary_refire_type 1
+set g_balance_okshotgun_secondary_shotangle 0
+set g_balance_okshotgun_secondary_speed 6000
+set g_balance_okshotgun_secondary_spread 0
+set g_balance_okshotgun_switchdelay_drop 0.2
+set g_balance_okshotgun_switchdelay_raise 0.2
+set g_balance_okshotgun_weaponreplace ""
+set g_balance_okshotgun_weaponstart 0
+set g_balance_okshotgun_weaponstartoverride -1
+set g_balance_okshotgun_weaponthrowable 1
+// }}}
+// {{{ Overkill Machine Gun
+set g_balance_okmachinegun_primary_ammo 1
+set g_balance_okmachinegun_primary_damage 25
+set g_balance_okmachinegun_primary_force 5
+set g_balance_okmachinegun_primary_refire 0.1
+set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_spread_add 0.012
+set g_balance_okmachinegun_primary_spread_max 0.05
+set g_balance_okmachinegun_primary_spread_min 0
+set g_balance_okmachinegun_reload_ammo 30
+set g_balance_okmachinegun_reload_time 1.5
+set g_balance_okmachinegun_secondary_animtime 0.2
+set g_balance_okmachinegun_secondary_damage 25
+set g_balance_okmachinegun_secondary_delay 0
+set g_balance_okmachinegun_secondary_edgedamage 12.5
+set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_lifetime 5
+set g_balance_okmachinegun_secondary_radius 70
+set g_balance_okmachinegun_secondary_refire 0.7
+set g_balance_okmachinegun_secondary_refire_type 1
+set g_balance_okmachinegun_secondary_shotangle 0
+set g_balance_okmachinegun_secondary_speed 6000
+set g_balance_okmachinegun_secondary_spread 0
+set g_balance_okmachinegun_switchdelay_drop 0.2
+set g_balance_okmachinegun_switchdelay_raise 0.2
+set g_balance_okmachinegun_weaponreplace ""
+set g_balance_okmachinegun_weaponstart 0
+set g_balance_okmachinegun_weaponstartoverride -1
+set g_balance_okmachinegun_weaponthrowable 1
+// }}}
+// {{{ Overkill Nex
+set g_balance_oknex_charge 0
+set g_balance_oknex_charge_animlimit 0.5
+set g_balance_oknex_charge_limit 1
+set g_balance_oknex_charge_maxspeed 800
+set g_balance_oknex_charge_mindmg 40
+set g_balance_oknex_charge_minspeed 400
+set g_balance_oknex_charge_rate 0.6
+set g_balance_oknex_charge_rot_pause 0
+set g_balance_oknex_charge_rot_rate 0
+set g_balance_oknex_charge_shot_multiplier 0
+set g_balance_oknex_charge_start 0.5
+set g_balance_oknex_charge_velocity_rate 0
+set g_balance_oknex_primary_ammo 10
+set g_balance_oknex_primary_animtime 0.65
+set g_balance_oknex_primary_damage 100
+set g_balance_oknex_primary_damagefalloff_forcehalflife 0
+set g_balance_oknex_primary_damagefalloff_halflife 0
+set g_balance_oknex_primary_damagefalloff_maxdist 0
+set g_balance_oknex_primary_damagefalloff_mindist 0
+set g_balance_oknex_primary_force 500
+set g_balance_oknex_primary_refire 1
+set g_balance_oknex_reload_ammo 50
+set g_balance_oknex_reload_time 2
+set g_balance_oknex_secondary 2
+set g_balance_oknex_secondary_ammo 0
+set g_balance_oknex_secondary_animtime 0.2
+set g_balance_oknex_secondary_chargepool 0
+set g_balance_oknex_secondary_chargepool_pause_regen 1
+set g_balance_oknex_secondary_chargepool_regen 0.15
+set g_balance_oknex_secondary_damage 25
+set g_balance_oknex_secondary_damagefalloff_forcehalflife 0
+set g_balance_oknex_secondary_damagefalloff_halflife 0
+set g_balance_oknex_secondary_damagefalloff_maxdist 0
+set g_balance_oknex_secondary_damagefalloff_mindist 0
+set g_balance_oknex_secondary_force 300
+set g_balance_oknex_secondary_refire 0.7
+set g_balance_oknex_secondary_refire_type 1
+set g_balance_oknex_secondary_delay 0
+set g_balance_oknex_secondary_edgedamage 12.5
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 70
+set g_balance_oknex_secondary_shotangle 0
+set g_balance_oknex_secondary_speed 6000
+set g_balance_oknex_secondary_spread 0
+set g_balance_oknex_switchdelay_drop 0.2
+set g_balance_oknex_switchdelay_raise 0.2
+set g_balance_oknex_weaponreplace ""
+set g_balance_oknex_weaponstart 0
+set g_balance_oknex_weaponstartoverride -1
+set g_balance_oknex_weaponthrowable 1
 // }}}
index f7d912ca773649743831610ab52209ee3704dee3..b1a83000f6f41d18345045cfd9d7b44c9c41442f 100644 (file)
@@ -303,6 +303,7 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 5
 set g_balance_vortex_primary_animtime 0.3
+set g_balance_vortex_primary_armorpierce 0
 set g_balance_vortex_primary_damage 100
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
@@ -315,6 +316,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -436,6 +438,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage -1
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -777,44 +780,70 @@ set g_balance_arc_weaponstart 0
 set g_balance_arc_weaponstartoverride -1
 set g_balance_arc_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
 // }}}
diff --git a/bal-wep-overkill-nerfed.cfg b/bal-wep-overkill-nerfed.cfg
new file mode 100644 (file)
index 0000000..e4fb022
--- /dev/null
@@ -0,0 +1,116 @@
+// This config file is for overkill weapons that were nerfed to have the same
+// stats as vanilla weapons, secondary attack uses stats of vanilla blaster.
+
+// {{{ Overkill Shotgun
+set g_balance_okshotgun_primary_ammo 1
+set g_balance_okshotgun_primary_animtime 0.2
+set g_balance_okshotgun_primary_bot_range 512
+set g_balance_okshotgun_primary_bullets 12
+set g_balance_okshotgun_primary_damage 4
+set g_balance_okshotgun_primary_force 15
+set g_balance_okshotgun_primary_refire 0.75
+set g_balance_okshotgun_primary_solidpenetration 3.8
+set g_balance_okshotgun_primary_spread 0.12
+set g_balance_okshotgun_reload_ammo 0
+set g_balance_okshotgun_reload_time 2
+set g_balance_okshotgun_secondary_animtime 0.2
+set g_balance_okshotgun_secondary_damage 20
+set g_balance_okshotgun_secondary_delay 0
+set g_balance_okshotgun_secondary_edgedamage 10
+set g_balance_okshotgun_secondary_force 300
+set g_balance_okshotgun_secondary_lifetime 5
+set g_balance_okshotgun_secondary_radius 60
+set g_balance_okshotgun_secondary_refire 0.7
+set g_balance_okshotgun_secondary_refire_type 0
+set g_balance_okshotgun_secondary_shotangle 0
+set g_balance_okshotgun_secondary_speed 6000
+set g_balance_okshotgun_secondary_spread 0
+set g_balance_okshotgun_switchdelay_drop 0.2
+set g_balance_okshotgun_switchdelay_raise 0.2
+set g_balance_okshotgun_weaponreplace ""
+set g_balance_okshotgun_weaponstart 0
+set g_balance_okshotgun_weaponstartoverride -1
+set g_balance_okshotgun_weaponthrowable 1
+// }}}
+// {{{ Overkill Machine Gun
+set g_balance_okmachinegun_primary_ammo 1
+set g_balance_okmachinegun_primary_damage 10
+set g_balance_okmachinegun_primary_force 3
+set g_balance_okmachinegun_primary_refire 0.1
+set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_spread_add 0.012
+set g_balance_okmachinegun_primary_spread_max 0.05
+set g_balance_okmachinegun_primary_spread_min 0.02
+set g_balance_okmachinegun_reload_ammo 60
+set g_balance_okmachinegun_reload_time 2
+set g_balance_okmachinegun_secondary_animtime 0.2
+set g_balance_okmachinegun_secondary_damage 20
+set g_balance_okmachinegun_secondary_delay 0
+set g_balance_okmachinegun_secondary_edgedamage 10
+set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_lifetime 5
+set g_balance_okmachinegun_secondary_radius 60
+set g_balance_okmachinegun_secondary_refire 0.7
+set g_balance_okmachinegun_secondary_refire_type 0
+set g_balance_okmachinegun_secondary_shotangle 0
+set g_balance_okmachinegun_secondary_speed 6000
+set g_balance_okmachinegun_secondary_spread 0
+set g_balance_okmachinegun_switchdelay_drop 0.2
+set g_balance_okmachinegun_switchdelay_raise 0.2
+set g_balance_okmachinegun_weaponreplace ""
+set g_balance_okmachinegun_weaponstart 0
+set g_balance_okmachinegun_weaponstartoverride -1
+set g_balance_okmachinegun_weaponthrowable 1
+// }}}
+// {{{ Overkill Nex
+set g_balance_oknex_charge 1
+set g_balance_oknex_charge_animlimit 0.5
+set g_balance_oknex_charge_limit 1
+set g_balance_oknex_charge_maxspeed 800
+set g_balance_oknex_charge_mindmg 40
+set g_balance_oknex_charge_minspeed 400
+set g_balance_oknex_charge_rate 0.6
+set g_balance_oknex_charge_rot_pause 0
+set g_balance_oknex_charge_rot_rate 0
+set g_balance_oknex_charge_shot_multiplier 0
+set g_balance_oknex_charge_start 0.5
+set g_balance_oknex_charge_velocity_rate 0
+set g_balance_oknex_primary_ammo 6
+set g_balance_oknex_primary_animtime 0.4
+set g_balance_oknex_primary_damage 80
+set g_balance_oknex_primary_damagefalloff_forcehalflife 0
+set g_balance_oknex_primary_damagefalloff_halflife 0
+set g_balance_oknex_primary_damagefalloff_maxdist 0
+set g_balance_oknex_primary_damagefalloff_mindist 0
+set g_balance_oknex_primary_force 400
+set g_balance_oknex_primary_refire 1.5
+set g_balance_oknex_reload_ammo 0
+set g_balance_oknex_reload_time 2
+set g_balance_oknex_secondary 0
+set g_balance_oknex_secondary_ammo 2
+set g_balance_oknex_secondary_animtime 0
+set g_balance_oknex_secondary_chargepool 0
+set g_balance_oknex_secondary_chargepool_pause_regen 1
+set g_balance_oknex_secondary_chargepool_regen 0.15
+set g_balance_oknex_secondary_damage 0
+set g_balance_oknex_secondary_damagefalloff_forcehalflife 0
+set g_balance_oknex_secondary_damagefalloff_halflife 0
+set g_balance_oknex_secondary_damagefalloff_maxdist 0
+set g_balance_oknex_secondary_damagefalloff_mindist 0
+set g_balance_oknex_secondary_force 0
+set g_balance_oknex_secondary_refire 0
+set g_balance_oknex_secondary_refire_type 0
+set g_balance_oknex_secondary_delay 0
+set g_balance_oknex_secondary_edgedamage 10
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 60
+set g_balance_oknex_secondary_shotangle 0
+set g_balance_oknex_secondary_speed 6000
+set g_balance_oknex_secondary_spread 0
+set g_balance_oknex_switchdelay_drop 0.2
+set g_balance_oknex_switchdelay_raise 0.2
+set g_balance_oknex_weaponreplace ""
+set g_balance_oknex_weaponstart 0
+set g_balance_oknex_weaponstartoverride -1
+set g_balance_oknex_weaponthrowable 1
+// }}}
diff --git a/bal-wep-overkill.cfg b/bal-wep-overkill.cfg
deleted file mode 100644 (file)
index 9cfffed..0000000
+++ /dev/null
@@ -1,820 +0,0 @@
-// {{{ #1: Blaster
-set g_balance_blaster_primary_animtime 0.2
-set g_balance_blaster_primary_damage 20
-set g_balance_blaster_primary_delay 0
-set g_balance_blaster_primary_edgedamage 10
-set g_balance_blaster_primary_force 300
-set g_balance_blaster_primary_force_zscale 1.25
-set g_balance_blaster_primary_lifetime 5
-set g_balance_blaster_primary_radius 60
-set g_balance_blaster_primary_refire 0.7
-set g_balance_blaster_primary_shotangle 0
-set g_balance_blaster_primary_speed 6000
-set g_balance_blaster_primary_spread 0
-set g_balance_blaster_secondary 0
-set g_balance_blaster_secondary_animtime 0.2
-set g_balance_blaster_secondary_damage 25
-set g_balance_blaster_secondary_delay 0
-set g_balance_blaster_secondary_edgedamage 12.5
-set g_balance_blaster_secondary_force 300
-set g_balance_blaster_secondary_force_zscale 1.2
-set g_balance_blaster_secondary_lifetime 5
-set g_balance_blaster_secondary_radius 70
-set g_balance_blaster_secondary_refire 0.7
-set g_balance_blaster_secondary_shotangle 0
-set g_balance_blaster_secondary_speed 6000
-set g_balance_blaster_secondary_spread 0
-set g_balance_blaster_switchdelay_drop 0.2
-set g_balance_blaster_switchdelay_raise 0.2
-set g_balance_blaster_weaponreplace ""
-set g_balance_blaster_weaponstart 1
-set g_balance_blaster_weaponstartoverride -1
-set g_balance_blaster_weaponthrowable 0
-// }}}
-// {{{ #2: Shotgun
-set g_balance_shotgun_primary_ammo 3
-set g_balance_shotgun_primary_animtime 0.65
-set g_balance_shotgun_primary_bullets 10
-set g_balance_shotgun_primary_damage 17
-set g_balance_shotgun_primary_force 80
-set g_balance_shotgun_primary_refire 0.75
-set g_balance_shotgun_primary_solidpenetration 3.8
-set g_balance_shotgun_primary_spread 0.07
-set g_balance_shotgun_reload_ammo 24
-set g_balance_shotgun_reload_time 2
-set g_balance_shotgun_secondary 1
-set g_balance_shotgun_secondary_animtime 1.15
-set g_balance_shotgun_secondary_damage 70
-set g_balance_shotgun_secondary_force 200
-set g_balance_shotgun_secondary_melee_delay 0.25
-set g_balance_shotgun_secondary_melee_multihit 1
-set g_balance_shotgun_secondary_melee_no_doubleslap 1
-set g_balance_shotgun_secondary_melee_nonplayerdamage 40
-set g_balance_shotgun_secondary_melee_range 120
-set g_balance_shotgun_secondary_melee_swing_side 120
-set g_balance_shotgun_secondary_melee_swing_up 30
-set g_balance_shotgun_secondary_melee_time 0.15
-set g_balance_shotgun_secondary_melee_traces 10
-set g_balance_shotgun_secondary_refire 1.25
-set g_balance_shotgun_secondary_alt_animtime 0.2
-set g_balance_shotgun_secondary_alt_refire 1.2
-set g_balance_shotgun_switchdelay_drop 0.2
-set g_balance_shotgun_switchdelay_raise 0.2
-set g_balance_shotgun_weaponreplace ""
-set g_balance_shotgun_weaponstart 1
-set g_balance_shotgun_weaponstartoverride -1
-set g_balance_shotgun_weaponthrowable 1
-// }}}
-// {{{ #3: Machine Gun
-set g_balance_machinegun_burst 3
-set g_balance_machinegun_burst_ammo 3
-set g_balance_machinegun_burst_animtime 0.3
-set g_balance_machinegun_burst_refire 0.06
-set g_balance_machinegun_burst_refire2 0.45
-set g_balance_machinegun_burst_speed 0
-set g_balance_machinegun_first 1
-set g_balance_machinegun_first_ammo 1
-set g_balance_machinegun_first_damage 14
-set g_balance_machinegun_first_force 5
-set g_balance_machinegun_first_refire 0.125
-set g_balance_machinegun_first_spread 0.03
-set g_balance_machinegun_mode 1
-set g_balance_machinegun_reload_ammo 30
-set g_balance_machinegun_reload_time 1.5
-set g_balance_machinegun_solidpenetration 63
-set g_balance_machinegun_spread_add 0.012
-set g_balance_machinegun_spread_max 0.05
-set g_balance_machinegun_spread_min 0
-set g_balance_machinegun_sustained_ammo 1
-set g_balance_machinegun_sustained_damage 25
-set g_balance_machinegun_sustained_force 5
-set g_balance_machinegun_sustained_refire 0.1
-set g_balance_machinegun_sustained_spread 0.01
-set g_balance_machinegun_switchdelay_drop 0.2
-set g_balance_machinegun_switchdelay_raise 0.2
-set g_balance_machinegun_weaponreplace ""
-set g_balance_machinegun_weaponstart 0
-set g_balance_machinegun_weaponstartoverride -1
-set g_balance_machinegun_weaponthrowable 1
-// }}}
-// {{{ #4: Mortar
-set g_balance_mortar_bouncefactor 0.5
-set g_balance_mortar_bouncestop 0.075
-set g_balance_mortar_primary_ammo 2
-set g_balance_mortar_primary_animtime 0.3
-set g_balance_mortar_primary_damage 55
-set g_balance_mortar_primary_damageforcescale 0
-set g_balance_mortar_primary_edgedamage 25
-set g_balance_mortar_primary_force 250
-set g_balance_mortar_primary_health 15
-set g_balance_mortar_primary_lifetime 5
-set g_balance_mortar_primary_lifetime_stick 0
-set g_balance_mortar_primary_radius 120
-set g_balance_mortar_primary_refire 0.8
-set g_balance_mortar_primary_remote_minbouncecnt 0
-set g_balance_mortar_primary_speed 1900
-set g_balance_mortar_primary_speed_up 225
-set g_balance_mortar_primary_speed_z 0
-set g_balance_mortar_primary_spread 0
-set g_balance_mortar_primary_type 0
-set g_balance_mortar_reload_ammo 0
-set g_balance_mortar_reload_time 2
-set g_balance_mortar_secondary_ammo 2
-set g_balance_mortar_secondary_animtime 0.3
-set g_balance_mortar_secondary_damage 55
-set g_balance_mortar_secondary_damageforcescale 4
-set g_balance_mortar_secondary_edgedamage 30
-set g_balance_mortar_secondary_force 250
-set g_balance_mortar_secondary_health 30
-set g_balance_mortar_secondary_lifetime 5
-set g_balance_mortar_secondary_lifetime_bounce 0.5
-set g_balance_mortar_secondary_lifetime_stick 0
-set g_balance_mortar_secondary_radius 120
-set g_balance_mortar_secondary_refire 0.7
-set g_balance_mortar_secondary_remote_detonateprimary 0
-set g_balance_mortar_secondary_speed 1400
-set g_balance_mortar_secondary_speed_up 150
-set g_balance_mortar_secondary_speed_z 0
-set g_balance_mortar_secondary_spread 0
-set g_balance_mortar_secondary_type 1
-set g_balance_mortar_switchdelay_drop 0.2
-set g_balance_mortar_switchdelay_raise 0.2
-set g_balance_mortar_weaponreplace ""
-set g_balance_mortar_weaponstart 0
-set g_balance_mortar_weaponstartoverride -1
-set g_balance_mortar_weaponthrowable 1
-// }}}
-// {{{ #5: Mine Layer (MUTATOR WEAPON)
-set g_balance_minelayer_ammo 4
-set g_balance_minelayer_animtime 0.4
-set g_balance_minelayer_damage 40
-set g_balance_minelayer_damageforcescale 0
-set g_balance_minelayer_detonatedelay -1
-set g_balance_minelayer_edgedamage 20
-set g_balance_minelayer_force 250
-set g_balance_minelayer_health 15
-set g_balance_minelayer_lifetime 10
-set g_balance_minelayer_lifetime_countdown 0.5
-set g_balance_minelayer_limit 3
-set g_balance_minelayer_protection 0
-set g_balance_minelayer_proximityradius 150
-set g_balance_minelayer_radius 175
-set g_balance_minelayer_refire 1.5
-set g_balance_minelayer_reload_ammo 0
-set g_balance_minelayer_reload_time 2
-set g_balance_minelayer_remote_damage 45
-set g_balance_minelayer_remote_edgedamage 40
-set g_balance_minelayer_remote_force 300
-set g_balance_minelayer_remote_radius 200
-set g_balance_minelayer_speed 1000
-set g_balance_minelayer_switchdelay_drop 0.2
-set g_balance_minelayer_switchdelay_raise 0.2
-set g_balance_minelayer_time 0.5
-set g_balance_minelayer_weaponreplace ""
-set g_balance_minelayer_weaponstart 0
-set g_balance_minelayer_weaponstartoverride -1
-set g_balance_minelayer_weaponthrowable 1
-// }}}
-// {{{ #6: Electro
-set g_balance_electro_combo_comboradius 300
-set g_balance_electro_combo_comboradius_thruwall 200
-set g_balance_electro_combo_damage 50
-set g_balance_electro_combo_edgedamage 25
-set g_balance_electro_combo_force 120
-set g_balance_electro_combo_radius 150
-set g_balance_electro_combo_safeammocheck 1
-set g_balance_electro_combo_speed 2000
-set g_balance_electro_primary_ammo 4
-set g_balance_electro_primary_animtime 0.3
-set g_balance_electro_primary_comboradius 300
-set g_balance_electro_primary_damage 40
-set g_balance_electro_primary_edgedamage 20
-set g_balance_electro_primary_force 200
-set g_balance_electro_primary_lifetime 5
-set g_balance_electro_primary_midaircombo_explode 1
-set g_balance_electro_primary_midaircombo_interval 0.1
-set g_balance_electro_primary_midaircombo_radius 0
-set g_balance_electro_primary_radius 100
-set g_balance_electro_primary_refire 0.6
-set g_balance_electro_primary_speed 2500
-set g_balance_electro_primary_spread 0
-set g_balance_electro_reload_ammo 0
-set g_balance_electro_reload_time 2
-set g_balance_electro_secondary_ammo 2
-set g_balance_electro_secondary_animtime 0.2
-set g_balance_electro_secondary_bouncefactor 0.3
-set g_balance_electro_secondary_bouncestop 0.05
-set g_balance_electro_secondary_count 3
-set g_balance_electro_secondary_damage 30
-set g_balance_electro_secondary_damagedbycontents 1
-set g_balance_electro_secondary_damageforcescale 4
-set g_balance_electro_secondary_edgedamage 15
-set g_balance_electro_secondary_force 50
-set g_balance_electro_secondary_health 5
-set g_balance_electro_secondary_lifetime 4
-set g_balance_electro_secondary_radius 150
-set g_balance_electro_secondary_refire 0.2
-set g_balance_electro_secondary_refire2 1.6
-set g_balance_electro_secondary_speed 1000
-set g_balance_electro_secondary_speed_up 200
-set g_balance_electro_secondary_speed_z 0
-set g_balance_electro_secondary_spread 0
-set g_balance_electro_secondary_stick 0
-set g_balance_electro_secondary_touchexplode 1
-set g_balance_electro_switchdelay_drop 0.2
-set g_balance_electro_switchdelay_raise 0.2
-set g_balance_electro_weaponreplace ""
-set g_balance_electro_weaponstart 0
-set g_balance_electro_weaponstartoverride -1
-set g_balance_electro_weaponthrowable 1
-// }}}
-// {{{ #7: Crylink
-set g_balance_crylink_primary_ammo 3
-set g_balance_crylink_primary_animtime 0.3
-set g_balance_crylink_primary_bouncedamagefactor 0.5
-set g_balance_crylink_primary_bounces 1
-set g_balance_crylink_primary_damage 10
-set g_balance_crylink_primary_edgedamage 5
-set g_balance_crylink_primary_force -50
-set g_balance_crylink_primary_joindelay 0.1
-set g_balance_crylink_primary_joinexplode 1
-set g_balance_crylink_primary_joinexplode_damage 0
-set g_balance_crylink_primary_joinexplode_edgedamage 0
-set g_balance_crylink_primary_joinexplode_force 0
-set g_balance_crylink_primary_joinexplode_radius 0
-set g_balance_crylink_primary_joinspread 0.2
-set g_balance_crylink_primary_linkexplode 0
-set g_balance_crylink_primary_middle_fadetime 5
-set g_balance_crylink_primary_middle_lifetime 5
-set g_balance_crylink_primary_other_fadetime 5
-set g_balance_crylink_primary_other_lifetime 5
-set g_balance_crylink_primary_radius 80
-set g_balance_crylink_primary_refire 0.7
-set g_balance_crylink_primary_shots 6
-set g_balance_crylink_primary_speed 2000
-set g_balance_crylink_primary_spread 0.08
-set g_balance_crylink_reload_ammo 0
-set g_balance_crylink_reload_time 2
-set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
-set g_balance_crylink_secondary_animtime 0.2
-set g_balance_crylink_secondary_bouncedamagefactor 0.5
-set g_balance_crylink_secondary_bounces 0
-set g_balance_crylink_secondary_damage 8
-set g_balance_crylink_secondary_edgedamage 4
-set g_balance_crylink_secondary_force -200
-set g_balance_crylink_secondary_joindelay 0
-set g_balance_crylink_secondary_joinexplode 0
-set g_balance_crylink_secondary_joinexplode_damage 0
-set g_balance_crylink_secondary_joinexplode_edgedamage 0
-set g_balance_crylink_secondary_joinexplode_force 0
-set g_balance_crylink_secondary_joinexplode_radius 0
-set g_balance_crylink_secondary_joinspread 0
-set g_balance_crylink_secondary_linkexplode 1
-set g_balance_crylink_secondary_middle_fadetime 5
-set g_balance_crylink_secondary_middle_lifetime 5
-set g_balance_crylink_secondary_other_fadetime 5
-set g_balance_crylink_secondary_other_lifetime 5
-set g_balance_crylink_secondary_radius 100
-set g_balance_crylink_secondary_refire 0.7
-set g_balance_crylink_secondary_shots 5
-set g_balance_crylink_secondary_speed 3000
-set g_balance_crylink_secondary_spread 0.01
-set g_balance_crylink_secondary_spreadtype 1
-set g_balance_crylink_switchdelay_drop 0.2
-set g_balance_crylink_switchdelay_raise 0.2
-set g_balance_crylink_weaponreplace ""
-set g_balance_crylink_weaponstart 0
-set g_balance_crylink_weaponstartoverride -1
-set g_balance_crylink_weaponthrowable 1
-// }}}
-// {{{ #8: Vortex
-set g_balance_vortex_charge 0
-set g_balance_vortex_charge_animlimit 0.5
-set g_balance_vortex_charge_limit 1
-set g_balance_vortex_charge_maxspeed 800
-set g_balance_vortex_charge_mindmg 40
-set g_balance_vortex_charge_minspeed 400
-set g_balance_vortex_charge_rate 0.6
-set g_balance_vortex_charge_rot_pause 0
-set g_balance_vortex_charge_rot_rate 0
-set g_balance_vortex_charge_shot_multiplier 0
-set g_balance_vortex_charge_start 0.5
-set g_balance_vortex_charge_velocity_rate 0
-set g_balance_vortex_primary_ammo 10
-set g_balance_vortex_primary_animtime 0.65
-set g_balance_vortex_primary_damage 100
-set g_balance_vortex_primary_damagefalloff_forcehalflife 0
-set g_balance_vortex_primary_damagefalloff_halflife 0
-set g_balance_vortex_primary_damagefalloff_maxdist 0
-set g_balance_vortex_primary_damagefalloff_mindist 0
-set g_balance_vortex_primary_force 500
-set g_balance_vortex_primary_refire 1
-set g_balance_vortex_reload_ammo 50
-set g_balance_vortex_reload_time 2
-set g_balance_vortex_secondary 1
-set g_balance_vortex_secondary_ammo 2
-set g_balance_vortex_secondary_animtime 0
-set g_balance_vortex_secondary_chargepool 0
-set g_balance_vortex_secondary_chargepool_pause_regen 1
-set g_balance_vortex_secondary_chargepool_regen 0.15
-set g_balance_vortex_secondary_damage 0
-set g_balance_vortex_secondary_damagefalloff_forcehalflife 0
-set g_balance_vortex_secondary_damagefalloff_halflife 0
-set g_balance_vortex_secondary_damagefalloff_maxdist 0
-set g_balance_vortex_secondary_damagefalloff_mindist 0
-set g_balance_vortex_secondary_force 0
-set g_balance_vortex_secondary_refire 0
-set g_balance_vortex_switchdelay_drop 0.2
-set g_balance_vortex_switchdelay_raise 0.2
-set g_balance_vortex_weaponreplace ""
-set g_balance_vortex_weaponstart 0
-set g_balance_vortex_weaponstartoverride -1
-set g_balance_vortex_weaponthrowable 1
-// }}}
-// {{{ #9: Hagar
-set g_balance_hagar_primary_ammo 1
-set g_balance_hagar_primary_damage 25
-set g_balance_hagar_primary_damageforcescale 0
-set g_balance_hagar_primary_edgedamage 12.5
-set g_balance_hagar_primary_force 100
-set g_balance_hagar_primary_health 15
-set g_balance_hagar_primary_lifetime 5
-set g_balance_hagar_primary_radius 65
-set g_balance_hagar_primary_refire 0.16667
-set g_balance_hagar_primary_speed 2200
-set g_balance_hagar_primary_spread 0
-set g_balance_hagar_reload_ammo 0
-set g_balance_hagar_reload_time 2
-set g_balance_hagar_secondary 1
-set g_balance_hagar_secondary_ammo 1
-set g_balance_hagar_secondary_damage 35
-set g_balance_hagar_secondary_damageforcescale 0
-set g_balance_hagar_secondary_edgedamage 17.5
-set g_balance_hagar_secondary_force 75
-set g_balance_hagar_secondary_health 15
-set g_balance_hagar_secondary_lifetime_min 10
-set g_balance_hagar_secondary_lifetime_rand 0
-set g_balance_hagar_secondary_load 1
-set g_balance_hagar_secondary_load_abort 1
-set g_balance_hagar_secondary_load_animtime 0.2
-set g_balance_hagar_secondary_load_hold 4
-set g_balance_hagar_secondary_load_linkexplode 0
-set g_balance_hagar_secondary_load_max 4
-set g_balance_hagar_secondary_load_releasedeath 0
-set g_balance_hagar_secondary_load_speed 0.5
-set g_balance_hagar_secondary_load_spread 0.075
-set g_balance_hagar_secondary_load_spread_bias 0.5
-set g_balance_hagar_secondary_radius 80
-set g_balance_hagar_secondary_refire 0.5
-set g_balance_hagar_secondary_speed 2000
-set g_balance_hagar_secondary_spread 0
-set g_balance_hagar_switchdelay_drop 0.2
-set g_balance_hagar_switchdelay_raise 0.2
-set g_balance_hagar_weaponreplace ""
-set g_balance_hagar_weaponstart 0
-set g_balance_hagar_weaponstartoverride -1
-set g_balance_hagar_weaponthrowable 1
-// }}}
-// {{{ #10: Devastator
-set g_balance_devastator_ammo 4
-set g_balance_devastator_animtime 0.4
-set g_balance_devastator_damage 80
-set g_balance_devastator_damageforcescale 1
-set g_balance_devastator_detonatedelay 0.02
-set g_balance_devastator_edgedamage 40
-set g_balance_devastator_force 400
-set g_balance_devastator_guidedelay 0.2
-set g_balance_devastator_guidegoal 512
-set g_balance_devastator_guiderate 90
-set g_balance_devastator_guideratedelay 0.01
-set g_balance_devastator_guidestop 0
-set g_balance_devastator_health 30
-set g_balance_devastator_lifetime 10
-set g_balance_devastator_radius 110
-set g_balance_devastator_refire 1.1
-set g_balance_devastator_reload_ammo 0
-set g_balance_devastator_reload_time 2
-set g_balance_devastator_remote_damage 70
-set g_balance_devastator_remote_edgedamage 35
-set g_balance_devastator_remote_force 300
-set g_balance_devastator_remote_jump_damage 70
-set g_balance_devastator_remote_jump_force 450
-set g_balance_devastator_remote_jump_radius 0
-set g_balance_devastator_remote_jump_velocity_z_add 0
-set g_balance_devastator_remote_jump_velocity_z_max 1500
-set g_balance_devastator_remote_jump_velocity_z_min 400
-set g_balance_devastator_remote_radius 110
-set g_balance_devastator_speed 1300
-set g_balance_devastator_speedaccel 1300
-set g_balance_devastator_speedstart 1000
-set g_balance_devastator_switchdelay_drop 0.2
-set g_balance_devastator_switchdelay_raise 0.2
-set g_balance_devastator_weaponreplace ""
-set g_balance_devastator_weaponstart 0
-set g_balance_devastator_weaponstartoverride -1
-set g_balance_devastator_weaponthrowable 1
-// }}}
-// {{{ #11: Port-O-Launch
-set g_balance_porto_primary_animtime 0.3
-set g_balance_porto_primary_lifetime 5
-set g_balance_porto_primary_refire 1.5
-set g_balance_porto_primary_speed 1000
-set g_balance_porto_secondary 1
-set g_balance_porto_secondary_animtime 0.3
-set g_balance_porto_secondary_lifetime 5
-set g_balance_porto_secondary_refire 1.5
-set g_balance_porto_secondary_speed 1000
-set g_balance_porto_switchdelay_drop 0.2
-set g_balance_porto_switchdelay_raise 0.2
-set g_balance_porto_weaponreplace ""
-set g_balance_porto_weaponstart 0
-set g_balance_porto_weaponstartoverride -1
-set g_balance_porto_weaponthrowable 1
-// }}}
-// {{{ #12: Vaporizer
-set g_balance_vaporizer_primary_ammo 10
-set g_balance_vaporizer_primary_animtime 0.3
-set g_balance_vaporizer_primary_damage 150
-set g_balance_vaporizer_primary_refire 1
-set g_balance_vaporizer_reload_ammo 0
-set g_balance_vaporizer_reload_time 0
-set g_balance_vaporizer_secondary_ammo 0
-set g_balance_vaporizer_secondary_animtime 0.2
-set g_balance_vaporizer_secondary_damage 25
-set g_balance_vaporizer_secondary_delay 0
-set g_balance_vaporizer_secondary_edgedamage 12.5
-set g_balance_vaporizer_secondary_force 300
-set g_balance_vaporizer_secondary_lifetime 5
-set g_balance_vaporizer_secondary_radius 70
-set g_balance_vaporizer_secondary_refire 0.7
-set g_balance_vaporizer_secondary_shotangle 0
-set g_balance_vaporizer_secondary_speed 6000
-set g_balance_vaporizer_secondary_spread 0
-set g_balance_vaporizer_switchdelay_drop 0.2
-set g_balance_vaporizer_switchdelay_raise 0.2
-set g_balance_vaporizer_weaponreplace ""
-set g_balance_vaporizer_weaponstart 0
-set g_balance_vaporizer_weaponstartoverride -1
-set g_balance_vaporizer_weaponthrowable 1
-// }}}
-// {{{ #13: Grappling Hook
-set g_balance_hook_primary_ammo 5
-set g_balance_hook_primary_animtime 0.3
-set g_balance_hook_primary_hooked_ammo 5
-set g_balance_hook_primary_hooked_time_free 2
-set g_balance_hook_primary_hooked_time_max 0
-set g_balance_hook_primary_refire 0.2
-set g_balance_hook_secondary_animtime 0.3
-set g_balance_hook_secondary_damage 25
-set g_balance_hook_secondary_damageforcescale 0
-set g_balance_hook_secondary_duration 1.5
-set g_balance_hook_secondary_edgedamage 5
-set g_balance_hook_secondary_force -2000
-set g_balance_hook_secondary_gravity 5
-set g_balance_hook_secondary_health 15
-set g_balance_hook_secondary_lifetime 5
-set g_balance_hook_secondary_power 3
-set g_balance_hook_secondary_radius 500
-set g_balance_hook_secondary_refire 3
-set g_balance_hook_secondary_speed 0
-set g_balance_hook_switchdelay_drop 0.2
-set g_balance_hook_switchdelay_raise 0.2
-set g_balance_hook_weaponreplace ""
-set g_balance_hook_weaponstart 0
-set g_balance_hook_weaponstartoverride -1
-set g_balance_hook_weaponthrowable 1
-// }}}
-// {{{ #14: Heavy Laser Assault Cannon (MUTATOR WEAPON)
-set g_balance_hlac_primary_ammo 1
-set g_balance_hlac_primary_animtime 0.4
-set g_balance_hlac_primary_damage 18
-set g_balance_hlac_primary_edgedamage 9
-set g_balance_hlac_primary_force 90
-set g_balance_hlac_primary_lifetime 5
-set g_balance_hlac_primary_radius 70
-set g_balance_hlac_primary_refire 0.15
-set g_balance_hlac_primary_speed 9000
-set g_balance_hlac_primary_spread_add 0.0045
-set g_balance_hlac_primary_spread_crouchmod 0.25
-set g_balance_hlac_primary_spread_max 0.25
-set g_balance_hlac_primary_spread_min 0.01
-set g_balance_hlac_reload_ammo 0
-set g_balance_hlac_reload_time 2
-set g_balance_hlac_secondary 1
-set g_balance_hlac_secondary_ammo 10
-set g_balance_hlac_secondary_animtime 0.3
-set g_balance_hlac_secondary_damage 15
-set g_balance_hlac_secondary_edgedamage 7.5
-set g_balance_hlac_secondary_force 90
-set g_balance_hlac_secondary_lifetime 5
-set g_balance_hlac_secondary_radius 70
-set g_balance_hlac_secondary_refire 1
-set g_balance_hlac_secondary_shots 6
-set g_balance_hlac_secondary_speed 9000
-set g_balance_hlac_secondary_spread 0.15
-set g_balance_hlac_secondary_spread_crouchmod 0.5
-set g_balance_hlac_switchdelay_drop 0.2
-set g_balance_hlac_switchdelay_raise 0.2
-set g_balance_hlac_weaponreplace ""
-set g_balance_hlac_weaponstart 0
-set g_balance_hlac_weaponstartoverride -1
-set g_balance_hlac_weaponthrowable 1
-// }}}
-// {{{ #15: @!#%'n Tuba
-set g_balance_tuba_animtime 0.05
-set g_balance_tuba_attenuation 0.5
-set g_balance_tuba_damage 5
-set g_balance_tuba_edgedamage 0
-set g_balance_tuba_fadetime 0.25
-set g_balance_tuba_force 40
-set g_balance_tuba_pitchstep 6
-set g_balance_tuba_radius 200
-set g_balance_tuba_refire 0.05
-set g_balance_tuba_switchdelay_drop 0.2
-set g_balance_tuba_switchdelay_raise 0.2
-set g_balance_tuba_volume 1
-set g_balance_tuba_weaponreplace ""
-set g_balance_tuba_weaponstart 0
-set g_balance_tuba_weaponstartoverride -1
-set g_balance_tuba_weaponthrowable 1
-// }}}
-// {{{ #16: Rifle (MUTATOR WEAPON)
-set g_balance_rifle_bursttime 0
-set g_balance_rifle_primary_ammo 10
-set g_balance_rifle_primary_animtime 0.4
-set g_balance_rifle_primary_bullethail 0
-set g_balance_rifle_primary_burstcost 0
-set g_balance_rifle_primary_damage 80
-set g_balance_rifle_primary_force 100
-set g_balance_rifle_primary_refire 1.2
-set g_balance_rifle_primary_shots 1
-set g_balance_rifle_primary_solidpenetration 62.2
-set g_balance_rifle_primary_spread 0
-set g_balance_rifle_primary_tracer 1
-set g_balance_rifle_reload_ammo 80
-set g_balance_rifle_reload_time 2
-set g_balance_rifle_secondary 1
-set g_balance_rifle_secondary_ammo 10
-set g_balance_rifle_secondary_animtime 0.3
-set g_balance_rifle_secondary_bullethail 0
-set g_balance_rifle_secondary_burstcost 0
-set g_balance_rifle_secondary_damage 20
-set g_balance_rifle_secondary_force 50
-set g_balance_rifle_secondary_refire 0.9
-set g_balance_rifle_secondary_reload 0
-set g_balance_rifle_secondary_shots 4
-set g_balance_rifle_secondary_solidpenetration 15.5
-set g_balance_rifle_secondary_spread 0.04
-set g_balance_rifle_secondary_tracer 0
-set g_balance_rifle_switchdelay_drop 0.2
-set g_balance_rifle_switchdelay_raise 0.2
-set g_balance_rifle_weaponreplace ""
-set g_balance_rifle_weaponstart 0
-set g_balance_rifle_weaponstartoverride -1
-set g_balance_rifle_weaponthrowable 1
-// }}}
-// {{{ #17: Fireball
-set g_balance_fireball_primary_animtime 0.4
-set g_balance_fireball_primary_bfgdamage 100
-set g_balance_fireball_primary_bfgforce 0
-set g_balance_fireball_primary_bfgradius 1000
-set g_balance_fireball_primary_damage 200
-set g_balance_fireball_primary_damageforcescale 0
-set g_balance_fireball_primary_edgedamage 50
-set g_balance_fireball_primary_force 600
-set g_balance_fireball_primary_health 0
-set g_balance_fireball_primary_laserburntime 0.5
-set g_balance_fireball_primary_laserdamage 80
-set g_balance_fireball_primary_laseredgedamage 20
-set g_balance_fireball_primary_laserradius 256
-set g_balance_fireball_primary_lifetime 15
-set g_balance_fireball_primary_radius 200
-set g_balance_fireball_primary_refire 2
-set g_balance_fireball_primary_refire2 0
-set g_balance_fireball_primary_speed 1200
-set g_balance_fireball_primary_spread 0
-set g_balance_fireball_secondary_animtime 0.3
-set g_balance_fireball_secondary_damage 40
-set g_balance_fireball_secondary_damageforcescale 4
-set g_balance_fireball_secondary_damagetime 5
-set g_balance_fireball_secondary_laserburntime 0.5
-set g_balance_fireball_secondary_laserdamage 50
-set g_balance_fireball_secondary_laseredgedamage 20
-set g_balance_fireball_secondary_laserradius 110
-set g_balance_fireball_secondary_lifetime 7
-set g_balance_fireball_secondary_refire 1.5
-set g_balance_fireball_secondary_speed 900
-set g_balance_fireball_secondary_speed_up 100
-set g_balance_fireball_secondary_speed_z 0
-set g_balance_fireball_secondary_spread 0
-set g_balance_fireball_switchdelay_drop 0.2
-set g_balance_fireball_switchdelay_raise 0.2
-set g_balance_fireball_weaponreplace ""
-set g_balance_fireball_weaponstart 0
-set g_balance_fireball_weaponstartoverride -1
-set g_balance_fireball_weaponthrowable 0
-// }}}
-// {{{ #18: T.A.G. Seeker (MUTATOR WEAPON)
-set g_balance_seeker_flac_ammo 1
-set g_balance_seeker_flac_animtime 0.1
-set g_balance_seeker_flac_damage 15
-set g_balance_seeker_flac_edgedamage 10
-set g_balance_seeker_flac_force 50
-set g_balance_seeker_flac_lifetime 0.1
-set g_balance_seeker_flac_lifetime_rand 0.05
-set g_balance_seeker_flac_radius 100
-set g_balance_seeker_flac_refire 0.1
-set g_balance_seeker_flac_speed 3000
-set g_balance_seeker_flac_speed_up 1000
-set g_balance_seeker_flac_speed_z 0
-set g_balance_seeker_flac_spread 0.4
-set g_balance_seeker_missile_accel 1400
-set g_balance_seeker_missile_ammo 2
-set g_balance_seeker_missile_animtime 0.2
-set g_balance_seeker_missile_count 3
-set g_balance_seeker_missile_damage 30
-set g_balance_seeker_missile_damageforcescale 4
-set g_balance_seeker_missile_decel 1400
-set g_balance_seeker_missile_delay 0.25
-set g_balance_seeker_missile_edgedamage 10
-set g_balance_seeker_missile_force 150
-set g_balance_seeker_missile_health 5
-set g_balance_seeker_missile_lifetime 15
-set g_balance_seeker_missile_proxy 0
-set g_balance_seeker_missile_proxy_delay 0.2
-set g_balance_seeker_missile_proxy_maxrange 45
-set g_balance_seeker_missile_radius 80
-set g_balance_seeker_missile_refire 0.5
-set g_balance_seeker_missile_smart 1
-set g_balance_seeker_missile_smart_mindist 800
-set g_balance_seeker_missile_smart_trace_max 2500
-set g_balance_seeker_missile_smart_trace_min 1000
-set g_balance_seeker_missile_speed 700
-set g_balance_seeker_missile_speed_max 1300
-set g_balance_seeker_missile_speed_up 300
-set g_balance_seeker_missile_speed_z 0
-set g_balance_seeker_missile_spread 0
-set g_balance_seeker_missile_turnrate 0.65
-set g_balance_seeker_reload_ammo 0
-set g_balance_seeker_reload_time 2
-set g_balance_seeker_switchdelay_drop 0.2
-set g_balance_seeker_switchdelay_raise 0.2
-set g_balance_seeker_tag_ammo 1
-set g_balance_seeker_tag_animtime 0.2
-set g_balance_seeker_tag_damageforcescale 4
-set g_balance_seeker_tag_health 5
-set g_balance_seeker_tag_lifetime 15
-set g_balance_seeker_tag_refire 0.75
-set g_balance_seeker_tag_speed 5000
-set g_balance_seeker_tag_spread 0
-set g_balance_seeker_tag_tracker_lifetime 10
-set g_balance_seeker_type 0
-set g_balance_seeker_weaponreplace ""
-set g_balance_seeker_weaponstart 0
-set g_balance_seeker_weaponstartoverride -1
-set g_balance_seeker_weaponthrowable 1
-// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
-set g_balance_shockwave_blast_animtime 0.3
-set g_balance_shockwave_blast_damage 40
-set g_balance_shockwave_blast_distance 1000
-set g_balance_shockwave_blast_edgedamage 0
-set g_balance_shockwave_blast_force 15
-set g_balance_shockwave_blast_force_forwardbias 50
-set g_balance_shockwave_blast_force_zscale 1
-set g_balance_shockwave_blast_jump_damage 20
-set g_balance_shockwave_blast_jump_edgedamage 0
-set g_balance_shockwave_blast_jump_force 100
-set g_balance_shockwave_blast_jump_force_velocitybias 1
-set g_balance_shockwave_blast_jump_force_zscale 1
-set g_balance_shockwave_blast_jump_multiplier_accuracy 0.5
-set g_balance_shockwave_blast_jump_multiplier_distance 0.5
-set g_balance_shockwave_blast_jump_multiplier_min 0
-set g_balance_shockwave_blast_jump_radius 150
-set g_balance_shockwave_blast_multiplier_accuracy 0.45
-set g_balance_shockwave_blast_multiplier_distance 0.2
-set g_balance_shockwave_blast_multiplier_min 0
-set g_balance_shockwave_blast_refire 0.75
-set g_balance_shockwave_blast_splash_damage 15
-set g_balance_shockwave_blast_splash_edgedamage 0
-set g_balance_shockwave_blast_splash_force 100
-set g_balance_shockwave_blast_splash_force_forwardbias 50
-set g_balance_shockwave_blast_splash_multiplier_accuracy 0.5
-set g_balance_shockwave_blast_splash_multiplier_distance 0.5
-set g_balance_shockwave_blast_splash_multiplier_min 0
-set g_balance_shockwave_blast_splash_radius 70
-set g_balance_shockwave_blast_spread_max 120
-set g_balance_shockwave_blast_spread_min 25
-set g_balance_shockwave_melee_animtime 1.3
-set g_balance_shockwave_melee_damage 80
-set g_balance_shockwave_melee_delay 0.25
-set g_balance_shockwave_melee_force 200
-set g_balance_shockwave_melee_multihit 1
-set g_balance_shockwave_melee_no_doubleslap 1
-set g_balance_shockwave_melee_nonplayerdamage 40
-set g_balance_shockwave_melee_range 120
-set g_balance_shockwave_melee_refire 1.25
-set g_balance_shockwave_melee_swing_side 120
-set g_balance_shockwave_melee_swing_up 30
-set g_balance_shockwave_melee_time 0.15
-set g_balance_shockwave_melee_traces 10
-set g_balance_shockwave_switchdelay_drop 0.2
-set g_balance_shockwave_switchdelay_raise 0.2
-set g_balance_shockwave_weaponreplace ""
-set g_balance_shockwave_weaponstart 0
-set g_balance_shockwave_weaponstartoverride -1
-set g_balance_shockwave_weaponthrowable 0
-// }}}
-// {{{ #20: Arc
-set g_balance_arc_beam_ammo 6
-set g_balance_arc_beam_animtime 0.1
-set g_balance_arc_beam_botaimlifetime 0
-set g_balance_arc_beam_botaimspeed 0
-set g_balance_arc_beam_damage 100
-set g_balance_arc_beam_degreespersegment 1
-set g_balance_arc_beam_distancepersegment 0
-set g_balance_arc_beam_falloff_halflifedist 0
-set g_balance_arc_beam_falloff_maxdist 0
-set g_balance_arc_beam_falloff_mindist 0
-set g_balance_arc_beam_force 600
-set g_balance_arc_beam_healing_amax 0
-set g_balance_arc_beam_healing_aps 50
-set g_balance_arc_beam_healing_hmax 150
-set g_balance_arc_beam_healing_hps 50
-set g_balance_arc_cooldown 2.5
-set g_balance_arc_cooldown_release 0
-set g_balance_arc_overheat_max 5
-set g_balance_arc_overheat_min 3
-set g_balance_arc_beam_heat 0
-set g_balance_arc_burst_heat 5
-set g_balance_arc_beam_maxangle 10
-set g_balance_arc_beam_nonplayerdamage 80
-set g_balance_arc_beam_range 1000
-set g_balance_arc_beam_refire 0.25
-set g_balance_arc_beam_returnspeed 8
-set g_balance_arc_beam_tightness 0.5
-set g_balance_arc_bolt 0
-set g_balance_arc_bolt_ammo 1
-set g_balance_arc_bolt_damage 25
-set g_balance_arc_bolt_damageforcescale 0
-set g_balance_arc_bolt_edgedamage 12.5
-set g_balance_arc_bolt_force 120
-set g_balance_arc_bolt_health 15
-set g_balance_arc_bolt_lifetime 5
-set g_balance_arc_bolt_radius 65
-set g_balance_arc_bolt_refire 0.16667
-set g_balance_arc_bolt_speed 2300
-set g_balance_arc_bolt_spread 0
-set g_balance_arc_burst_ammo 15
-set g_balance_arc_burst_damage 250
-set g_balance_arc_burst_healing_aps 100
-set g_balance_arc_burst_healing_hps 100
-set g_balance_arc_switchdelay_drop 0.2
-set g_balance_arc_switchdelay_raise 0.2
-set g_balance_arc_weaponreplace ""
-set g_balance_arc_weaponstart 0
-set g_balance_arc_weaponstartoverride -1
-set g_balance_arc_weaponthrowable 1
-// }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
-// }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
-// }}}
index b3ec457a8af5ae1f8b4a62c3656d146d3af33fda..380d93ed47acc76f5aae18c560b77962a49ad531 100644 (file)
@@ -369,6 +369,7 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 6
 set g_balance_vortex_primary_animtime 0.6
+set g_balance_vortex_primary_armorpierce 0
 set g_balance_vortex_primary_damage 80
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
@@ -381,6 +382,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -502,6 +504,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -775,44 +778,70 @@ set g_balance_shotgun_weaponstart 0
 set g_balance_shotgun_weaponstartoverride -1
 set g_balance_shotgun_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
 // }}}
index cc8936c3381c9a3a0f1c1eb055071a558525227c..fcf68678d197f048f1b4bad1a270890eea1d7cd4 100644 (file)
@@ -303,6 +303,7 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 6
 set g_balance_vortex_primary_animtime 0.4
+set g_balance_vortex_primary_armorpierce 0
 set g_balance_vortex_primary_damage 80
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
@@ -315,6 +316,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -436,6 +438,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -777,44 +780,70 @@ set g_balance_arc_weaponstart 0
 set g_balance_arc_weaponstartoverride -1
 set g_balance_arc_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
 // }}}
index ac5be34f3783b822759d7b26922629c1adedd52b..e55e860773424fdad08857e6b3c121c3b686c407 100644 (file)
@@ -303,6 +303,7 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 6
 set g_balance_vortex_primary_animtime 0.4
+set g_balance_vortex_primary_armorpierce 0
 set g_balance_vortex_primary_damage 80
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
@@ -315,6 +316,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -436,6 +438,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -750,11 +753,11 @@ set g_balance_arc_beam_heat 0
 set g_balance_arc_burst_heat 5
 set g_balance_arc_beam_maxangle 10
 set g_balance_arc_beam_nonplayerdamage 80
-set g_balance_arc_beam_range 1000
+set g_balance_arc_beam_range 1500
 set g_balance_arc_beam_refire 0.25
 set g_balance_arc_beam_returnspeed 8
-set g_balance_arc_beam_tightness 0.5
-set g_balance_arc_bolt 0
+set g_balance_arc_beam_tightness 0.6
+set g_balance_arc_bolt 1
 set g_balance_arc_bolt_ammo 1
 set g_balance_arc_bolt_damage 25
 set g_balance_arc_bolt_damageforcescale 0
@@ -777,44 +780,183 @@ set g_balance_arc_weaponstart 0
 set g_balance_arc_weaponstartoverride -1
 set g_balance_arc_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
+// }}}
+// {{{ Overkill Shotgun
+set g_balance_okshotgun_primary_ammo 3
+set g_balance_okshotgun_primary_animtime 0.65
+set g_balance_okshotgun_primary_bot_range 512
+set g_balance_okshotgun_primary_bullets 10
+set g_balance_okshotgun_primary_damage 17
+set g_balance_okshotgun_primary_force 80
+set g_balance_okshotgun_primary_refire 0.75
+set g_balance_okshotgun_primary_solidpenetration 3.8
+set g_balance_okshotgun_primary_spread 0.07
+set g_balance_okshotgun_reload_ammo 24
+set g_balance_okshotgun_reload_time 2
+set g_balance_okshotgun_secondary_animtime 0.2
+set g_balance_okshotgun_secondary_damage 25
+set g_balance_okshotgun_secondary_delay 0
+set g_balance_okshotgun_secondary_edgedamage 12.5
+set g_balance_okshotgun_secondary_force 300
+set g_balance_okshotgun_secondary_lifetime 5
+set g_balance_okshotgun_secondary_radius 70
+set g_balance_okshotgun_secondary_refire 0.7
+set g_balance_okshotgun_secondary_refire_type 1
+set g_balance_okshotgun_secondary_shotangle 0
+set g_balance_okshotgun_secondary_speed 6000
+set g_balance_okshotgun_secondary_spread 0
+set g_balance_okshotgun_switchdelay_drop 0.2
+set g_balance_okshotgun_switchdelay_raise 0.2
+set g_balance_okshotgun_weaponreplace ""
+set g_balance_okshotgun_weaponstart 0
+set g_balance_okshotgun_weaponstartoverride -1
+set g_balance_okshotgun_weaponthrowable 1
+// }}}
+// {{{ Overkill Machine Gun
+set g_balance_okmachinegun_primary_ammo 1
+set g_balance_okmachinegun_primary_damage 25
+set g_balance_okmachinegun_primary_force 5
+set g_balance_okmachinegun_primary_refire 0.1
+set g_balance_okmachinegun_primary_solidpenetration 13.1
+set g_balance_okmachinegun_primary_spread_add 0.012
+set g_balance_okmachinegun_primary_spread_max 0.05
+set g_balance_okmachinegun_primary_spread_min 0
+set g_balance_okmachinegun_reload_ammo 30
+set g_balance_okmachinegun_reload_time 1.5
+set g_balance_okmachinegun_secondary_animtime 0.2
+set g_balance_okmachinegun_secondary_damage 25
+set g_balance_okmachinegun_secondary_delay 0
+set g_balance_okmachinegun_secondary_edgedamage 12.5
+set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_lifetime 5
+set g_balance_okmachinegun_secondary_radius 70
+set g_balance_okmachinegun_secondary_refire 0.7
+set g_balance_okmachinegun_secondary_refire_type 1
+set g_balance_okmachinegun_secondary_shotangle 0
+set g_balance_okmachinegun_secondary_speed 6000
+set g_balance_okmachinegun_secondary_spread 0
+set g_balance_okmachinegun_switchdelay_drop 0.2
+set g_balance_okmachinegun_switchdelay_raise 0.2
+set g_balance_okmachinegun_weaponreplace ""
+set g_balance_okmachinegun_weaponstart 0
+set g_balance_okmachinegun_weaponstartoverride -1
+set g_balance_okmachinegun_weaponthrowable 1
+// }}}
+// {{{ Overkill Nex
+set g_balance_oknex_charge 0
+set g_balance_oknex_charge_animlimit 0.5
+set g_balance_oknex_charge_limit 1
+set g_balance_oknex_charge_maxspeed 800
+set g_balance_oknex_charge_mindmg 40
+set g_balance_oknex_charge_minspeed 400
+set g_balance_oknex_charge_rate 0.6
+set g_balance_oknex_charge_rot_pause 0
+set g_balance_oknex_charge_rot_rate 0
+set g_balance_oknex_charge_shot_multiplier 0
+set g_balance_oknex_charge_start 0.5
+set g_balance_oknex_charge_velocity_rate 0
+set g_balance_oknex_primary_ammo 10
+set g_balance_oknex_primary_animtime 0.65
+set g_balance_oknex_primary_damage 100
+set g_balance_oknex_primary_damagefalloff_forcehalflife 0
+set g_balance_oknex_primary_damagefalloff_halflife 0
+set g_balance_oknex_primary_damagefalloff_maxdist 0
+set g_balance_oknex_primary_damagefalloff_mindist 0
+set g_balance_oknex_primary_force 500
+set g_balance_oknex_primary_refire 1
+set g_balance_oknex_reload_ammo 50
+set g_balance_oknex_reload_time 2
+set g_balance_oknex_secondary 2
+set g_balance_oknex_secondary_ammo 0
+set g_balance_oknex_secondary_animtime 0.2
+set g_balance_oknex_secondary_chargepool 0
+set g_balance_oknex_secondary_chargepool_pause_regen 1
+set g_balance_oknex_secondary_chargepool_regen 0.15
+set g_balance_oknex_secondary_damage 25
+set g_balance_oknex_secondary_damagefalloff_forcehalflife 0
+set g_balance_oknex_secondary_damagefalloff_halflife 0
+set g_balance_oknex_secondary_damagefalloff_maxdist 0
+set g_balance_oknex_secondary_damagefalloff_mindist 0
+set g_balance_oknex_secondary_force 300
+set g_balance_oknex_secondary_refire 0.7
+set g_balance_oknex_secondary_refire_type 1
+set g_balance_oknex_secondary_delay 0
+set g_balance_oknex_secondary_edgedamage 12.5
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 70
+set g_balance_oknex_secondary_shotangle 0
+set g_balance_oknex_secondary_speed 6000
+set g_balance_oknex_secondary_spread 0
+set g_balance_oknex_switchdelay_drop 0.2
+set g_balance_oknex_switchdelay_raise 0.2
+set g_balance_oknex_weaponreplace ""
+set g_balance_oknex_weaponstart 0
+set g_balance_oknex_weaponstartoverride -1
+set g_balance_oknex_weaponthrowable 1
 // }}}
index ac5be34f3783b822759d7b26922629c1adedd52b..b16e787f5e5a95c029e1c679405b6b7d37d00a08 100644 (file)
@@ -303,6 +303,7 @@ set g_balance_vortex_charge_start 0.5
 set g_balance_vortex_charge_velocity_rate 0
 set g_balance_vortex_primary_ammo 6
 set g_balance_vortex_primary_animtime 0.4
+set g_balance_vortex_primary_armorpierce 0
 set g_balance_vortex_primary_damage 80
 set g_balance_vortex_primary_damagefalloff_forcehalflife 0
 set g_balance_vortex_primary_damagefalloff_halflife 0
@@ -315,6 +316,7 @@ set g_balance_vortex_reload_time 2
 set g_balance_vortex_secondary 0
 set g_balance_vortex_secondary_ammo 2
 set g_balance_vortex_secondary_animtime 0
+set g_balance_vortex_secondary_armorpierce 0
 set g_balance_vortex_secondary_chargepool 0
 set g_balance_vortex_secondary_chargepool_pause_regen 1
 set g_balance_vortex_secondary_chargepool_regen 0.15
@@ -436,6 +438,7 @@ set g_balance_porto_weaponthrowable 1
 set g_balance_vaporizer_primary_ammo 10
 set g_balance_vaporizer_primary_animtime 0.3
 set g_balance_vaporizer_primary_damage 150
+set g_balance_vaporizer_primary_force 800
 set g_balance_vaporizer_primary_refire 1
 set g_balance_vaporizer_reload_ammo 0
 set g_balance_vaporizer_reload_time 0
@@ -777,44 +780,70 @@ set g_balance_arc_weaponstart 0
 set g_balance_arc_weaponstartoverride -1
 set g_balance_arc_weaponthrowable 1
 // }}}
-// {{{ #21: Heavy Machine Gun
-set g_balance_hmg_ammo 1
-set g_balance_hmg_damage 30
-set g_balance_hmg_force 10
-set g_balance_hmg_refire 0.05
-set g_balance_hmg_reload_ammo 120
-set g_balance_hmg_reload_time 1
-set g_balance_hmg_solidpenetration 32
-set g_balance_hmg_spread_add 0.005
-set g_balance_hmg_spread_max 0.06
-set g_balance_hmg_spread_min 0.01
-set g_balance_hmg_switchdelay_drop 0.2
-set g_balance_hmg_switchdelay_raise 0.2
-set g_balance_hmg_weaponreplace ""
-set g_balance_hmg_weaponstart 0
-set g_balance_hmg_weaponstartoverride 0
-set g_balance_hmg_weaponthrowable 0
+// {{{ #21: Overkill Heavy Machine Gun
+set g_balance_okhmg_primary_ammo 1
+set g_balance_okhmg_primary_damage 30
+set g_balance_okhmg_primary_force 10
+set g_balance_okhmg_primary_refire 0.05
+set g_balance_okhmg_primary_solidpenetration 32
+set g_balance_okhmg_primary_spread_add 0.005
+set g_balance_okhmg_primary_spread_max 0.06
+set g_balance_okhmg_primary_spread_min 0.01
+set g_balance_okhmg_reload_ammo 120
+set g_balance_okhmg_reload_time 1
+set g_balance_okhmg_secondary_ammo 0
+set g_balance_okhmg_secondary_animtime 0.2
+set g_balance_okhmg_secondary_damage 25
+set g_balance_okhmg_secondary_delay 0
+set g_balance_okhmg_secondary_edgedamage 12.5
+set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_lifetime 5
+set g_balance_okhmg_secondary_radius 70
+set g_balance_okhmg_secondary_refire 0.7
+set g_balance_okhmg_secondary_refire_type 1
+set g_balance_okhmg_secondary_shotangle 0
+set g_balance_okhmg_secondary_speed 6000
+set g_balance_okhmg_secondary_spread 0
+set g_balance_okhmg_switchdelay_drop 0.2
+set g_balance_okhmg_switchdelay_raise 0.2
+set g_balance_okhmg_weaponreplace ""
+set g_balance_okhmg_weaponstart 0
+set g_balance_okhmg_weaponstartoverride 0
+set g_balance_okhmg_weaponthrowable 0
 // }}}
-// {{{ #22: Rocket Propelled Chainsaw
-set g_balance_rpc_ammo 10
-set g_balance_rpc_animtime 1
-set g_balance_rpc_damage 150
-set g_balance_rpc_damage2 500
-set g_balance_rpc_damageforcescale 2
-set g_balance_rpc_edgedamage 50
-set g_balance_rpc_force 400
-set g_balance_rpc_health 25
-set g_balance_rpc_lifetime 30
-set g_balance_rpc_radius 300
-set g_balance_rpc_refire 1
-set g_balance_rpc_reload_ammo 10
-set g_balance_rpc_reload_time 1
-set g_balance_rpc_speed 2500
-set g_balance_rpc_speedaccel 5000
-set g_balance_rpc_switchdelay_drop 0.2
-set g_balance_rpc_switchdelay_raise 0.2
-set g_balance_rpc_weaponreplace ""
-set g_balance_rpc_weaponstart 0
-set g_balance_rpc_weaponstartoverride 0
-set g_balance_rpc_weaponthrowable 0
+// {{{ #22: Overkill Rocket Propelled Chainsaw
+set g_balance_okrpc_primary_ammo 10
+set g_balance_okrpc_primary_animtime 1
+set g_balance_okrpc_primary_damage 150
+set g_balance_okrpc_primary_damage2 500
+set g_balance_okrpc_primary_damageforcescale 2
+set g_balance_okrpc_primary_edgedamage 50
+set g_balance_okrpc_primary_force 400
+set g_balance_okrpc_primary_health 25
+set g_balance_okrpc_primary_lifetime 30
+set g_balance_okrpc_primary_radius 300
+set g_balance_okrpc_primary_refire 1
+set g_balance_okrpc_primary_speed 2500
+set g_balance_okrpc_primary_speedaccel 5000
+set g_balance_okrpc_reload_ammo 10
+set g_balance_okrpc_reload_time 1
+set g_balance_okrpc_secondary_ammo 0
+set g_balance_okrpc_secondary_animtime 0.2
+set g_balance_okrpc_secondary_damage 25
+set g_balance_okrpc_secondary_delay 0
+set g_balance_okrpc_secondary_edgedamage 12.5
+set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_lifetime 5
+set g_balance_okrpc_secondary_radius 70
+set g_balance_okrpc_secondary_refire 0.7
+set g_balance_okrpc_secondary_refire_type 1
+set g_balance_okrpc_secondary_shotangle 0
+set g_balance_okrpc_secondary_speed 6000
+set g_balance_okrpc_secondary_spread 0
+set g_balance_okrpc_switchdelay_drop 0.2
+set g_balance_okrpc_switchdelay_raise 0.2
+set g_balance_okrpc_weaponreplace ""
+set g_balance_okrpc_weaponstart 0
+set g_balance_okrpc_weaponstartoverride 0
+set g_balance_okrpc_weaponthrowable 0
 // }}}
index 4dda8bdc8842318701f1dcc39e95db6a87f8f7c3..1974ad6c811d130e2ad129424d24e5824b5135c9 100644 (file)
@@ -101,7 +101,7 @@ set g_pickup_respawntime_powerup 120
 set g_pickup_respawntime_weapon 10
 set g_pickup_respawntime_superweapon 120
 set g_pickup_respawntime_ammo 10
-set g_pickup_respawntime_initial_random 2
+set g_pickup_respawntime_initial_random 1
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -132,7 +132,7 @@ set g_balance_pause_armor_rot_spawn 5
 set g_balance_armor_regenstable 100
 set g_balance_armor_rotstable 100
 set g_balance_armor_limit 200
-set g_balance_armor_blockpercent 0.7
+set g_balance_armor_blockpercent 0.55
 set g_balance_fuel_regen 0.1 "fuel regeneration (only applies if the player owns IT_FUEL_REGEN)"
 set g_balance_fuel_regenlinear 0
 set g_balance_pause_fuel_regen 2 // other than this, fuel uses the health regen counter
@@ -199,7 +199,7 @@ set g_maxpushtime 8.0 "timeout for kill credit when your damage knocks someone i
 
 // {{{ powerups
 set g_balance_powerup_invincible_takedamage 0.33 // only 1/3rd damage is taken
-set g_balance_powerup_invincible_takeforce 1
+set g_balance_powerup_invincible_takeforce 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
index bf2ecc623cccf3ebd3fba2cc0afecb2ec7432e40..18d862d747808a987ea24b1946a8eb5b39c11096 100644 (file)
@@ -239,5 +239,3 @@ set g_balance_grapplehook_pull_frozen 0
 set g_balance_portal_health 200 // these get recharged whenever the portal is used
 set g_balance_portal_lifetime 15 // these get recharged whenever the portal is used
 // }}}
-
-exec bal-wep-overkill.cfg
index 245fa7cc4cd06cdc0a8eabcf5ac346fc8190a5a7..6a1622c2c42c5dc1a85148cd6d84e380c63c88a7 100644 (file)
@@ -49,8 +49,8 @@ set g_balance_nix_ammoincr_fuel 2
 // }}}
 
 // {{{ pickup items
-set g_pickup_ammo_anyway 1
-set g_pickup_weapons_anyway 1
+set g_pickup_ammo_anyway 0
+set g_pickup_weapons_anyway 0
 set g_pickup_shells 15
 set g_pickup_shells_weapon 15
 set g_pickup_shells_max 60
@@ -72,28 +72,28 @@ set g_pickup_fuel_jetpack 100
 set g_pickup_fuel_max 100
 set g_pickup_armorsmall 5
 set g_pickup_armorsmall_max 200
-set g_pickup_armorsmall_anyway 1
+set g_pickup_armorsmall_anyway 0
 set g_pickup_armormedium 25
 set g_pickup_armormedium_max 200
-set g_pickup_armormedium_anyway 1
+set g_pickup_armormedium_anyway 0
 set g_pickup_armorbig 50
 set g_pickup_armorbig_max 200
-set g_pickup_armorbig_anyway 1
+set g_pickup_armorbig_anyway 0
 set g_pickup_armormega 100
 set g_pickup_armormega_max 200
-set g_pickup_armormega_anyway 1
+set g_pickup_armormega_anyway 0
 set g_pickup_healthsmall 5
 set g_pickup_healthsmall_max 200
-set g_pickup_healthsmall_anyway 1
+set g_pickup_healthsmall_anyway 0
 set g_pickup_healthmedium 25
 set g_pickup_healthmedium_max 200
-set g_pickup_healthmedium_anyway 1
+set g_pickup_healthmedium_anyway 0
 set g_pickup_healthbig 50
 set g_pickup_healthbig_max 200
-set g_pickup_healthbig_anyway 1
+set g_pickup_healthbig_anyway 0
 set g_pickup_healthmega 100
 set g_pickup_healthmega_max 200
-set g_pickup_healthmega_anyway 1
+set g_pickup_healthmega_anyway 0
 set g_pickup_respawntime_short 0.1
 set g_pickup_respawntime_medium 0.1
 set g_pickup_respawntime_long 0.1
index e8f4f1a589810a7ae237492fe2651366d5e0a311..18ee7ea28f1a100f21e29c8e0aed1d0c9fece23e 100644 (file)
@@ -4,7 +4,7 @@ bind f5 menu_showteamselect
 bind f6 team_auto
 
 bind f7 menu_showsandboxtools
-
+bind f8 "quickmenu"
 bind f9 "cl_cmd hud minigame"
 
 // movement
index b7c77fd563a35a24ca2b4c1c1b5a4319861b5d52..a6038dd59131c5df736e0862c8b29086f6833162 100755 (executable)
@@ -3,7 +3,16 @@ CPP=${CPP:-cpp}
 QCC=${QCC:-$PWD/../../gmqcc/gmqcc${CMAKE_EXECUTABLE_SUFFIX}}
 case $1 in
     compile)
-        ${CPP} ${@:3} | sed 's/^#\(line\)\? \([[:digit:]]\+\) "\(.*\)".*/\n#pragma file(\3)\n#pragma line(\2)/g' > $2
+        for var in "$@"; do case "$var" in
+            -I*)
+                home=${var:2}
+                break
+                ;;
+        esac; done
+        ${CPP} ${@:3} \
+            | sed -E "s|${home}|~|g" \
+            | sed -E 's/^#(line)? ([[:digit:]]+) "(.*)".*/'$'\\\n''#pragma file(\3)'$'\\\n''#pragma line(\2)/g' \
+            > $2
     ;;
     link)
         ${QCC} \
index 79366e4b703af1967b2ef20e8a1299536d4d9974..0e765b8a136cd83be6d5d0743421ac6b382f5fbf 100644 (file)
@@ -322,7 +322,7 @@ set sv_vote_master_password "" "when set, users can use \"vlogin PASSWORD\" to l
 set sv_vote_master_playerlimit 2 "Minimum number of players needed for a player to be allowed to vote for master"
 set sv_vote_no_stops_vote 1 "Allow the vote caller to stop his own vote simply by voting no"
 set sv_vote_singlecount 0      "set to 1 to count votes once after timeout or to 0 to count with every vote"
-set sv_vote_timeout 30 "a vote will timeout after this many seconds"
+set sv_vote_timeout 24 "a vote will timeout after this many seconds"
 set sv_vote_wait 120   "a player can not call a vote again for this many seconds when his vote was not accepted"
 set sv_vote_stop 15    "a player can not call a vote again for this many seconds when he stopped this vote (e.g. to correct it)"
 set sv_vote_majority_factor 0.5        "What percentage of the PLAYERS constitute a majority? (Must be at least 0.5, recommended: 0.5)"
index 5413fe14141f3cbed89c4740f39a0a60bf3b8c5a..149ddc5c83009b35febcc87fd30218d524d06148 100644 (file)
@@ -6,22 +6,23 @@
 # Martin Taibr <taibr.martin@gmail.com>, 2017
 # Martin Taibr <taibr.martin@gmail.com>, 2017
 # NONE <nechtom@gmail.com>, 2015
-# Tomáš Volavka <czheron@gmail.com>, 2015
+# Tomáš Volavka <czheron@gmail.com>, 2015,2018
 # Tomáš Volavka <czheron@gmail.com>, 2015
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 23:01+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-05-13 08:23+0000\n"
+"Last-Translator: Tomáš Volavka <czheron@gmail.com>\n"
 "Language-Team: Czech (http://www.transifex.com/team-xonotic/xonotic/language/"
 "cs/)\n"
 "Language: cs\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
+"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
@@ -31,7 +32,7 @@ msgstr "^2Úspěšně exportováno do %s! (Pozn.: Uloženo v data/data/)\n"
 #: qcsrc/client/hud/hud_config.qc:243
 #, c-format
 msgid "^1Couldn't write to %s\n"
-msgstr ""
+msgstr "^1Nelze zapisovat do %s\n"
 
 #: qcsrc/client/hud/panel/chat.qc:82
 msgid "^3Player^7: This is the chat area."
@@ -59,7 +60,7 @@ msgstr "^1Stiskni ^3%s^1 pro sledování"
 #: qcsrc/client/hud/panel/infomessages.qc:100
 #: qcsrc/menu/xonotic/keybinder.qc:40
 msgid "primary fire"
-msgstr ""
+msgstr "primární střelba"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #, c-format
@@ -69,12 +70,12 @@ msgstr "^1Stiskni ^3%s^1 nebo ^3%s^1 pro dalšího nebo předchozího hráče"
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "next weapon"
-msgstr ""
+msgstr "další zbraň"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "previous weapon"
-msgstr ""
+msgstr "předchozí zbraň"
 
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
@@ -84,17 +85,17 @@ msgstr "^1Použij ^3%s^1 nebo ^3%s^1 pro změnu rychlosti"
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
 msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
-msgstr ""
+msgstr "^1Stskni ^3%s^1 pro sledování, ^3%s^1 pro změnu kamery"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 msgid "drop weapon"
-msgstr ""
+msgstr "odhodit zbraň"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/menu/xonotic/keybinder.qc:41
 msgid "secondary fire"
-msgstr ""
+msgstr "sekundární střelba"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
@@ -123,7 +124,7 @@ msgstr "^1Stiskni ^3%s^1 pro připojení"
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
 msgid "jump"
-msgstr ""
+msgstr "skok"
 
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
index 5025390f48b08410f9b12d7363962fc949e51f33..2d4350a35f0c325b54ada8cc8a5c7c072366b5a6 100644 (file)
@@ -15,7 +15,8 @@
 # roader_gentoo <ivanviso123@gmail.com>, 2014
 # Rodrigo Mouton Laudin <ratogenesis@gmail.com>, 2011
 # Simon <inactive+0000simon@transifex.com>, 2014-2015
-# starfire24680 <starfire24680@gmail.com>, 2017
+# starfire24680 <starfire24680@gmail.com>, 2018
+# starfire24680 <starfire24680@gmail.com>, 2017-2018
 # starfire24680 <starfire24680@gmail.com>, 2017
 # Vitama Piru Leta <vitamanrules@gmail.com>, 2017
 # Ari_tent <xonotic@outlook.com>, 2014
@@ -26,8 +27,8 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 19:54+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-05-11 21:48+0000\n"
+"Last-Translator: starfire24680 <starfire24680@gmail.com>\n"
 "Language-Team: Spanish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/es/)\n"
 "Language: es\n"
@@ -48,7 +49,7 @@ msgstr "^1No se pudo escribir a %s\n"
 
 #: qcsrc/client/hud/panel/chat.qc:82
 msgid "^3Player^7: This is the chat area."
-msgstr "^3Jugador^7: Este es el area de chat."
+msgstr "^3Jugador^7: Este es el area del chat."
 
 #: qcsrc/client/hud/panel/engineinfo.qc:69
 #, c-format
@@ -97,7 +98,7 @@ msgstr "^1Usa ^3%s^1 o ^3%s^1 para cambiar la velocidad"
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
 msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
-msgstr "^1Pulsa ^3%s^1 para observar y ^3%s^1 para cambiar el modo de cámara."
+msgstr "^1Pulsa ^3%s^1 para observar o ^3%s^1 para cambiar el modo de cámara."
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
@@ -112,7 +113,7 @@ msgstr "disparo secundario"
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
 msgid "^1Press ^3%s^1 for gamemode info"
-msgstr "^1Presiona ^3%s^1 para información del modo de juego"
+msgstr "^1Presiona ^3%s^1 para mostrar información del modo de juego"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #: qcsrc/menu/xonotic/keybinder.qc:94
@@ -357,7 +358,7 @@ msgstr "QMCMD^asesinado el portador de bandera (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "QMCMD^asesinado el portador de la bandera, icono"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -370,11 +371,11 @@ msgstr "QMCMD^bandera tirada, icono"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "QMCMD^tirar arma, icono"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^arma tirada %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -523,7 +524,7 @@ msgstr "Linea de salida"
 #: qcsrc/client/hud/panel/racetimer.qc:63
 #: qcsrc/client/hud/panel/racetimer.qc:67
 msgid "Finish line"
-msgstr "Línea eta"
+msgstr "Línea de meta"
 
 #: qcsrc/client/hud/panel/racetimer.qc:65
 #, c-format
@@ -1118,7 +1119,7 @@ msgstr "No importa"
 
 #: qcsrc/client/mapvoting.qc:365
 msgid "Decide the gametype"
-msgstr "Elegir el modo de juego"
+msgstr "Elige el modo de juego"
 
 #: qcsrc/client/mapvoting.qc:365
 msgid "Vote for a map"
@@ -1132,7 +1133,7 @@ msgstr "%d segundos restantes"
 #: qcsrc/client/mapvoting.qc:497
 msgid ""
 "mv_mapdownload: ^3You're not supposed to use this command on your own!\n"
-msgstr "mv_mapdownload: ^3¡No deberias usar este comando en tí!\n"
+msgstr "mv_mapdownload: ^3¡No deberias usar este comando por tu cuenta!\n"
 
 #: qcsrc/client/mapvoting.qc:507
 msgid "^1Error:^7 Couldn't find pak index.\n"
@@ -1251,7 +1252,7 @@ msgstr "Combate a muerte por equipos"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid "Capture the Flag"
-msgstr "Consigue la bandera"
+msgstr "Captura la bandera"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid ""
@@ -1679,7 +1680,7 @@ msgstr "Color:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
 msgid "Draw damage numbers for friendly fire"
-msgstr "Dibujar números de daño para fuego amigo"
+msgstr "Dibujar números de daño para el fuego amigo"
 
 #: qcsrc/common/mutators/mutator/instagib/items.qh:56
 msgid "Extra life"
@@ -1814,7 +1815,7 @@ msgstr "Base rosa"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:29
 msgid "Return flag here"
-msgstr "Devuele la vandera aquí"
+msgstr "Devuelva la bandera aquí"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:31
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:32
@@ -1912,8 +1913,8 @@ msgid ""
 "^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG"
 "%s^BG's previous record of ^F2%s^BG seconds"
 msgstr ""
-"^BG%s^BG capturó la bandera ^TC^TT^BG en ^F1%s^BG segundos, rompiendo ^BG"
-"%s^BG's el record anterior de ^F2%s^BG segundos"
+"^BG%s^BG capturó la bandera ^TC^TT^BG en ^F1%s^BG segundos, batiendo el "
+"record anterior de ^BG%s^BG de ^F2%s^BG segundos"
 
 #: qcsrc/common/notifications/all.inc:243
 #, c-format
@@ -1932,7 +1933,7 @@ msgid ""
 "^BG%s^BG's previous record of ^F1%s^BG seconds"
 msgstr ""
 "^BG%s^BG capturó la bandera ^TC^TT^BG en ^F2%s^BG segundos, fallando al "
-"romper ^BG%s^BG's el record anterior de ^F1%s^BG segundos"
+"batir el record anterior de ^BG%s^BG de ^F1%s^BG segundos"
 
 #: qcsrc/common/notifications/all.inc:246
 msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
@@ -2085,12 +2086,12 @@ msgstr "^BG%s%s^K1 fue cocinado por ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:280
 #, c-format
 msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 fue empujado a un monstruo por ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 fue empujado hacia un monstruo por ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:281
 #, c-format
 msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"
-msgstr "^BG%s%s^K1 fue explotado por ^BG%s^K1 Granda%s%s"
+msgstr "^BG%s%s^K1 fue explotado por la granada de ^BG%s^K1 %s%s"
 
 #: qcsrc/common/notifications/all.inc:282
 #, c-format
@@ -2869,7 +2870,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:443
 #, c-format
 msgid "^BG%s^K1 picked up a Superweapon"
-msgstr "^BG%s^K1 ha recogido una superarma"
+msgstr "^BG%s^K1 ha recogido una Superarma"
 
 #: qcsrc/common/notifications/all.inc:445
 msgid "^BGYou cannot change to a larger team"
@@ -2908,7 +2909,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:452
 #, c-format
 msgid "^F3SVQC Build information: ^F4%s"
-msgstr "^F3SVQC Información de compilación ^F4%s"
+msgstr "^F3SVQC Información de compilación: ^F4%s"
 
 #: qcsrc/common/notifications/all.inc:454
 #, c-format
@@ -3106,7 +3107,7 @@ msgstr "^BG%s%s^K1 se acercó demasiado a la granada del Mortar de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:490
 #, c-format
 msgid "^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"
-msgstr "^BG%s%s^K1 se comió la granada del mortar de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 se comió la granada del Mortero de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:491
 #, c-format
@@ -3215,7 +3216,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:510
 #, c-format
 msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Tuba%s%s"
-msgstr "^BG%s^K1 lastimó sus propios oidos con el @!#%%'n Tuba%s%s"
+msgstr "^BG%s^K1 lastimó sus propios oidos con la @!#%%'n Tuba%s%s"
 
 #: qcsrc/common/notifications/all.inc:511
 #, c-format
@@ -4120,7 +4121,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:788
 msgid "^F2Intruder detected, disabling shields!"
-msgstr ""
+msgstr "^F2Intruso detectado, desactivando escudos!"
 
 #: qcsrc/common/notifications/all.qh:188
 msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
@@ -4533,11 +4534,11 @@ msgstr "Presiona %s"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
 msgid "No right gunner!"
-msgstr "Sin ametralladora derecha!"
+msgstr "¡Sin artillero derecho!"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
 msgid "No left gunner!"
-msgstr "Sin ametralladora izquierda!"
+msgstr "¡Sin artillero izquierdo!"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
 msgid "Bumblebee"
@@ -5041,7 +5042,7 @@ msgstr "Húngaro"
 
 #: qcsrc/menu/xonotic/credits.qc:231
 msgid "Irish"
-msgstr ""
+msgstr "Irlandés"
 
 #: qcsrc/menu/xonotic/credits.qc:234
 msgid "Italian"
@@ -5073,7 +5074,7 @@ msgstr "Ruso"
 
 #: qcsrc/menu/xonotic/credits.qc:279
 msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Gaélico escocés"
 
 #: qcsrc/menu/xonotic/credits.qc:282
 msgid "Serbian"
@@ -7390,7 +7391,7 @@ msgstr "Ajustado"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:163
 msgid "Decals"
-msgstr "Símbolos"
+msgstr "Calcomanía"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
 msgid "Enable decals (bullet holes and blood) (default: enabled)"
index abdf38575f2f818c6c39ebde32433e80b706b9e5..593e684a646c9714c90d90cbf02bf197633a270b 100644 (file)
@@ -16,7 +16,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % "
+"1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
index 60d4b36c96cb5cd5823293d1937ec57bbbd0c163..6738cdd3ec480efde886411cf0b8458e485f9cd8 100644 (file)
@@ -20,7 +20,7 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=1; plural=0;\n"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
index 33fbaf5be42b6257b4e7a8dd963119c9d8036ff7..7562f10ba65f2c0a0ff7a4fc59f861da47f0bf56 100644 (file)
@@ -3,22 +3,23 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# Nicky Rowe <nickyrowe@gmail.com>, 2016
+# Nicky Rowe <nicky@kernowlingo.com>, 2016,2018
+# Nicky Rowe <nicky@kernowlingo.com>, 2016
+# Nicky Rowe <nicky@kernowlingo.com>, 2016
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-22 11:16+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-04-28 07:53+0000\n"
+"Last-Translator: Nicky Rowe <nicky@kernowlingo.com>\n"
 "Language-Team: Cornish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/kw/)\n"
 "Language: kw\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : "
-"3;\n"
+"Plural-Forms: nplurals=3; plural=(n == 1 ? 0 : n == 2 ? 1 : 2);\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
@@ -56,7 +57,7 @@ msgstr "^1Gweskewgh ^3%s^1 rag mires"
 #: qcsrc/client/hud/panel/infomessages.qc:100
 #: qcsrc/menu/xonotic/keybinder.qc:40
 msgid "primary fire"
-msgstr ""
+msgstr "tenn kensa"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #, c-format
@@ -66,12 +67,12 @@ msgstr "^1Gweskewgh ^3%s^1 po ^3%s^1 rag an gwarier nessa po kyns"
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "next weapon"
-msgstr ""
+msgstr "arv nessa"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "previous weapon"
-msgstr ""
+msgstr "arv gens"
 
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
@@ -81,17 +82,17 @@ msgstr "^1Usyewgh ^3%s^1 po ^3%s^1 rag chanjya an tooth"
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
 msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
-msgstr ""
+msgstr "^1Gweskewgh ^3%s^1 aspia, ^3%s^1 dhe janjya modh an kamera"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 msgid "drop weapon"
-msgstr ""
+msgstr "droppya an arv"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/menu/xonotic/keybinder.qc:41
 msgid "secondary fire"
-msgstr ""
+msgstr "tenn nessa"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
@@ -101,7 +102,7 @@ msgstr "^1Gweskewgh ^3%s^1 rag kedhlow an modh gwari"
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #: qcsrc/menu/xonotic/keybinder.qc:94
 msgid "server info"
-msgstr ""
+msgstr "kedhlow an servyer"
 
 #: qcsrc/client/hud/panel/infomessages.qc:124
 msgid "^1Match has already begun"
@@ -120,7 +121,7 @@ msgstr "^1Gweskewgh ^3%s^1 dhe junya"
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
 msgid "jump"
-msgstr ""
+msgstr "lamma"
 
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
@@ -141,7 +142,7 @@ msgstr "%sGweskewgh ^3%s%s rag diwedha an tommheans"
 #: qcsrc/client/hud/panel/infomessages.qc:175
 #: qcsrc/menu/xonotic/keybinder.qc:91
 msgid "ready"
-msgstr ""
+msgstr "parys"
 
 #: qcsrc/client/hud/panel/infomessages.qc:162
 #, c-format
@@ -173,15 +174,15 @@ msgstr " Gweskewgh ^3%s%s rag kompeshe"
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #: qcsrc/menu/xonotic/keybinder.qc:102
 msgid "team menu"
-msgstr ""
+msgstr "rol an para"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating this player:"
-msgstr ""
+msgstr "^1Owth aspia an gwarier ma:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating you:"
-msgstr ""
+msgstr "^1Orth dha aspia:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:225
 msgid "^7Press ^3ESC ^7to show HUD options."
@@ -340,7 +341,7 @@ msgstr "QMCMD^doger an baner ledhys (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "QMCMD^a ladhas doger an baner, arwodhik"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -353,11 +354,11 @@ msgstr "QMCMD^baner droppyes, arwodhik"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "QMCMD^droppya an arv, arwodhik"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^a dhroppyas an arv %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -555,7 +556,7 @@ msgstr "SCO^distruys"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:84
 msgid "SCO^damage"
-msgstr ""
+msgstr "SCO^damach"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:85
 msgid "SCO^dmgtaken"
@@ -655,7 +656,7 @@ msgstr "SCO^teudhys"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:109
 msgid "SCO^rounds won"
-msgstr ""
+msgstr "SCO^rondys gwaynyes"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:110
 msgid "SCO^score"
@@ -702,7 +703,7 @@ msgstr "Aswonys yw an henwyn skrifva a sew (nyns yw an kas aswonys):\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:301
 msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
-msgstr ""
+msgstr "Ty a yll usya ^3|^7 rag dalleth an parkow alinys a-dhyghow.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:304
 msgid "^3name^7 or ^3nick^7             Name of a player\n"
@@ -718,7 +719,7 @@ msgstr "^3pl^7                       Fardelligow kellys\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:307
 msgid "^3elo^7                      Player ELO\n"
-msgstr ""
+msgstr "^3elo^7                      ELO an gwarier\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:308
 msgid "^3kills^7                    Number of kills\n"
@@ -851,7 +852,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:335
 msgid "^3score^7                    Total score\n"
-msgstr ""
+msgstr "^3score^7                    Skor dien\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:338
 msgid ""
@@ -928,7 +929,7 @@ msgstr "Kevrinyow diskudhys:"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Capture time rankings"
-msgstr ""
+msgstr "Renkyow an termyn sesya"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Rankings"
@@ -942,12 +943,12 @@ msgstr "Bord an skoryow"
 #: qcsrc/client/hud/panel/scoreboard.qc:1584
 #, c-format
 msgid "Speed award: %d%s ^7(%s^7)"
-msgstr ""
+msgstr "Powas tooth: %d%s ^7(%s^7)"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1588
 #, c-format
 msgid "All-time fastest: %d%s ^7(%s^7)"
-msgstr ""
+msgstr "An kreffa oll-dermyn: %d%s ^7(%s^7)"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1604
 #, c-format
@@ -1039,7 +1040,7 @@ msgstr "^1Restra an HUD"
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:16
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:15
 msgid "Yes"
-msgstr ""
+msgstr "Ya"
 
 #: qcsrc/client/hud/panel/vote.qc:127 qcsrc/menu/xonotic/dialog_firstrun.qc:83
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:21
@@ -1049,7 +1050,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:17
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:17
 msgid "No"
-msgstr ""
+msgstr "Na"
 
 #: qcsrc/client/hud/panel/weapons.qc:530
 msgid "Out of ammo"
@@ -1139,7 +1140,7 @@ msgstr "Euryer granaden"
 
 #: qcsrc/client/view.qc:1385
 msgid "Capture progress"
-msgstr ""
+msgstr "Spedyans ow sesya"
 
 #: qcsrc/client/view.qc:1390
 msgid "Revival progress"
@@ -1160,7 +1161,7 @@ msgstr "Lader pelyow"
 
 #: qcsrc/common/items/item/armor.qh:111
 msgid "Big armor"
-msgstr ""
+msgstr "Arvwisk bras"
 
 #: qcsrc/common/items/item/armor.qh:147
 msgid "Mega armor"
@@ -1168,7 +1169,7 @@ msgstr "Arvwisk mega"
 
 #: qcsrc/common/items/item/health.qh:111
 msgid "Big health"
-msgstr ""
+msgstr "Yeghes bras"
 
 #: qcsrc/common/items/item/health.qh:147
 msgid "Mega health"
@@ -1308,6 +1309,8 @@ msgid ""
 "Kill enemies to freeze them, stand next to frozen teammates to revive them; "
 "freeze all enemies to win"
 msgstr ""
+"Ladh eskerens rag aga rewi, sav ryb dha bara rag aga dasserghi; rew pub "
+"eskar rag gwaynya"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Hold the ball to get points for kills"
@@ -1514,135 +1517,135 @@ msgstr "Lemmewgh darn a-ugh darn aral rag y sesya"
 
 #: qcsrc/common/minigames/minigame/ttt.qc:666
 msgid "Single Player"
-msgstr ""
+msgstr "Unn gwarier"
 
 #: qcsrc/common/monsters/monster/mage.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:18
 msgid "Mage"
-msgstr ""
+msgstr "Huder"
 
 #: qcsrc/common/monsters/monster/mage.qh:29
 msgid "Mage spike"
-msgstr ""
+msgstr "Spik an huder"
 
 #: qcsrc/common/monsters/monster/shambler.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:17
 msgid "Shambler"
-msgstr ""
+msgstr "Shambler"
 
 #: qcsrc/common/monsters/monster/spider.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:16
 msgid "Spider"
-msgstr ""
+msgstr "Kevnisen"
 
 #: qcsrc/common/monsters/monster/spider.qh:28
 msgid "Spider attack"
-msgstr ""
+msgstr "Omsettyans kevnisen"
 
 #: qcsrc/common/monsters/monster/wyvern.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:19
 msgid "Wyvern"
-msgstr ""
+msgstr "Dragon"
 
 #: qcsrc/common/monsters/monster/wyvern.qh:28
 msgid "Wyvern attack"
-msgstr ""
+msgstr "Omsettyans dragon"
 
 #: qcsrc/common/monsters/monster/zombie.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:15
 msgid "Zombie"
-msgstr ""
+msgstr "Zombi"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:15
 msgid "Ammo"
-msgstr ""
+msgstr "Daffar ladhva"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:24
 msgid "Resistance"
-msgstr ""
+msgstr "Defens"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:33
 #: qcsrc/common/mutators/mutator/instagib/items.qh:94
 msgid "Speed"
-msgstr ""
+msgstr "Tooth"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:43
 msgid "Medic"
-msgstr ""
+msgstr "Medhek"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:54
 msgid "Bash"
-msgstr ""
+msgstr "Kronkya"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:62
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:85
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:177
 msgid "Vampire"
-msgstr ""
+msgstr "Vampir"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:70
 msgid "Disability"
-msgstr ""
+msgstr "Anles"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:78
 msgid "Vengeance"
-msgstr ""
+msgstr "Venjyans"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:86
 msgid "Jump"
-msgstr ""
+msgstr "Lamma"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:95
 msgid "Invisible"
-msgstr ""
+msgstr "Anweladow"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:104
 msgid "Inferno"
-msgstr ""
+msgstr "Inferno"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:112
 msgid "Swapper"
-msgstr ""
+msgstr "Keschanj"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:120
 msgid "Magnet"
-msgstr ""
+msgstr "Tennven"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:128
 msgid "Luck"
-msgstr ""
+msgstr "Chons"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:136
 msgid "Flight"
-msgstr ""
+msgstr "Neyj"
 
 #: qcsrc/common/mutators/mutator/buffs/buffs.qh:7
 msgid "Buff"
-msgstr ""
+msgstr "Bonus"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
 msgid "Damage text"
-msgstr ""
+msgstr "Tekst damach"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:18
 msgid "Draw damage numbers"
-msgstr ""
+msgstr "Delinya niverow damach"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:20
 msgid "Font size minimum:"
-msgstr ""
+msgstr "Myns font an lyha:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:25
 msgid "Font size maximum:"
-msgstr ""
+msgstr "Myns font an ughella:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:30
 msgid "Accumulate range:"
-msgstr ""
+msgstr "Kuntel towlhys:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:35
 msgid "Lifetime:"
-msgstr ""
+msgstr "Termyn bewnans:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:40
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:50
@@ -1656,11 +1659,11 @@ msgstr "Liw:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
 msgid "Draw damage numbers for friendly fire"
-msgstr ""
+msgstr "Delinya niverow damach rag tenn kowethek"
 
 #: qcsrc/common/mutators/mutator/instagib/items.qh:56
 msgid "Extra life"
-msgstr ""
+msgstr "Bewnans keworransel"
 
 #: qcsrc/common/mutators/mutator/instagib/items.qh:75
 msgid "Invisibility"
@@ -1668,51 +1671,51 @@ msgstr "Anweladowder"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:18
 msgid "Napalm grenade"
-msgstr ""
+msgstr "Grenad napalm"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:26
 msgid "Ice grenade"
-msgstr ""
+msgstr "Grenad rew"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:34
 msgid "Translocate grenade"
-msgstr ""
+msgstr "Grenad treustesedha"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:42
 msgid "Spawn grenade"
-msgstr ""
+msgstr "Grenad dinythi"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:50
 msgid "Heal grenade"
-msgstr ""
+msgstr "Grenad sawya"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:58
 msgid "Monster grenade"
-msgstr ""
+msgstr "Grenad euthvil"
 
 #: qcsrc/common/mutators/mutator/nades/nades.inc:66
 msgid "Entrap grenade"
-msgstr ""
+msgstr "Grenad maglenna"
 
 #: qcsrc/common/mutators/mutator/nades/nades.qh:32
 msgid "Grenade"
-msgstr ""
+msgstr "Grenad"
 
 #: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
 msgid "Heavy Machine Gun"
-msgstr ""
+msgstr "Gonn Jynn Poos"
 
 #: qcsrc/common/mutators/mutator/overkill/rpc.qh:17
 msgid "Rocket Propelled Chainsaw"
-msgstr ""
+msgstr "Hesken gadon rocket"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:3
 msgid "Waypoint"
-msgstr ""
+msgstr "Fordhva"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:4
 msgid "Help me!"
-msgstr ""
+msgstr "Gweres vy!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:5
 msgid "Here"
@@ -1720,7 +1723,7 @@ msgstr "Omma"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:6
 msgid "DANGER"
-msgstr ""
+msgstr "PERYL"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:8
 msgid "Frozen!"
@@ -1728,11 +1731,11 @@ msgstr "Rewys!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:10
 msgid "Item"
-msgstr ""
+msgstr "Tra"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:12
 msgid "Checkpoint"
-msgstr ""
+msgstr "Checkva"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:13
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
@@ -1747,51 +1750,51 @@ msgstr "Dallethva"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:17
 msgid "Defend"
-msgstr ""
+msgstr "Difres"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:18
 msgid "Destroy"
-msgstr ""
+msgstr "Distrui"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:19
 msgid "Push"
-msgstr ""
+msgstr "Herdhya"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:21
 msgid "Flag carrier"
-msgstr ""
+msgstr "Doger an baner"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:22
 msgid "Enemy carrier"
-msgstr ""
+msgstr "Doger an anvi"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:23
 msgid "Dropped flag"
-msgstr ""
+msgstr "Baner droppyes"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:24
 msgid "White base"
-msgstr ""
+msgstr "Selva wynn"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:25
 msgid "Red base"
-msgstr ""
+msgstr "Selva rudh"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:26
 msgid "Blue base"
-msgstr ""
+msgstr "Selva las"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:27
 msgid "Yellow base"
-msgstr ""
+msgstr "Selva velyn"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:28
 msgid "Pink base"
-msgstr ""
+msgstr "Selva wynnrudh"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:29
 msgid "Return flag here"
-msgstr ""
+msgstr "Daskor an baner arta"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:31
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:32
@@ -1802,11 +1805,11 @@ msgstr ""
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:52
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:53
 msgid "Control point"
-msgstr ""
+msgstr "Kontrolva"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:37
 msgid "Dropped key"
-msgstr ""
+msgstr "Alhwedh droppyes"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:38
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:40
@@ -1814,11 +1817,11 @@ msgstr ""
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:42
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:43
 msgid "Key carrier"
-msgstr ""
+msgstr "Deger an alhwedh"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:39
 msgid "Run here"
-msgstr ""
+msgstr "Poon bys yn omma"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:45
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:48
@@ -1827,54 +1830,55 @@ msgstr "Pel"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:46
 msgid "Ball carrier"
-msgstr ""
+msgstr "Deger an bel"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:49
 msgid "Goal"
-msgstr ""
+msgstr "Gol"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:54
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:55
 msgid "Generator"
-msgstr ""
+msgstr "Dinythor"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:57
 msgid "Weapon"
-msgstr ""
+msgstr "Arv"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:59
 msgid "Monster"
-msgstr ""
+msgstr "Euthvil"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:61
 msgid "Vehicle"
-msgstr ""
+msgstr "Karr"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:62
 msgid "Intruder!"
-msgstr ""
+msgstr "Kammdremener!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:64
 msgid "Tagged"
-msgstr ""
+msgstr "Taggys"
 
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:651
 #: qcsrc/common/turrets/cl_turrets.qc:120
 msgid "Spam"
-msgstr ""
+msgstr "Spam"
 
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:655
 #, c-format
 msgid "%s needing help!"
-msgstr ""
+msgstr "%s ow kovyn gweres!"
 
 #: qcsrc/common/net_notice.qc:87
 msgid "^1Server notices:"
-msgstr ""
+msgstr "^1Notyansow an servyer:"
 
 #: qcsrc/common/notifications/all.inc:239
 msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
 msgstr ""
+"^F4NOTEN: ^BGNyns yw klap an viroryon danvenys dhe warioryon dres an fytt"
 
 #: qcsrc/common/notifications/all.inc:241
 #, c-format
diff --git a/common.ms.po b/common.ms.po
new file mode 100644 (file)
index 0000000..f50708e
--- /dev/null
@@ -0,0 +1,9172 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Muhammad Nur Hidayat Yasuyoshi <mnh48mail@gmail.com>, 2018
+msgid ""
+msgstr ""
+"Project-Id-Version: Xonotic\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-09 00:35+0200\n"
+"PO-Revision-Date: 2018-05-29 05:44+0000\n"
+"Last-Translator: Muhammad Nur Hidayat Yasuyoshi <mnh48mail@gmail.com>\n"
+"Language-Team: Malay (http://www.transifex.com/team-xonotic/xonotic/language/"
+"ms/)\n"
+"Language: ms\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+#: qcsrc/client/hud/hud_config.qc:239
+#, c-format
+msgid "^2Successfully exported to %s! (Note: It's saved in data/data/)\n"
+msgstr "^2Berjaya dieksport ke %s! (Nota: Ia disimpan di data/data/)\n"
+
+#: qcsrc/client/hud/hud_config.qc:243
+#, c-format
+msgid "^1Couldn't write to %s\n"
+msgstr "^1Tidak boleh menulis ke %s\n"
+
+#: qcsrc/client/hud/panel/chat.qc:82
+msgid "^3Player^7: This is the chat area."
+msgstr "^3Pemain^7: Ini kawasan sembang."
+
+#: qcsrc/client/hud/panel/engineinfo.qc:69
+#, c-format
+msgid "FPS: %.*f"
+msgstr "FPS: %.*f"
+
+#: qcsrc/client/hud/panel/infomessages.qc:87
+msgid "^1Observing"
+msgstr "^1Memerhati"
+
+#: qcsrc/client/hud/panel/infomessages.qc:89
+#, c-format
+msgid "^1Spectating: ^7%s"
+msgstr "^1Menonton: ^7%s"
+
+#: qcsrc/client/hud/panel/infomessages.qc:100
+#, c-format
+msgid "^1Press ^3%s^1 to spectate"
+msgstr "^1Tekan ^3%s^1 untuk menonton"
+
+#: qcsrc/client/hud/panel/infomessages.qc:100
+#: qcsrc/menu/xonotic/keybinder.qc:40
+msgid "primary fire"
+msgstr "senjata api utama"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#, c-format
+msgid "^1Press ^3%s^1 or ^3%s^1 for next or previous player"
+msgstr "^1Tekan ^3%s^1 atau ^3%s^1 untuk pemain seterusnya atau sebelumnya"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#: qcsrc/client/hud/panel/infomessages.qc:106
+msgid "next weapon"
+msgstr "senjata seterusnya"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#: qcsrc/client/hud/panel/infomessages.qc:106
+msgid "previous weapon"
+msgstr "senjata sebelumnya"
+
+#: qcsrc/client/hud/panel/infomessages.qc:106
+#, c-format
+msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
+msgstr "^1Gunakan ^3%s^1 atau ^3%s^1 untuk mengubah kelajuan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#, c-format
+msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
+msgstr "^1Tekan ^3%s^1 untuk memerhati, ^3%s^1 untuk tukar mod kamera"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#: qcsrc/common/vehicles/cl_vehicles.qc:192
+msgid "drop weapon"
+msgstr "jatuhkan senjata"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#: qcsrc/menu/xonotic/keybinder.qc:41
+msgid "secondary fire"
+msgstr "senjata api kedua"
+
+#: qcsrc/client/hud/panel/infomessages.qc:111
+#, c-format
+msgid "^1Press ^3%s^1 for gamemode info"
+msgstr "^1Tekan ^3%s^1 untuk maklumat mod permainan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:111
+#: qcsrc/menu/xonotic/keybinder.qc:94
+msgid "server info"
+msgstr "maklumat pelayan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:124
+msgid "^1Match has already begun"
+msgstr "^1Perlawanan telah bermula"
+
+#: qcsrc/client/hud/panel/infomessages.qc:126
+msgid "^1You have no more lives left"
+msgstr "^1Anda dah kehabisan nyawa"
+
+#: qcsrc/client/hud/panel/infomessages.qc:128
+#: qcsrc/client/hud/panel/infomessages.qc:131
+#, c-format
+msgid "^1Press ^3%s^1 to join"
+msgstr "^1Tekan ^3%s^1 untuk ikut serta"
+
+#: qcsrc/client/hud/panel/infomessages.qc:128
+#: qcsrc/client/hud/panel/infomessages.qc:131
+msgid "jump"
+msgstr "lompat"
+
+#: qcsrc/client/hud/panel/infomessages.qc:139
+#, c-format
+msgid "^1Game starts in ^3%d^1 seconds"
+msgstr "^1Permainan bermula dalam ^3%d^1 saat"
+
+#: qcsrc/client/hud/panel/infomessages.qc:145
+msgid "^2Currently in ^1warmup^2 stage!"
+msgstr "^2Kini ni peringkat ^1panaskan badan^2!"
+
+#: qcsrc/client/hud/panel/infomessages.qc:160
+#, c-format
+msgid "%sPress ^3%s%s to end warmup"
+msgstr "%sTekan ^3%s%s untuk tamatkan sesi panaskan badan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:160
+#: qcsrc/client/hud/panel/infomessages.qc:162
+#: qcsrc/client/hud/panel/infomessages.qc:175
+#: qcsrc/menu/xonotic/keybinder.qc:91
+msgid "ready"
+msgstr "bersedia"
+
+#: qcsrc/client/hud/panel/infomessages.qc:162
+#, c-format
+msgid "%sPress ^3%s%s once you are ready"
+msgstr "%sTekan ^3%s%s apabila anda dah bersedia"
+
+#: qcsrc/client/hud/panel/infomessages.qc:167
+msgid "^2Waiting for others to ready up to end warmup..."
+msgstr ""
+"^2Menunggu yang lain untuk bersedia sebelum menamatkan sesi panaskan badan..."
+
+#: qcsrc/client/hud/panel/infomessages.qc:169
+msgid "^2Waiting for others to ready up..."
+msgstr "^2Menunggu yang lain untuk bersedia..."
+
+#: qcsrc/client/hud/panel/infomessages.qc:175
+#, c-format
+msgid "^2Press ^3%s^2 to end warmup"
+msgstr "^2Tekan ^3%s^2 untuk tamatkan sesi panaskan badan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:196
+msgid "Teamnumbers are unbalanced!"
+msgstr "Jumlah ahli pasukan tidak seimbang!"
+
+#: qcsrc/client/hud/panel/infomessages.qc:199
+#, c-format
+msgid " Press ^3%s%s to adjust"
+msgstr " Tekan ^3%s%s untuk susun"
+
+#: qcsrc/client/hud/panel/infomessages.qc:199
+#: qcsrc/menu/xonotic/keybinder.qc:102
+msgid "team menu"
+msgstr "menu pasukan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:209
+msgid "^1Spectating this player:"
+msgstr "^1Menonton pemain ini:"
+
+#: qcsrc/client/hud/panel/infomessages.qc:209
+msgid "^1Spectating you:"
+msgstr "^1Menonton anda:"
+
+#: qcsrc/client/hud/panel/infomessages.qc:225
+msgid "^7Press ^3ESC ^7to show HUD options."
+msgstr "^7Tekan ^3ESC ^7untuk menunjukkan pilihan HUD."
+
+#: qcsrc/client/hud/panel/infomessages.qc:226
+msgid "^3Doubleclick ^7a panel for panel-specific options."
+msgstr "^3Klik dua kali ^7a panel untuk pilihan khusus panel."
+
+#: qcsrc/client/hud/panel/infomessages.qc:227
+msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
+msgstr "^3CTRL ^7untuk melumpuhkan percubaan perlanggaran, ^3SHIFT ^7dan"
+
+#: qcsrc/client/hud/panel/infomessages.qc:228
+msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
+msgstr "^3ALT ^7+ ^3KEKUNCI ANAK PANAH ^7untuk pelarasan halus."
+
+#: qcsrc/client/hud/panel/modicons.qc:566
+msgid "Personal best"
+msgstr "Pencapaian terbaik peribadi"
+
+#: qcsrc/client/hud/panel/modicons.qc:576
+msgid "Server best"
+msgstr "Pencapaian terbaik pelayan"
+
+#: qcsrc/client/hud/panel/notify.qc:115 qcsrc/client/hud/panel/notify.qc:116
+#: qcsrc/client/hud/panel/score.qc:59
+#, c-format
+msgid "Player %d"
+msgstr "Pemain %d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:603
+#: qcsrc/client/hud/panel/quickmenu.qc:605
+#, c-format
+msgid "Submenu%d"
+msgstr "Submenu%d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:610
+#, c-format
+msgid "Command%d"
+msgstr "Perintah%d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:636
+msgid "Continue..."
+msgstr "Teruskan..."
+
+#: qcsrc/client/hud/panel/quickmenu.qc:794
+#: qcsrc/client/hud/panel/quickmenu.qc:798
+msgid "Chat"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:795
+msgid "QMCMD^:-) / nice one"
+msgstr "QMCMD^:-) / hebat"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:795
+msgid "QMCMD^nice one"
+msgstr "QMCMD^hebat"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:796
+msgid "QMCMD^good game"
+msgstr "QMCMD^terbaiklah"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:797
+msgid "QMCMD^hi / good luck"
+msgstr "QMCMD^hai / semoga berjaya"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:797
+msgid "QMCMD^hi / good luck and have fun"
+msgstr "QMCMD^hai / semoga berjaya dan bergembiralah"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:802
+#: qcsrc/client/hud/panel/quickmenu.qc:818
+msgid "QMCMD^Team chat"
+msgstr "QMCMD^Sembang pasukan"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:803
+msgid "QMCMD^quad soon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:804
+msgid "QMCMD^free item %x^7 (l:%y^7)"
+msgstr "QMCMD^item percuma %x^7 (l:%y^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:804
+msgid "QMCMD^free item, icon"
+msgstr "QMCMD^item percuma, ikon"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:805
+msgid "QMCMD^took item (l:%l^7)"
+msgstr "QMCMD^mengambil item (l:%l^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:805
+msgid "QMCMD^took item, icon"
+msgstr "QMCMD^mengambil item, ikon"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:806
+msgid "QMCMD^negative"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:807
+msgid "QMCMD^positive"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:808
+msgid "QMCMD^need help (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:808
+msgid "QMCMD^need help, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:809
+msgid "QMCMD^enemy seen (l:%y^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:809
+msgid "QMCMD^enemy seen, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:810
+msgid "QMCMD^flag seen (l:%y^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:810
+msgid "QMCMD^flag seen, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:811
+msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:811
+msgid "QMCMD^defending, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:812
+msgid "QMCMD^roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:812
+msgid "QMCMD^roaming, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:813
+msgid "QMCMD^attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:813
+msgid "QMCMD^attacking, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:814
+msgid "QMCMD^killed flagcarrier (l:%y^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:814
+msgid "QMCMD^killed flagcarrier, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:815
+#, c-format
+msgid "QMCMD^dropped flag (l:%d^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:815
+msgid "QMCMD^dropped flag, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:816
+msgid "QMCMD^drop weapon, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:816
+msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:817
+msgid "QMCMD^drop flag/key, icon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:817
+msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:821
+msgid "QMCMD^Send private message to"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:823
+#: qcsrc/client/hud/panel/quickmenu.qc:860
+msgid "QMCMD^Settings"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:824
+#: qcsrc/client/hud/panel/quickmenu.qc:831
+msgid "QMCMD^View/HUD settings"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:825
+msgid "QMCMD^3rd person view"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:826
+msgid "QMCMD^Player models like mine"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:827
+msgid "QMCMD^Names above players"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:828
+msgid "QMCMD^Crosshair per weapon"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:829
+msgid "QMCMD^FPS"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:830
+msgid "QMCMD^Net graph"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:833
+#: qcsrc/client/hud/panel/quickmenu.qc:836
+msgid "QMCMD^Sound settings"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:834
+msgid "QMCMD^Hit sound"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:835
+msgid "QMCMD^Chat sound"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:840
+#: qcsrc/client/hud/panel/quickmenu.qc:844
+msgid "QMCMD^Spectator camera"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:841
+msgid "QMCMD^1st person"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:842
+msgid "QMCMD^3rd person around player"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:843
+msgid "QMCMD^3rd person behind"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:849
+#: qcsrc/client/hud/panel/quickmenu.qc:854
+msgid "QMCMD^Observer camera"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:850
+msgid "QMCMD^Increase speed"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:851
+msgid "QMCMD^Decrease speed"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:852
+msgid "QMCMD^Wall collision off"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:853
+msgid "QMCMD^Wall collision on"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:857
+msgid "QMCMD^Fullscreen"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:859
+msgid "QMCMD^Translate chat messages"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:862
+#: qcsrc/client/hud/panel/quickmenu.qc:872
+msgid "QMCMD^Call a vote"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:863
+msgid "QMCMD^Restart the map"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:864
+msgid "QMCMD^End match"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:867
+msgid "QMCMD^Reduce match time"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:868
+msgid "QMCMD^Extend match time"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:871
+msgid "QMCMD^Shuffle teams"
+msgstr ""
+
+#: qcsrc/client/hud/panel/racetimer.qc:37
+#, c-format
+msgid " (-%dL)"
+msgstr " (-%dL)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:42
+#, c-format
+msgid " (+%dL)"
+msgstr " (+%dL)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:61
+msgid "Start line"
+msgstr "Garisan pemula"
+
+#: qcsrc/client/hud/panel/racetimer.qc:63
+#: qcsrc/client/hud/panel/racetimer.qc:67
+msgid "Finish line"
+msgstr "Garisan penamat"
+
+#: qcsrc/client/hud/panel/racetimer.qc:65
+#, c-format
+msgid "Intermediate %d"
+msgstr ""
+
+#: qcsrc/client/hud/panel/racetimer.qc:132
+msgid "^1Intermediate 1 (+15.42)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/racetimer.qc:135
+#: qcsrc/client/hud/panel/racetimer.qc:177
+#: qcsrc/client/hud/panel/racetimer.qc:227
+#, c-format
+msgid "^1PENALTY: %.1f (%s)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/racetimer.qc:229
+#, c-format
+msgid "^2PENALTY: %.1f (%s)"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:78
+msgid "SCO^bckills"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:79
+msgid "SCO^bctime"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:80
+msgid "SCO^caps"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:81
+msgid "SCO^captime"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:82
+msgid "SCO^deaths"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:83
+msgid "SCO^destroyed"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:84
+msgid "SCO^damage"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:85
+msgid "SCO^dmgtaken"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:86
+msgid "SCO^drops"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:87
+msgid "SCO^faults"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:88
+msgid "SCO^fckills"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:89
+msgid "SCO^goals"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:90
+msgid "SCO^kckills"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:91
+msgid "SCO^kdratio"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:92
+msgid "SCO^k/d"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:93
+msgid "SCO^kdr"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:94
+msgid "SCO^kills"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:95
+msgid "SCO^laps"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:96
+msgid "SCO^lives"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:97
+msgid "SCO^losses"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:98
+msgid "SCO^name"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:99
+msgid "SCO^sum"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:100
+msgid "SCO^nick"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:101
+msgid "SCO^objectives"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:102
+msgid "SCO^pickups"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:103
+msgid "SCO^ping"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:104
+msgid "SCO^pl"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:105
+msgid "SCO^pushes"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:106
+msgid "SCO^rank"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:107
+msgid "SCO^returns"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:108
+msgid "SCO^revivals"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:109
+msgid "SCO^rounds won"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:110
+msgid "SCO^score"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:111
+msgid "SCO^suicides"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:112
+msgid "SCO^takes"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:113
+msgid "SCO^ticks"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:295
+msgid ""
+"You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
+msgstr ""
+"Anda boleh mengubah papan markah menggunakan perintah "
+"^2scoreboard_columns_set .\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:296
+msgid "^3|---------------------------------------------------------------|\n"
+msgstr "^3|---------------------------------------------------------------|\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:297
+msgid "Usage:\n"
+msgstr "Kegunaan:\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:298
+msgid "^2scoreboard_columns_set default\n"
+msgstr "^2scoreboard_columns_set default\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:299
+msgid "^2scoreboard_columns_set ^7field1 field2 ...\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:300
+msgid "The following field names are recognized (case insensitive):\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:301
+msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:304
+msgid "^3name^7 or ^3nick^7             Name of a player\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:305
+msgid "^3ping^7                     Ping time\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:306
+msgid "^3pl^7                       Packet loss\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:307
+msgid "^3elo^7                      Player ELO\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:308
+msgid "^3kills^7                    Number of kills\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:309
+msgid "^3deaths^7                   Number of deaths\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:310
+msgid "^3suicides^7                 Number of suicides\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:311
+msgid "^3frags^7                    kills - suicides\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:312
+msgid "^3kd^7                       The kill-death ratio\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:313
+msgid "^3dmg^7                      The total damage done\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:314
+msgid "^3dmgtaken^7                 The total damage taken\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:315
+msgid "^3sum^7                      frags - deaths\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:316
+msgid ""
+"^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was "
+"captured\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:317
+msgid ""
+"^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a "
+"ball (Keepaway) was picked up\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:318
+msgid "^3captime^7                  Time of fastest cap (CTF)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:319
+msgid "^3fckills^7                  Number of flag carrier kills\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:320
+msgid "^3returns^7                  Number of flag returns\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:321
+msgid "^3drops^7                    Number of flag drops\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:322
+msgid "^3lives^7                    Number of lives (LMS)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:323
+msgid "^3rank^7                     Player rank\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:324
+msgid "^3pushes^7                   Number of players pushed into void\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:325
+msgid ""
+"^3destroyed^7                Number of keys destroyed by pushing them into "
+"void\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:326
+msgid "^3kckills^7                  Number of keys carrier kills\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:327
+msgid "^3losses^7                   Number of times a key was lost\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:328
+msgid "^3laps^7                     Number of laps finished (race/cts)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:329
+msgid "^3time^7                     Total time raced (race/cts)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:330
+msgid "^3fastest^7                  Time of fastest lap (race/cts)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:331
+msgid "^3ticks^7                    Number of ticks (DOM)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:332
+msgid "^3takes^7                    Number of domination points taken (DOM)\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:333
+msgid "^3bckills^7                  Number of ball carrier kills\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:334
+msgid ""
+"^3bctime^7                   Total amount of time holding the ball in "
+"Keepaway\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:335
+msgid "^3score^7                    Total score\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:338
+msgid ""
+"Before a field you can put a + or - sign, then a comma separated list\n"
+"of game types, then a slash, to make the field show up only in these\n"
+"or in all but these game types. You can also specify 'all' as a\n"
+"field to show all fields available for the current game mode.\n"
+"\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:343
+msgid ""
+"The special game type names 'teams' and 'noteams' can be used to\n"
+"include/exclude ALL teams/noteams game modes.\n"
+"\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:346
+msgid "Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:347
+msgid ""
+"will display name, ping and pl aligned to the left, and the fields\n"
+"right of the vertical bar aligned to the right.\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:349
+msgid ""
+"'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+"other gamemodes except DM.\n"
+msgstr ""
+
+#: qcsrc/client/hud/panel/scoreboard.qc:611
+#: qcsrc/client/hud/panel/scoreboard.qc:618
+#: qcsrc/client/hud/panel/scoreboard.qc:670
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:86
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:87
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:208
+msgid "N/A"
+msgstr "Tiada"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1156
+#, c-format
+msgid "Accuracy stats (average %d%%)"
+msgstr "Statistik ketepatan (puratanya %d%%)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1295
+msgid "Map stats:"
+msgstr "Statistik peta:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1325
+msgid "Monsters killed:"
+msgstr "Raksasa dibunuh:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1332
+msgid "Secrets found:"
+msgstr "Rahsia dijumpai:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1354
+msgid "Capture time rankings"
+msgstr "Kedudukan masa tangkapan"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1354
+msgid "Rankings"
+msgstr "Kedudukan"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1519
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
+msgid "Scoreboard"
+msgstr "Papan markah"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1584
+#, c-format
+msgid "Speed award: %d%s ^7(%s^7)"
+msgstr "Anugerah kelajuan: %d%s ^7(%s^7)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1588
+#, c-format
+msgid "All-time fastest: %d%s ^7(%s^7)"
+msgstr "Terlaju sepanjang masa: %d%s ^7(%s^7)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1604
+#, c-format
+msgid "Spectators"
+msgstr "Penonton"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1619
+#, c-format
+msgid "playing ^3%s^7 on ^2%s^7"
+msgstr "bermain ^3%s^7 di ^2%s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1626
+#: qcsrc/client/hud/panel/scoreboard.qc:1631
+#, c-format
+msgid " for up to ^1%1.0f minutes^7"
+msgstr " sehingga ^1%1.0f minit^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1635
+#: qcsrc/client/hud/panel/scoreboard.qc:1654
+msgid " or"
+msgstr "atau"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1638
+#: qcsrc/client/hud/panel/scoreboard.qc:1645
+#, c-format
+msgid " until ^3%s %s^7"
+msgstr " sehingga ^3%s %s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1639
+#: qcsrc/client/hud/panel/scoreboard.qc:1646
+#: qcsrc/client/hud/panel/scoreboard.qc:1658
+#: qcsrc/client/hud/panel/scoreboard.qc:1665
+msgid "SCO^points"
+msgstr "SCO^mata"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1640
+#: qcsrc/client/hud/panel/scoreboard.qc:1647
+#: qcsrc/client/hud/panel/scoreboard.qc:1659
+#: qcsrc/client/hud/panel/scoreboard.qc:1666
+msgid "SCO^is beaten"
+msgstr "SCO^dikalahkan"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1657
+#: qcsrc/client/hud/panel/scoreboard.qc:1664
+#, c-format
+msgid " until a lead of ^3%s %s^7"
+msgstr " sehingga pimpinan ^3%s %s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1688
+#, c-format
+msgid "^1Respawning in ^3%s^1..."
+msgstr "^1Lahir semula dalam ^3%s^1..."
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1698
+#, c-format
+msgid "You are dead, wait ^3%s^7 before respawning"
+msgstr "Anda dah mati, tunggu ^3%s^7 sebelum lahir semula"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1707
+#, c-format
+msgid "You are dead, press ^2%s^7 to respawn"
+msgstr "Anda dah mati, tekan ^2%s^7 untuk lahir semula"
+
+#: qcsrc/client/hud/panel/vote.qc:24
+msgid "^1You must answer before entering hud configure mode\n"
+msgstr "^1Anda mesti jawab sebelum memasuki mod susunan hud\n"
+
+#: qcsrc/client/hud/panel/vote.qc:29
+msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
+msgstr "^2Nama ^7menggantikan \"^1Pemain tidak bernama^7\" dalam statistik"
+
+#: qcsrc/client/hud/panel/vote.qc:115
+msgid "A vote has been called for:"
+msgstr ""
+
+#: qcsrc/client/hud/panel/vote.qc:117
+msgid "Allow servers to store and display your name?"
+msgstr "Benarkan pelayan untuk menyimpan dan memaparkan nama anda?"
+
+#: qcsrc/client/hud/panel/vote.qc:121
+msgid "^1Configure the HUD"
+msgstr "^1Susun HUD"
+
+#: qcsrc/client/hud/panel/vote.qc:125 qcsrc/menu/xonotic/dialog_firstrun.qc:82
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:18
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:18
+#: qcsrc/menu/xonotic/dialog_quit.qc:14
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:26
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:16
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:15
+msgid "Yes"
+msgstr "Ya"
+
+#: qcsrc/client/hud/panel/vote.qc:127 qcsrc/menu/xonotic/dialog_firstrun.qc:83
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:21
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:21
+#: qcsrc/menu/xonotic/dialog_quit.qc:16
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:29
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:17
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:17
+msgid "No"
+msgstr "Tidak"
+
+#: qcsrc/client/hud/panel/weapons.qc:530
+msgid "Out of ammo"
+msgstr "Kehabisan peluru"
+
+#: qcsrc/client/hud/panel/weapons.qc:534
+msgid "Don't have"
+msgstr "Tiada"
+
+#: qcsrc/client/hud/panel/weapons.qc:538
+msgid "Unavailable"
+msgstr "Tak wujud"
+
+#: qcsrc/client/main.qc:1014
+msgid " qu/s"
+msgstr "qu/s"
+
+#: qcsrc/client/main.qc:1016
+msgid " m/s"
+msgstr "m/s"
+
+#: qcsrc/client/main.qc:1018
+msgid " km/h"
+msgstr "km/j"
+
+#: qcsrc/client/main.qc:1020
+msgid " mph"
+msgstr "b/j"
+
+#: qcsrc/client/main.qc:1022
+msgid " knots"
+msgstr "knot"
+
+#: qcsrc/client/main.qc:1264
+#, c-format
+msgid "%s (not bound)"
+msgstr ""
+
+#: qcsrc/client/mapvoting.qc:49
+msgid " (1 vote)"
+msgstr "(1 undi)"
+
+#: qcsrc/client/mapvoting.qc:51
+#, c-format
+msgid " (%d votes)"
+msgstr " (%d undi)"
+
+#: qcsrc/client/mapvoting.qc:271
+msgid "Don't care"
+msgstr "Tak kisah"
+
+#: qcsrc/client/mapvoting.qc:365
+msgid "Decide the gametype"
+msgstr "Tentukan jenis permainan"
+
+#: qcsrc/client/mapvoting.qc:365
+msgid "Vote for a map"
+msgstr "Undi peta"
+
+#: qcsrc/client/mapvoting.qc:382
+#, c-format
+msgid "%d seconds left"
+msgstr "Tinggal %d saat"
+
+#: qcsrc/client/mapvoting.qc:497
+msgid ""
+"mv_mapdownload: ^3You're not supposed to use this command on your own!\n"
+msgstr ""
+"mv_mapdownload: ^3Anda tidak patut guna perintah ini dengan sendirinya!\n"
+
+#: qcsrc/client/mapvoting.qc:507
+msgid "^1Error:^7 Couldn't find pak index.\n"
+msgstr ""
+
+#: qcsrc/client/mapvoting.qc:516
+msgid "Requesting preview...\n"
+msgstr "Meminta pratonton...\n"
+
+#: qcsrc/client/miscfunctions.qc:109
+msgid "Trying to remove a team which is not in the teamlist!"
+msgstr ""
+
+#: qcsrc/client/view.qc:1380
+msgid "Nade timer"
+msgstr ""
+
+#: qcsrc/client/view.qc:1385
+msgid "Capture progress"
+msgstr ""
+
+#: qcsrc/client/view.qc:1390
+msgid "Revival progress"
+msgstr ""
+
+#: qcsrc/common/command/generic.qc:157
+msgid "error creating curl handle\n"
+msgstr ""
+
+#: qcsrc/common/command/generic.qc:403
+msgid "Notification restart command only works with cl_cmd and sv_cmd.\n"
+msgstr ""
+
+#: qcsrc/common/gamemodes/gamemode/nexball/weapon.qh:7
+msgid "Ball Stealer"
+msgstr ""
+
+#: qcsrc/common/items/item/armor.qh:111
+msgid "Big armor"
+msgstr ""
+
+#: qcsrc/common/items/item/armor.qh:147
+msgid "Mega armor"
+msgstr ""
+
+#: qcsrc/common/items/item/health.qh:111
+msgid "Big health"
+msgstr ""
+
+#: qcsrc/common/items/item/health.qh:147
+msgid "Mega health"
+msgstr ""
+
+#: qcsrc/common/items/item/jetpack.qh:35
+msgid "Jet Pack"
+msgstr ""
+
+#: qcsrc/common/items/item/jetpack.qh:82
+msgid "Fuel regen"
+msgstr ""
+
+#: qcsrc/common/items/item/powerup.qh:44
+msgid "Strength"
+msgstr ""
+
+#: qcsrc/common/items/item/powerup.qh:76
+msgid "Shield"
+msgstr ""
+
+#: qcsrc/common/mapinfo.qc:639
+#, no-c-format
+msgid "@!#%'n Tuba Throwing"
+msgstr ""
+
+#: qcsrc/common/mapinfo.qh:99
+msgid "Deathmatch"
+msgstr "Kalah Mati"
+
+#: qcsrc/common/mapinfo.qh:99
+msgid "Score as many frags as you can"
+msgstr "Dominasi kawasan sebanyak mana yang anda boleh"
+
+#: qcsrc/common/mapinfo.qh:111
+msgid "Last Man Standing"
+msgstr "Orang Terakhir Berdiri"
+
+#: qcsrc/common/mapinfo.qh:111
+msgid "Survive and kill until the enemies have no lives left"
+msgstr "Kekal hidup dan bunuh semua musuh sehingga mereka kehabisan nyawa"
+
+#: qcsrc/common/mapinfo.qh:126
+msgid "Race"
+msgstr "Lumba"
+
+#: qcsrc/common/mapinfo.qh:126
+msgid "Race against other players to the finish line"
+msgstr "Berlumba dengan pemain lain ke garisan penamat"
+
+#: qcsrc/common/mapinfo.qh:160
+msgid "Race CTS"
+msgstr "Lumba CTS"
+
+#: qcsrc/common/mapinfo.qh:160
+msgid "Race for fastest time."
+msgstr "Lumba untuk masa terpantas."
+
+#: qcsrc/common/mapinfo.qh:184
+msgid "Help your team score the most frags against the enemy team"
+msgstr ""
+"Bantu pasukan anda untuk mendominasi kebanyakan kawasan berbanding pasukan "
+"lawan"
+
+#: qcsrc/common/mapinfo.qh:184
+msgid "Team Deathmatch"
+msgstr "Kalah Mati Berpasukan"
+
+#: qcsrc/common/mapinfo.qh:220
+msgid "Capture the Flag"
+msgstr "Curi Bendera"
+
+#: qcsrc/common/mapinfo.qh:220
+msgid ""
+"Find and bring the enemy flag to your base to capture it, defend your base "
+"from the other team"
+msgstr ""
+"Cari dan bawa balik bendera musuh ke tapak anda, pertahankan tapak anda "
+"daripada pasukan lain"
+
+#: qcsrc/common/mapinfo.qh:249
+msgid "Clan Arena"
+msgstr "Arena Suku"
+
+#: qcsrc/common/mapinfo.qh:249
+msgid "Kill all enemy teammates to win the round"
+msgstr "Bunuh semua ahli pasukan musuh untuk memenangi pusingan tersebut"
+
+#: qcsrc/common/mapinfo.qh:287
+msgid "Capture and defend all the control points to win"
+msgstr "Ambil alih dan pertahankan semua titik kawalan untuk menang"
+
+#: qcsrc/common/mapinfo.qh:287
+msgid "Domination"
+msgstr "Dominasi"
+
+#: qcsrc/common/mapinfo.qh:319
+msgid "Gather all the keys to win the round"
+msgstr "Kumpul semua kunci untuk memenangi pusingan"
+
+#: qcsrc/common/mapinfo.qh:319
+msgid "Key Hunt"
+msgstr "Pencarian Kunci"
+
+#: qcsrc/common/mapinfo.qh:353
+msgid "Assault"
+msgstr "Serangan"
+
+#: qcsrc/common/mapinfo.qh:353
+msgid ""
+"Destroy obstacles to find and destroy the enemy power core before time runs "
+"out"
+msgstr ""
+"Musnahkan halangan untuk mencari dan memusnahkan teras kuasa musuh sebelum "
+"masa tamat"
+
+#: qcsrc/common/mapinfo.qh:371
+msgid "Capture control points to reach and destroy the enemy generator"
+msgstr ""
+"Ambil alih titik kawalan untuk sampai ke dan musnahkan penjana kuasa musuh"
+
+#: qcsrc/common/mapinfo.qh:371
+msgid "Onslaught"
+msgstr "Serangan Hebat"
+
+#: qcsrc/common/mapinfo.qh:387
+msgid "Nexball"
+msgstr "Bola Nex"
+
+#: qcsrc/common/mapinfo.qh:387
+msgid "Shoot and kick the ball into the enemies goal, keep your goal clean"
+msgstr "Tembak dan tendang bola ke dalam gol musuh, biar kosong gol anda"
+
+#: qcsrc/common/mapinfo.qh:408
+msgid "Freeze Tag"
+msgstr "Aci Beku"
+
+#: qcsrc/common/mapinfo.qh:408
+msgid ""
+"Kill enemies to freeze them, stand next to frozen teammates to revive them; "
+"freeze all enemies to win"
+msgstr ""
+"Bunuh musuh untuk bekukan mereka, berdiri dekat dengan rakan pasukan beku "
+"untuk mencairkan mereka; bekukan semua musuh untuk menang"
+
+#: qcsrc/common/mapinfo.qh:446
+msgid "Hold the ball to get points for kills"
+msgstr "Tangkap bola untuk mendapat mata pembunuhan"
+
+#: qcsrc/common/mapinfo.qh:446
+msgid "Keepaway"
+msgstr "Bola Elak"
+
+#: qcsrc/common/mapinfo.qh:461
+msgid "Invasion"
+msgstr "Serangan"
+
+#: qcsrc/common/mapinfo.qh:461
+msgid "Survive against waves of monsters"
+msgstr "Cuba untuk hidup dengan gelombang kelahiran raksasa"
+
+#: qcsrc/common/minigames/cl_minigames.qc:383
+msgid "It's your turn"
+msgstr "Giliran anda"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:331
+#: qcsrc/menu/xonotic/dialog_quit.qh:6
+msgid "Quit"
+msgstr "Berhenti Main"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:336
+msgid "Invite"
+msgstr "Ajak Rakan"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:378
+msgid "Current Game"
+msgstr "Permainan Semasa"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:403
+msgid "Exit Menu"
+msgstr "Keluar Menu"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:415
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:16
+msgid "Create"
+msgstr "Cipta"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:418
+msgid "Join"
+msgstr "Sertai"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:489
+msgid "Minigames"
+msgstr "Permainan Mini"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1168
+msgid "Better luck next time!"
+msgstr "Cuba lagi akan datang!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1172
+msgid "Tubular! Press \"Next Level\" to continue!"
+msgstr "Macam tiub! Tekan \"Tahap Seterusnya\" untuk teruskan!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1174
+msgid "Wicked! Press \"Next Level\" to continue!"
+msgstr "Jahatnya! Tekan \"Tahap Seterusnya\" untuk teruskan!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1177
+msgid "Press the space bar to change your currently selected tile"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/bd.qc:1180
+msgid "Push the boulders onto the targets"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/bd.qc:1404
+msgid "Next Level"
+msgstr "Tahap Seterusnya"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1405
+msgid "Restart"
+msgstr "Mulakan Semula"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1406
+msgid "Editor"
+msgstr "Editor"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1407
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:37
+msgid "Save"
+msgstr "Simpan"
+
+#: qcsrc/common/minigames/minigame/c4.qc:373
+#: qcsrc/common/minigames/minigame/pp.qc:438
+#: qcsrc/common/minigames/minigame/ttt.qc:319
+msgid "Draw"
+msgstr "Lukis"
+
+#: qcsrc/common/minigames/minigame/c4.qc:378
+#: qcsrc/common/minigames/minigame/nmm.qc:601
+msgid "You lost the game!"
+msgstr "Anda kalah!"
+
+#: qcsrc/common/minigames/minigame/c4.qc:379
+#: qcsrc/common/minigames/minigame/nmm.qc:602
+msgid "You win!"
+msgstr "Anda menang!"
+
+#: qcsrc/common/minigames/minigame/c4.qc:383
+#: qcsrc/common/minigames/minigame/nmm.qc:606
+#: qcsrc/common/minigames/minigame/pp.qc:455
+#: qcsrc/common/minigames/minigame/ttt.qc:336
+msgid "Wait for your opponent to make their move"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/c4.qc:386
+#: qcsrc/common/minigames/minigame/nmm.qc:608
+#: qcsrc/common/minigames/minigame/pp.qc:458
+#: qcsrc/common/minigames/minigame/ttt.qc:339
+msgid "Click on the game board to place your piece"
+msgstr "Klik pada papan permainan untuk meletakkan kepingan anda"
+
+#: qcsrc/common/minigames/minigame/nmm.qc:610
+msgid ""
+"You can select one of your pieces to move it in one of the surrounding places"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/nmm.qc:612
+msgid "You can select one of your pieces to move it anywhere on the board"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/nmm.qc:614
+msgid "You can take one of the opponent's pieces"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pong.qc:570
+#: qcsrc/common/minigames/minigame/ttt.qc:299
+msgid "AI"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pong.qc:587
+msgid "Press ^1Start Match^7 to start the match with the current players"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pong.qc:651
+msgid "Start Match"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pong.qc:652
+msgid "Add AI player"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pong.qc:653
+msgid "Remove AI player"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pp.qc:443
+#: qcsrc/common/minigames/minigame/ttt.qc:324
+msgid ""
+"You lost the game!\n"
+"Select \"^1Next Match^7\" on the menu for a rematch!"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pp.qc:444
+#: qcsrc/common/minigames/minigame/ttt.qc:325
+msgid ""
+"You win!\n"
+"Select \"^1Next Match^7\" on the menu to start a new match!"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pp.qc:450
+#: qcsrc/common/minigames/minigame/ttt.qc:331
+msgid "Select \"^1Next Match^7\" on the menu to start a new match!"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pp.qc:451
+#: qcsrc/common/minigames/minigame/ttt.qc:332
+msgid "Wait for your opponent to confirm the rematch"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/pp.qc:582
+#: qcsrc/common/minigames/minigame/ttt.qc:665
+msgid "Next Match"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/ps.qc:478
+#, c-format
+msgid "Pieces left: %s"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/ps.qc:488
+msgid "No more valid moves"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/ps.qc:491
+msgid "Well done, you win!"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/ps.qc:494
+msgid "Jump a piece over another to capture it"
+msgstr ""
+
+#: qcsrc/common/minigames/minigame/ttt.qc:666
+msgid "Single Player"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/mage.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:18
+msgid "Mage"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/mage.qh:29
+msgid "Mage spike"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/shambler.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:17
+msgid "Shambler"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/spider.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:16
+msgid "Spider"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/spider.qh:28
+msgid "Spider attack"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/wyvern.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:19
+msgid "Wyvern"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/wyvern.qh:28
+msgid "Wyvern attack"
+msgstr ""
+
+#: qcsrc/common/monsters/monster/zombie.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:15
+msgid "Zombie"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:15
+msgid "Ammo"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:24
+msgid "Resistance"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:33
+#: qcsrc/common/mutators/mutator/instagib/items.qh:94
+msgid "Speed"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:43
+msgid "Medic"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:54
+msgid "Bash"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:62
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:85
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:177
+msgid "Vampire"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:70
+msgid "Disability"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:78
+msgid "Vengeance"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:86
+msgid "Jump"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:95
+msgid "Invisible"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:104
+msgid "Inferno"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:112
+msgid "Swapper"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:120
+msgid "Magnet"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:128
+msgid "Luck"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:136
+msgid "Flight"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/buffs/buffs.qh:7
+msgid "Buff"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
+msgid "Damage text"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:18
+msgid "Draw damage numbers"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:20
+msgid "Font size minimum:"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:25
+msgid "Font size maximum:"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:30
+msgid "Accumulate range:"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:35
+msgid "Lifetime:"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:40
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:50
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:55
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:102
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:60
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:109
+#: qcsrc/menu/xonotic/util.qc:775
+msgid "Color:"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
+msgid "Draw damage numbers for friendly fire"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/instagib/items.qh:56
+msgid "Extra life"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/instagib/items.qh:75
+msgid "Invisibility"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:18
+msgid "Napalm grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:26
+msgid "Ice grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:34
+msgid "Translocate grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:42
+msgid "Spawn grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:50
+msgid "Heal grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:58
+msgid "Monster grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:66
+msgid "Entrap grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/nades/nades.qh:32
+msgid "Grenade"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
+msgid "Heavy Machine Gun"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/overkill/rpc.qh:17
+msgid "Rocket Propelled Chainsaw"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:3
+msgid "Waypoint"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:4
+msgid "Help me!"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:5
+msgid "Here"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:6
+msgid "DANGER"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:8
+msgid "Frozen!"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:10
+msgid "Item"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:12
+msgid "Checkpoint"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:13
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
+msgid "Finish"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:14
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:15
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
+msgid "Start"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:17
+msgid "Defend"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:18
+msgid "Destroy"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:19
+msgid "Push"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:21
+msgid "Flag carrier"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:22
+msgid "Enemy carrier"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:23
+msgid "Dropped flag"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:24
+msgid "White base"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:25
+msgid "Red base"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:26
+msgid "Blue base"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:27
+msgid "Yellow base"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:28
+msgid "Pink base"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:29
+msgid "Return flag here"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:31
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:32
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:33
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:34
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:35
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:51
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:52
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:53
+msgid "Control point"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:37
+msgid "Dropped key"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:38
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:40
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:41
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:42
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:43
+msgid "Key carrier"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:39
+msgid "Run here"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:45
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:48
+msgid "Ball"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:46
+msgid "Ball carrier"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:49
+msgid "Goal"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:54
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:55
+msgid "Generator"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:57
+msgid "Weapon"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:59
+msgid "Monster"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:61
+msgid "Vehicle"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:62
+msgid "Intruder!"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:64
+msgid "Tagged"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:651
+#: qcsrc/common/turrets/cl_turrets.qc:120
+msgid "Spam"
+msgstr ""
+
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:655
+#, c-format
+msgid "%s needing help!"
+msgstr ""
+
+#: qcsrc/common/net_notice.qc:87
+msgid "^1Server notices:"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:239
+msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:241
+#, c-format
+msgid "^BG%s^BG captured the ^TC^TT^BG flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:242
+#, c-format
+msgid ""
+"^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG"
+"%s^BG's previous record of ^F2%s^BG seconds"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:243
+#, c-format
+msgid "^BG%s^BG captured the flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:244
+#, c-format
+msgid "^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:245
+#, c-format
+msgid ""
+"^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break "
+"^BG%s^BG's previous record of ^F1%s^BG seconds"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:246
+msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:247
+msgid "^BGThe flag was returned by its owner"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:248
+msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:249
+msgid "^BGThe flag was destroyed and returned to base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:250
+msgid "^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:251
+msgid "^BGThe flag was dropped in the base and returned itself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:252
+msgid ""
+"^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to "
+"base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:253
+msgid "^BGThe flag fell somewhere it couldn't be reached and returned to base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:254
+#, c-format
+msgid ""
+"^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned "
+"itself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:255
+#, c-format
+msgid ""
+"^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:256
+msgid "^BGThe ^TC^TT^BG flag has returned to the base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:257
+msgid "^BGThe flag has returned to the base"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:258
+#, c-format
+msgid "^BG%s^BG lost the ^TC^TT^BG flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:259
+#, c-format
+msgid "^BG%s^BG lost the flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:260
+#, c-format
+msgid "^BG%s^BG got the ^TC^TT^BG flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:261
+#, c-format
+msgid "^BG%s^BG got the flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:262
+#: qcsrc/common/notifications/all.inc:263
+#, c-format
+msgid "^BG%s^BG returned the ^TC^TT^BG flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:265
+#: qcsrc/common/notifications/all.inc:553
+#, c-format
+msgid "^F2Throwing coin... Result: %s^F2!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:267
+msgid "^BGYou don't have any fuel for the ^F1Jetpack"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:269
+msgid "^F2You lack a UID, superspec options will not be saved/restored"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:271
+msgid "^F1Round already started, you will join the game in the next round"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:272
+msgid "^F2You will spectate in the next round"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:274
+#, c-format
+msgid "^BG%s%s^K1 was killed by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:274
+#, c-format
+msgid "^BG%s%s^K1 was scored against by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:275
+#, c-format
+msgid "^BG%s%s^K1 was unfairly eliminated by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:276
+#, c-format
+msgid "^BG%s%s^K1 was drowned by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:277
+#, c-format
+msgid "^BG%s%s^K1 was grounded by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:278
+#, c-format
+msgid "^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:278
+#, c-format
+msgid "^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:279
+#, c-format
+msgid "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:280
+#, c-format
+msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:281
+#, c-format
+msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:282
+#, c-format
+msgid "^BG%s%s^K1 got too close to a napalm explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:282
+#, c-format
+msgid "^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:283
+#, c-format
+msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:284
+#, c-format
+msgid "^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:285
+#, c-format
+msgid "^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:286
+#, c-format
+msgid "^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:287
+#, c-format
+msgid "^BG%s%s^K1 was slimed by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:288
+#, c-format
+msgid "^BG%s%s^K1 was preserved by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:289
+#, c-format
+msgid "^BG%s%s^K1 tried to occupy ^BG%s^K1's teleport destination space%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:289
+#, c-format
+msgid "^BG%s%s^K1 was telefragged by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:290
+#, c-format
+msgid "^BG%s%s^K1 died in an accident with ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:291
+#, c-format
+msgid ""
+"^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Bumblebee exploded%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:292
+#, c-format
+msgid "^BG%s%s^K1 saw the pretty lights of ^BG%s^K1's Bumblebee gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:293
+#, c-format
+msgid "^BG%s%s^K1 was crushed by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:294
+#, c-format
+msgid "^BG%s%s^K1 was cluster bombed by ^BG%s^K1's Raptor%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:295
+#, c-format
+msgid "^BG%s%s^K1 couldn't resist ^BG%s^K1's purple blobs%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:296
+#, c-format
+msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Raptor exploded%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:297
+#, c-format
+msgid ""
+"^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Spiderbot exploded%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:298
+#, c-format
+msgid "^BG%s%s^K1 got shredded by ^BG%s^K1's Spiderbot%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:299
+#, c-format
+msgid "^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:300
+#, c-format
+msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:301
+#, c-format
+msgid "^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:302
+#, c-format
+msgid "^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:303
+#, c-format
+msgid "^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:305
+#, c-format
+msgid "^BG%s^K1 was moved into the %s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:306
+#, c-format
+msgid "^BG%s^K1 became enemies with the Lord of Teamplay%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:307
+#, c-format
+msgid "^BG%s^K1 thought they found a nice camping ground%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:308
+#, c-format
+msgid "^BG%s^K1 unfairly eliminated themself%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:310
+#, c-format
+msgid "^BG%s^K1 couldn't catch their breath%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:310
+#, c-format
+msgid "^BG%s^K1 was in the water for too long%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:311
+#, c-format
+msgid "^BG%s^K1 hit the ground with a bit too much force%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:311
+#, c-format
+msgid "^BG%s^K1 hit the ground with a crunch%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:312
+#, c-format
+msgid "^BG%s^K1 became a bit too crispy%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:312
+#, c-format
+msgid "^BG%s^K1 felt a little hot%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:313
+#, c-format
+msgid "^BG%s^K1 died%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:314
+#, c-format
+msgid "^BG%s^K1 found a hot place%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:314
+#, c-format
+msgid "^BG%s^K1 turned into hot slag%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:315
+#, c-format
+msgid "^BG%s^K1 was exploded by a Mage%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:316
+#, c-format
+msgid "^BG%s^K1's innards became outwards by a Shambler%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:317
+#, c-format
+msgid "^BG%s^K1 was smashed by a Shambler%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:318
+#, c-format
+msgid "^BG%s^K1 was zapped to death by a Shambler%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:319
+#, c-format
+msgid "^BG%s^K1 was bitten by a Spider%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:320
+#, c-format
+msgid "^BG%s^K1 was fireballed by a Wyvern%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:321
+#, c-format
+msgid "^BG%s^K1 joins the Zombies%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:322
+#, c-format
+msgid "^BG%s^K1 was given kung fu lessons by a Zombie%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:323
+#: qcsrc/common/notifications/all.inc:325
+#, c-format
+msgid "^BG%s^K1 mastered the art of self-nading%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:324
+#, c-format
+msgid ""
+"^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:324
+#, c-format
+msgid "^BG%s^K1 was burned to death by their own Napalm Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:326
+#, c-format
+msgid "^BG%s^K1 felt a little chilly%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:326
+#, c-format
+msgid "^BG%s^K1 was frozen to death by their own Ice Nade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:327
+#, c-format
+msgid "^BG%s^K1's Healing Nade didn't quite heal them%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:328
+#, c-format
+msgid "^BG%s^K1 died%s%s. What's the point of living without ammo?"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:328
+#, c-format
+msgid "^BG%s^K1 ran out of ammo%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:329
+#, c-format
+msgid "^BG%s^K1 rotted away%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:330
+#, c-format
+msgid "^BG%s^K1 became a shooting star%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:331
+#, c-format
+msgid "^BG%s^K1 was slimed%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:332
+#, c-format
+msgid "^BG%s^K1 couldn't take it anymore%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:333
+#, c-format
+msgid "^BG%s^K1 is now preserved for centuries to come%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:334
+#, c-format
+msgid "^BG%s^K1 switched to the %s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:335
+#, c-format
+msgid "^BG%s^K1 died in an accident%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:336
+#, c-format
+msgid "^BG%s^K1 ran into a turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:337
+#, c-format
+msgid "^BG%s^K1 was blasted away by an eWheel turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:338
+#, c-format
+msgid "^BG%s^K1 got caught up in the FLAC turret fire%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:339
+#, c-format
+msgid "^BG%s^K1 was blasted away by a Hellion turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:340
+#, c-format
+msgid "^BG%s^K1 could not hide from the Hunter turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:341
+#, c-format
+msgid "^BG%s^K1 was riddled full of holes by a Machinegun turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:342
+#, c-format
+msgid "^BG%s^K1 got turned into smoldering gibs by an MLRS turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:343
+#, c-format
+msgid "^BG%s^K1 was phased out by a turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:344
+#, c-format
+msgid "^BG%s^K1 got served some superheated plasma from a turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:345
+#, c-format
+msgid "^BG%s^K1 was electrocuted by a Tesla turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:346
+#, c-format
+msgid "^BG%s^K1 got served a lead enrichment by a Walker turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:347
+#, c-format
+msgid "^BG%s^K1 was impaled by a Walker turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:348
+#, c-format
+msgid "^BG%s^K1 was blasted away by a Walker turret%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:349
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Bumblebee explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:350
+#, c-format
+msgid "^BG%s^K1 was crushed by a vehicle%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:351
+#, c-format
+msgid "^BG%s^K1 was caught in a Raptor cluster bomb%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:352
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Raptor explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:353
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Spiderbot explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:354
+#, c-format
+msgid "^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:355
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Racer explosion%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:356
+#, c-format
+msgid "^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:359
+#, c-format
+msgid "^BG%s^K1 was betrayed by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:361
+#, c-format
+msgid "^BG%s^BG%s^BG (%s %s every %s seconds)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:363
+#, c-format
+msgid "^BG%s^K1 was frozen by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:364
+#, c-format
+msgid "^BG%s^K3 was revived by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:365
+#, c-format
+msgid "^BG%s^K3 was revived by falling"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:366
+#, c-format
+msgid "^BG%s^K3 was revived by their Nade explosion"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:367
+#, c-format
+msgid "^BG%s^K3 was automatically revived after %s second(s)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:368
+#, c-format
+msgid "^BG%s^K1 froze themself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:370
+#: qcsrc/common/notifications/all.inc:684
+msgid "^TC^TT^BG team wins the round"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:371
+#: qcsrc/common/notifications/all.inc:685
+#, c-format
+msgid "^BG%s^BG wins the round"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:372
+#: qcsrc/common/notifications/all.inc:548
+msgid "^BGRound tied"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:373
+#: qcsrc/common/notifications/all.inc:549
+msgid "^BGRound over, there's no winner"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:375
+#, c-format
+msgid "^BGGodmode saved you %s units of damage, cheater!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:377
+#, c-format
+msgid "^BG%s^BG got the %s^BG buff!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:378
+#, c-format
+msgid "^BG%s^BG lost the %s^BG buff!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:379
+#: qcsrc/common/notifications/all.inc:692
+#, c-format
+msgid "^BGYou dropped the %s^BG buff!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:380
+#: qcsrc/common/notifications/all.inc:693
+#, c-format
+msgid "^BGYou got the %s^BG buff!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:382
+#: qcsrc/common/notifications/all.inc:696
+#, c-format
+msgid "^BGYou do not have the ^F1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:383
+#: qcsrc/common/notifications/all.inc:697
+#, c-format
+msgid "^BGYou dropped the ^F1%s^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:384
+#: qcsrc/common/notifications/all.inc:698
+#, c-format
+msgid "^BGYou got the ^F1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:385
+#: qcsrc/common/notifications/all.inc:699
+#, c-format
+msgid "^BGYou don't have enough ammo for the ^F1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:386
+#: qcsrc/common/notifications/all.inc:700
+#, c-format
+msgid "^F1%s %s^BG is unable to fire, but its ^F1%s^BG can"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:387
+#: qcsrc/common/notifications/all.inc:701
+#, c-format
+msgid "^F1%s^BG is ^F4not available^BG on this map"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:389
+#, c-format
+msgid "^BG%s^BG is connecting..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:390
+#, c-format
+msgid "^BG%s^F3 connected"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:391
+#, c-format
+msgid "^BG%s^F3 connected and joined the ^TC^TT team"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:392
+#, c-format
+msgid "^BG%s^F3 is now playing"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:393
+#, c-format
+msgid "^BG%s^F3 is now playing on the ^TC^TT team"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:395
+#: qcsrc/common/notifications/all.inc:706
+#, c-format
+msgid "^BG%s^BG has dropped the ball!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:396
+#: qcsrc/common/notifications/all.inc:707
+#, c-format
+msgid "^BG%s^BG has picked up the ball!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:398
+#, c-format
+msgid "^BG%s^BG captured the keys for the ^TC^TT team"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:399
+#, c-format
+msgid "^BG%s^BG dropped the ^TC^TT Key"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:400
+#, c-format
+msgid "^BG%s^BG lost the ^TC^TT Key"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:401
+#, c-format
+msgid "^BG%s^BG pushed %s^BG causing the ^TC^TT Key ^BGdestruction"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:402
+#, c-format
+msgid "^BG%s^BG destroyed the ^TC^TT Key"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:403
+#, c-format
+msgid "^BG%s^BG picked up the ^TC^TT Key"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:405
+#, c-format
+msgid "^BG%s^F3 forfeited"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:406
+#, c-format
+msgid "^BG%s^F3 has no more lives left"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:408
+msgid "^BGMonsters are currently disabled"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:410
+msgid "^BGThe ^TC^TT^BG team held the ball for too long"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:412
+#, c-format
+msgid "^BG%s^BG captured %s^BG control point"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:413
+#, c-format
+msgid "^TC^TT^BG team %s^BG control point has been destroyed by %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:414
+msgid "^TC^TT^BG generator has been destroyed"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:415
+msgid "^TC^TT^BG generator spontaneously combusted due to overtime!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:417
+#, c-format
+msgid "^BG%s^K1 picked up Invisibility"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:418
+#, c-format
+msgid "^BG%s^K1 picked up Shield"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:419
+#, c-format
+msgid "^BG%s^K1 picked up Speed"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:420
+#, c-format
+msgid "^BG%s^K1 picked up Strength"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:422
+#, c-format
+msgid "^BG%s^F3 disconnected"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:423
+#, c-format
+msgid "^BG%s^F3 was kicked for idling"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:424
+msgid ""
+"^F2You were kicked from the server because you are a spectator and "
+"spectators aren't allowed at the moment."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:425
+#, c-format
+msgid "^BG%s^F3 is now spectating"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:427
+#, c-format
+msgid "^BG%s^BG has abandoned the race"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:428
+#, c-format
+msgid "^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:429
+#, c-format
+msgid "^BG%s^BG couldn't break the %s%s^BG place record of %s%s %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:430
+#, c-format
+msgid "^BG%s^BG has finished the race"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:431
+#, c-format
+msgid "^BG%s^BG broke %s^BG's %s%s^BG place record with %s%s %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:432
+#, c-format
+msgid "^BG%s^BG improved their %s%s^BG place record with %s%s %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:433
+#, c-format
+msgid ""
+"^BG%s^BG scored a new record with ^F2%s^BG, but unfortunately lacks a UID "
+"and will be lost."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:434
+#, c-format
+msgid ""
+"^BG%s^BG scored a new record with ^F2%s^BG, but is anonymous and will be "
+"lost."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:435
+#, c-format
+msgid "^BG%s^BG set the %s%s^BG place record with %s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:437
+#, c-format
+msgid ""
+"^F4You have been invited by ^BG%s^F4 to join their game of ^F2%s^F4 "
+"(^F1%s^F4)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:439
+msgid "^TC^TT ^BGteam scores!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:441
+#, c-format
+msgid ""
+"^F2You have to become a player within the next %s, otherwise you will be "
+"kicked, because spectating isn't allowed at this time!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:443
+#, c-format
+msgid "^BG%s^K1 picked up a Superweapon"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:445
+msgid "^BGYou cannot change to a larger team"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:446
+msgid "^BGYou are not allowed to change teams"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:448
+#, c-format
+msgid ""
+"^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have "
+"^F2Xonotic %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:449
+#, c-format
+msgid ""
+"^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:450
+#, c-format
+msgid ""
+"^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get "
+"the update from ^F3http://www.xonotic.org/^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:452
+#, c-format
+msgid "^F3SVQC Build information: ^F4%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:454
+#, c-format
+msgid ""
+"^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:455
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:456
+#, c-format
+msgid "^BG%s%s^K1 was electrocuted by ^BG%s^K1's Arc%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:457
+#, c-format
+msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Arc bolts%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:458
+#, c-format
+msgid "^BG%s%s^K1 was shot to death by ^BG%s^K1's Blaster%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:459
+#, c-format
+msgid "^BG%s^K1 shot themself to hell with their Blaster%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:460
+#, c-format
+msgid "^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:461
+#, c-format
+msgid "^BG%s^K1 felt the strong pull of their Crylink%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:462
+#, c-format
+msgid "^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:463
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:464
+#, c-format
+msgid "^BG%s^K1 blew themself up with their Devastator%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:465
+#, c-format
+msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:466
+#, c-format
+msgid "^BG%s%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:467
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Electro orb%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:468
+#, c-format
+msgid "^BG%s^K1 played with Electro bolts%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:469
+#, c-format
+msgid "^BG%s^K1 could not remember where they put their Electro orb%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:470
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's fireball%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:471
+#, c-format
+msgid "^BG%s%s^K1 got burnt by ^BG%s^K1's firemine%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:472
+#, c-format
+msgid "^BG%s^K1 should have used a smaller gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:473
+#, c-format
+msgid "^BG%s^K1 forgot about their firemine%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:474
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:475
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:476
+#, c-format
+msgid "^BG%s^K1 played with tiny Hagar rockets%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:477
+#, c-format
+msgid "^BG%s%s^K1 was cut down with ^BG%s^K1's HLAC%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:478
+#, c-format
+msgid "^BG%s^K1 got a little jumpy with their HLAC%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:479
+#, c-format
+msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Heavy Machine Gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:480
+#, c-format
+msgid "^BG%s%s^K1 was torn to bits by ^BG%s^K1's Heavy Machine Gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:481
+#, c-format
+msgid "^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:482
+#, c-format
+msgid ""
+"^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:483
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:484
+#, c-format
+msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:485
+#, c-format
+msgid "^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:486
+#: qcsrc/common/notifications/all.inc:790
+#, c-format
+msgid "^BGYou cannot place more than ^F2%s^BG mines at a time"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:487
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's mine%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:488
+#, c-format
+msgid "^BG%s^K1 forgot about their mine%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:489
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:490
+#, c-format
+msgid "^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:491
+#, c-format
+msgid "^BG%s^K1 didn't see their own Mortar grenade%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:492
+#, c-format
+msgid "^BG%s^K1 blew themself up with their own Mortar%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:493
+#, c-format
+msgid "^BG%s%s^K1 was sniped with a Rifle by ^BG%s^K1%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:494
+#, c-format
+msgid "^BG%s%s^K1 died in ^BG%s^K1's Rifle bullet hail%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:495
+#, c-format
+msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:496
+#, c-format
+msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:497
+#, c-format
+msgid "^BG%s%s^K1 was sawn in half by ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:498
+#, c-format
+msgid "^BG%s%s^K1 almost dodged ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:499
+#, c-format
+msgid "^BG%s^K1 was sawn in half by their own Rocket Propelled Chainsaw%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:500
+#, c-format
+msgid "^BG%s^K1 blew themself up with their Rocket Propelled Chainsaw%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:501
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Seeker rockets%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:502
+#, c-format
+msgid "^BG%s%s^K1 was tagged by ^BG%s^K1's Seeker%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:503
+#, c-format
+msgid "^BG%s^K1 played with tiny Seeker rockets%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:504
+#, c-format
+msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shockwave%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:505
+#, c-format
+msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shockwave%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:506
+#, c-format
+msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:507
+#, c-format
+msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:508
+#, c-format
+msgid "^BG%s^K1 is now thinking with portals%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:509
+#, c-format
+msgid "^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Tuba%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:510
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Tuba%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:511
+#, c-format
+msgid "^BG%s%s^K1 has been sublimated by ^BG%s^K1's Vaporizer%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:512
+#, c-format
+msgid "^BG%s%s^K1 has been vaporized by ^BG%s^K1's Vortex%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:537
+msgid "^F4You are now alone!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:539
+msgid "^BGYou are attacking!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:540
+msgid "^BGYou are defending!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:541
+#, c-format
+msgid "^BGObjective destroyed in ^F4%s^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:543
+msgid "^F4Begin!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:544
+msgid "^F4Game starts in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:545
+msgid "^F4Round starts in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:546
+msgid "^F4Round cannot start"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:551
+msgid "^F2Don't camp!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:555
+msgid ""
+"^BGYou are now free.\n"
+"^BGFeel free to ^F2try to capture^BG the flag again\n"
+"^BGif you think you will succeed."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:556
+msgid "^BGThis flag is currently inactive"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:557
+msgid ""
+"^BGYou are now ^F1shielded^BG from the flag(s)\n"
+"^BGfor ^F2too many unsuccessful attempts^BG to capture.\n"
+"^BGMake some defensive scores before trying again."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:558
+msgid "^BGYou captured the ^TC^TT^BG flag!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:559
+msgid "^BGYou captured the flag!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:560
+#, c-format
+msgid "^BGToo many flag throws! Throwing disabled for %s."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:561
+#, c-format
+msgid "^BG%s^BG passed the ^TC^TT^BG flag to %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:562
+#, c-format
+msgid "^BG%s^BG passed the flag to %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:563
+#, c-format
+msgid "^BGYou received the ^TC^TT^BG flag from %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:564
+#, c-format
+msgid "^BGYou received the flag from %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:565
+#, c-format
+msgid "^BGPress ^F2%s^BG to receive the flag from %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:566
+#, c-format
+msgid "^BGRequesting %s^BG to pass you the flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:567
+#, c-format
+msgid "^BGYou passed the ^TC^TT^BG flag to %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:568
+#, c-format
+msgid "^BGYou passed the flag to %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:569
+msgid "^BGYou got the ^TC^TT^BG flag!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:570
+msgid "^BGYou got the flag!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:571
+#, c-format
+msgid "^BGYou got your %steam^BG's flag, return it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:572
+#, c-format
+msgid "^BGYou got the %senemy^BG's flag, return it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:573
+#, c-format
+msgid "^BGThe %senemy^BG got your flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:574
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:575
+#, c-format
+msgid "^BGThe %senemy^BG got the flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:576
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:577
+#, c-format
+msgid "^BGThe %senemy^BG got their flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:578
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:579
+#, c-format
+msgid "^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:580
+#, c-format
+msgid "^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:581
+#, c-format
+msgid "^BGYour %steam mate^BG got the flag! Protect them!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:582
+#, c-format
+msgid "^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:583
+msgid "^BGEnemies can now see you on radar!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:584
+msgid "^BGYou returned the ^TC^TT^BG flag!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:585
+msgid "^BGStalemate! Enemies can now see you on radar!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:586
+msgid "^BGStalemate! Flag carriers can now be seen by enemies on radar!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:590
+#, c-format
+msgid "^K3%sYou fragged ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:591
+#: qcsrc/common/notifications/all.inc:600
+#: qcsrc/common/notifications/all.inc:609
+#, c-format
+msgid "^K3%sYou scored against ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:592
+#, c-format
+msgid "^K1%sYou were fragged by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:593
+#: qcsrc/common/notifications/all.inc:602
+#: qcsrc/common/notifications/all.inc:611
+#, c-format
+msgid "^K1%sYou were scored against by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:599
+#, c-format
+msgid "^K3%sYou burned ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:601
+#, c-format
+msgid "^K1%sYou were burned by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:608
+#, c-format
+msgid "^K3%sYou froze ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:610
+#, c-format
+msgid "^K1%sYou were frozen by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:617
+#, c-format
+msgid "^K1%sYou typefragged ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:618
+#, c-format
+msgid "^K1%sYou scored against ^BG%s^K1 while they were typing"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:619
+#, c-format
+msgid "^K1%sYou were typefragged by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:620
+#, c-format
+msgid "^K1%sYou were scored against by ^BG%s^K1 while typing"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:626
+#, c-format
+msgid "^BGPress ^F2%s^BG again to toss the nade!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:627
+msgid "^F2You got a ^K1BONUS GRENADE^F2!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:629
+#, c-format
+msgid ""
+"^BGYou have been moved into a different team\n"
+"You are now on: %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:630
+msgid "^K1Don't go against your team mates!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:630
+msgid "^K1Don't shoot your team mates!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:631
+msgid "^K1Die camper!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:631
+msgid "^K1Reconsider your tactics, camper!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:632
+msgid "^K1You unfairly eliminated yourself!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:633
+#, c-format
+msgid "^K1You were %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:634
+msgid "^K1You couldn't catch your breath!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:635
+msgid "^K1You hit the ground with a crunch!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:636
+msgid "^K1You felt a little too hot!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:636
+msgid "^K1You got a little bit too crispy!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:637
+msgid "^K1You killed your own dumb self!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:637
+msgid "^K1You need to be more careful!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:638
+msgid "^K1You couldn't stand the heat!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:639
+msgid "^K1You need to watch out for monsters!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:639
+msgid "^K1You were killed by a monster!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:640
+msgid "^K1Tastes like chicken!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:640
+msgid "^K1You forgot to put the pin back in!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:641
+msgid "^K1Hanging around a napalm explosion is bad!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:642
+msgid "^K1You felt a little chilly!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:642
+msgid "^K1You got a little bit too cold!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:643
+msgid "^K1Your Healing Nade is a bit defective"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:644
+msgid "^K1You are respawning for running out of ammo..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:644
+msgid "^K1You were killed for running out of ammo..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:645
+msgid "^K1You grew too old without taking your medicine"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:645
+msgid "^K1You need to preserve your health"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:646
+msgid "^K1You became a shooting star!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:647
+msgid "^K1You melted away in slime!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:648
+msgid "^K1You committed suicide!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:648
+msgid "^K1You ended it all!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:649
+msgid "^K1You got stuck in a swamp!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:650
+#, c-format
+msgid "^BGYou are now on: %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:651
+msgid "^K1You died in an accident!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:652
+msgid "^K1You had an unfortunate run in with a turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:652
+msgid "^K1You were fragged by a turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:653
+msgid "^K1You had an unfortunate run in with an eWheel turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:653
+msgid "^K1You were fragged by an eWheel turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:654
+msgid "^K1You had an unfortunate run in with a Walker turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:654
+msgid "^K1You were fragged by a Walker turret!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:655
+msgid "^K1You got caught in the blast of a Bumblebee explosion!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:656
+msgid "^K1You were crushed by a vehicle!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:657
+msgid "^K1You were caught in a Raptor cluster bomb!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:658
+msgid "^K1You got caught in the blast of a Raptor explosion!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:659
+msgid "^K1You got caught in the blast of a Spiderbot explosion!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:660
+msgid "^K1You were blasted to bits by a Spiderbot rocket!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:661
+msgid "^K1You got caught in the blast of a Racer explosion!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:662
+msgid "^K1You couldn't find shelter from a Racer rocket!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:663
+msgid "^K1Watch your step!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:665
+#, c-format
+msgid "^K1Moron! You fragged ^BG%s^K1, a team mate!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:665
+#, c-format
+msgid "^K1Moron! You went against ^BG%s^K1, a team mate!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:666
+#, c-format
+msgid "^K1You were fragged by ^BG%s^K1, a team mate"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:666
+#, c-format
+msgid "^K1You were scored against by ^BG%s^K1, a team mate"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:668
+msgid ""
+"^K1Stop idling!\n"
+"^BGDisconnecting in ^COUNT..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:670
+#, c-format
+msgid "^BGYou need %s^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:671
+#, c-format
+msgid "^BGYou also need %s^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:672
+msgid "^BGDoor unlocked!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:674
+msgid "^F2You picked up some extra lives"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:676
+#, c-format
+msgid "^K3You revived ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:677
+msgid "^K3You revived yourself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:678
+#, c-format
+msgid "^K3You were revived by ^BG%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:679
+#, c-format
+msgid "^K3You were automatically revived after %s second(s)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:681
+msgid "^BGThe generator is under attack!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:683
+msgid "^TC^TT^BG team loses the round"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:687
+msgid "^K1You froze yourself"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:688
+msgid "^K1Round already started, you spawn as frozen"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:690
+#, c-format
+msgid "^K1A %s has arrived!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:694
+msgid "^BGYou got the ^F1Fuel regenerator"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:695
+msgid "^BGYou got the ^F1Jet pack"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:703
+msgid ""
+"^K1No spawnpoints available!\n"
+"Hope your team can fix it..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:704
+msgid ""
+"^K1You may not join the game at this time.\n"
+"The player limit reached maximum capacity."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:708
+msgid "^BGYou picked up the ball"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:709
+msgid "^BGKilling people while you don't have the ball gives no points!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:711
+msgid ""
+"^BGAll keys are in your team's hands!\n"
+"Help the key carriers to meet!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:712
+msgid ""
+"^BGAll keys are in ^TC^TT team^BG's hands!\n"
+"Interfere ^F4NOW^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:713
+msgid ""
+"^BGAll keys are in your team's hands!\n"
+"Meet the other key carriers ^F4NOW^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:714
+msgid "^F4Round will start in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:715
+msgid "^BGScanning frequency range..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:716
+msgid "^BGYou are starting with the ^TC^TT Key"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:718
+msgid "^BGYou have no lives left, you must wait until the next match"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:720
+#, c-format
+msgid ""
+"^BGWaiting for players to join...\n"
+"Need active players for: %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:721
+#, c-format
+msgid "^BGWaiting for %s player(s) to join..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:723
+msgid "^BGYour weapon has been downgraded until you find some ammo!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:724
+msgid "^F4^COUNT^BG left to find some ammo!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:725
+msgid "^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:725
+msgid "^BGGet some ammo! ^F4^COUNT^BG left!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:726
+#, c-format
+msgid "^F2Extra lives remaining: ^K1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:730
+#, c-format
+msgid ""
+"^F2^COUNT^BG until weapon change...\n"
+"Next weapon: ^F1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:731
+#, c-format
+msgid "^F2Active weapon: ^F1%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:733
+#, c-format
+msgid "^BGYou captured %s^BG control point"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:734
+#, c-format
+msgid "^TC^TT^BG team captured %s^BG control point"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:735
+msgid "^BGThis control point currently cannot be captured"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:736
+msgid ""
+"^BGThe enemy generator cannot be destroyed yet\n"
+"^F2Capture some control points to unshield it"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:737
+msgid "^BGThe ^TCenemy^BG generator is no longer shielded!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:738
+msgid ""
+"^K1Your generator is NOT shielded!\n"
+"^BGRe-capture control points to shield it!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:739
+#, c-format
+msgid "^BGPress ^F2%s^BG to teleport"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:740
+#, c-format
+msgid "^BGTeleporting disabled for %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:742
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"Keep fragging until we have a winner!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:742
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"Keep scoring until we have a winner!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:743
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"\n"
+"Generators are now decaying.\n"
+"The more control points your team holds,\n"
+"the faster the enemy generator decays"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:744
+#, c-format
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"^BGAdded ^F4%s^BG to the game!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:746
+msgid "^K1In^BG-portal created"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:747
+msgid "^F3Out^BG-portal created"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:748
+msgid "^F1Portal creation failed"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:750
+msgid "^F2Strength infuses your weapons with devastating power"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:751
+msgid "^F2Strength has worn off"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:753
+msgid "^F2Shield surrounds you"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:754
+msgid "^F2Shield has worn off"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:756
+msgid "^F2You are on speed"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:757
+msgid "^F2Speed has worn off"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:759
+msgid "^F2You are invisible"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:760
+msgid "^F2Invisibility has worn off"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:762
+msgid "^F2The race is over, finish your lap!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:764
+msgid "^BGSecondary fire inflicts no damage!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:766
+msgid "^BGSequence completed!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:767
+msgid "^BGThere are more to go..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:768
+#, c-format
+msgid "^BGOnly %s^BG more to go..."
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:770
+msgid "^F2Superweapons have broken down"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:771
+msgid "^F2Superweapons have been lost"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:772
+msgid "^F2You now have a superweapon"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:774
+msgid "^K1Changing to ^TC^TT^K1 in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:775
+msgid "^K1Changing team in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:776
+msgid "^K1Spectating in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:777
+msgid "^K1Suicide in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:779
+msgid "^F4Timeout begins in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:780
+msgid "^F4Timeout ends in ^COUNT"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:782
+msgid "^K1Cannot join given minigame session!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:784
+#, c-format
+msgid "^BGPress ^F2%s^BG to enter/exit the vehicle"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:785
+#, c-format
+msgid "^BGPress ^F2%s^BG to enter the vehicle gunner"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:786
+#, c-format
+msgid "^BGPress ^F2%s^BG to steal this vehicle"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:787
+msgid ""
+"^F2The enemy is stealing one of your vehicles!\n"
+"^F4Stop them!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:788
+msgid "^F2Intruder detected, disabling shields!"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:188
+msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:399 qcsrc/common/notifications/all.qh:400
+#, c-format
+msgid " (near %s)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
+msgid "primary"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
+msgid "secondary"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:410
+msgid "point"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:410
+msgid "points"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:419
+msgid "drop flag"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:420
+msgid "throw nade"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:431
+#, c-format
+msgid " with %s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:444
+#, c-format
+msgid "%s^K1 made a TRIPLE FRAG! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:444
+#, c-format
+msgid "%s^K1 made a TRIPLE SCORE! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:444
+msgid "TRIPLE FRAG! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:445
+#, c-format
+msgid "%s^K1 made FIVE SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:445
+#, c-format
+msgid "%s^K1 unlocked RAGE! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:445
+msgid "RAGE! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:446
+#, c-format
+msgid "%s^K1 made TEN SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:446
+#, c-format
+msgid "%s^K1 started a MASSACRE! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:446
+msgid "MASSACRE! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:447
+#, c-format
+msgid "%s^K1 executed MAYHEM! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:447
+#, c-format
+msgid "%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:447
+msgid "MAYHEM! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:448
+#, c-format
+msgid "%s^K1 is a BERSERKER! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:448
+#, c-format
+msgid "%s^K1 made TWENTY SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:448
+msgid "BERSERKER! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:449
+#, c-format
+msgid "%s^K1 inflicts CARNAGE! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:449
+#, c-format
+msgid "%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:449
+msgid "CARNAGE! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:450
+#, c-format
+msgid "%s^K1 made THIRTY SCORES IN A ROW! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:450
+#, c-format
+msgid "%s^K1 unleashes ARMAGEDDON! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:450
+msgid "ARMAGEDDON! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:457
+#, c-format
+msgid "%s(^F1Bot^BG)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:459
+#, c-format
+msgid "%s(Ping ^F1%d^BG)"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:466
+#, c-format
+msgid ""
+"\n"
+"(Health ^1%d^BG / Armor ^2%d^BG)%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:468
+#, c-format
+msgid ""
+"\n"
+"(^F4Dead^BG)%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:489 qcsrc/common/notifications/all.qh:502
+#, c-format
+msgid "%d score spree! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:501
+#, c-format
+msgid "%d frag spree! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:514
+msgid "First blood! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:514
+msgid "First score! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:518
+msgid "First casualty! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:518
+msgid "First victim! "
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:559
+#, c-format
+msgid "%s^K1 has %d frags in a row! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:560
+#, c-format
+msgid "%s^K1 made %d scores in a row! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:578
+#, c-format
+msgid "%s^K1 drew first blood! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:579
+#, c-format
+msgid "%s^K1 got the first score! %s^BG"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:595
+#, c-format
+msgid ", ending their %d frag spree"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:596
+#, c-format
+msgid ", ending their %d score spree"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:610
+#, c-format
+msgid ", losing their %d frag spree"
+msgstr ""
+
+#: qcsrc/common/notifications/all.qh:611
+#, c-format
+msgid ", losing their %d score spree"
+msgstr ""
+
+#: qcsrc/common/teams.qh:29
+msgid "TEAM^Red"
+msgstr ""
+
+#: qcsrc/common/teams.qh:30
+msgid "TEAM^Blue"
+msgstr ""
+
+#: qcsrc/common/teams.qh:31
+msgid "TEAM^Yellow"
+msgstr ""
+
+#: qcsrc/common/teams.qh:32
+msgid "TEAM^Pink"
+msgstr ""
+
+#: qcsrc/common/teams.qh:33
+msgid "Team"
+msgstr ""
+
+#: qcsrc/common/teams.qh:34
+msgid "Neutral"
+msgstr ""
+
+#: qcsrc/common/teams.qh:37
+msgid "KEY^Red"
+msgstr ""
+
+#: qcsrc/common/teams.qh:38
+msgid "KEY^Blue"
+msgstr ""
+
+#: qcsrc/common/teams.qh:39
+msgid "KEY^Yellow"
+msgstr ""
+
+#: qcsrc/common/teams.qh:40
+msgid "KEY^Pink"
+msgstr ""
+
+#: qcsrc/common/teams.qh:41
+msgid "FLAG^Red"
+msgstr ""
+
+#: qcsrc/common/teams.qh:42
+msgid "FLAG^Blue"
+msgstr ""
+
+#: qcsrc/common/teams.qh:43
+msgid "FLAG^Yellow"
+msgstr ""
+
+#: qcsrc/common/teams.qh:44
+msgid "FLAG^Pink"
+msgstr ""
+
+#: qcsrc/common/teams.qh:45
+msgid "GENERATOR^Red"
+msgstr ""
+
+#: qcsrc/common/teams.qh:46
+msgid "GENERATOR^Blue"
+msgstr ""
+
+#: qcsrc/common/teams.qh:47
+msgid "GENERATOR^Yellow"
+msgstr ""
+
+#: qcsrc/common/teams.qh:48
+msgid "GENERATOR^Pink"
+msgstr ""
+
+#: qcsrc/common/turrets/all.qh:51
+msgid "Turrets dump command only works with sv_cmd.\n"
+msgstr ""
+
+#: qcsrc/common/turrets/cl_turrets.qc:129
+#, c-format
+msgid "%s under attack!"
+msgstr ""
+
+#: qcsrc/common/turrets/turret.qh:11
+msgid "Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/ewheel.qh:15
+msgid "eWheel Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/ewheel_weapon.qh:7
+msgid "eWheel"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/flac.qh:13
+msgid "FLAC Cannon"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/flac_weapon.qh:7
+msgid "FLAC"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/fusionreactor.qh:11
+msgid "Fusion Reactor"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/hellion.qh:13
+msgid "Hellion Missile Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/hellion_weapon.qh:7
+msgid "Hellion"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/hk.qh:15
+msgid "Hunter-Killer Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/hk_weapon.qh:7
+msgid "Hunter-Killer"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/machinegun.qh:13
+msgid "Machinegun Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/machinegun_weapon.qh:7
+msgid "Machinegun"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/mlrs.qh:13
+msgid "MLRS Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/mlrs_weapon.qh:7
+msgid "MLRS"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/phaser.qh:13
+msgid "Phaser Cannon"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/phaser_weapon.qh:7
+msgid "Phaser"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/plasma.qh:13
+msgid "Plasma Cannon"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/plasma_dual.qh:7
+msgid "Dual plasma"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/plasma_dual.qh:19
+msgid "Dual Plasma Cannon"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/plasma_weapon.qh:7
+msgid "Plasma"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/tesla.qh:13
+#: qcsrc/common/turrets/turret/tesla_weapon.qh:7
+msgid "Tesla Coil"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/walker.qh:15
+msgid "Walker Turret"
+msgstr ""
+
+#: qcsrc/common/turrets/turret/walker_weapon.qh:7
+msgid "Walker"
+msgstr ""
+
+#: qcsrc/common/vehicles/cl_vehicles.qc:192
+#, c-format
+msgid "Press %s"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
+msgid "No right gunner!"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
+msgid "No left gunner!"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
+msgid "Bumblebee"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/racer.qh:19
+msgid "Racer"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/racer_weapon.qh:9
+msgid "Racer cannon"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/raptor.qh:19
+msgid "Raptor"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:9
+msgid "Raptor cannon"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:17
+msgid "Raptor bomb"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:25
+msgid "Raptor flare"
+msgstr ""
+
+#: qcsrc/common/vehicles/vehicle/spiderbot.qh:19
+msgid "Spiderbot"
+msgstr ""
+
+#: qcsrc/common/weapons/all.qh:78
+msgid "Weapons dump command only works with sv_cmd.\n"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/arc.qc:17
+msgid "Arc"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/blaster.qc:17
+msgid "Blaster"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/crylink.qc:17
+msgid "Crylink"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/devastator.qc:17
+msgid "Devastator"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/electro.qc:17
+msgid "Electro"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/fireball.qc:17
+msgid "Fireball"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/hagar.qc:17
+msgid "Hagar"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/hlac.qc:17
+msgid "Heavy Laser Assault Cannon"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/hook.qc:17
+msgid "Grappling Hook"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/machinegun.qc:17
+msgid "MachineGun"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/minelayer.qc:17
+msgid "Mine Layer"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/mortar.qc:17
+msgid "Mortar"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/porto.qc:17
+msgid "Port-O-Launch"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/rifle.qc:18
+msgid "Rifle"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/seeker.qc:17
+msgid "T.A.G. Seeker"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/shockwave.qc:17
+msgid "Shockwave"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/shotgun.qc:17
+msgid "Shotgun"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/tuba.qc:17
+#, no-c-format
+msgid "@!#%'n Tuba"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/vaporizer.qc:18
+msgid "Vaporizer"
+msgstr ""
+
+#: qcsrc/common/weapons/weapon/vortex.qc:18
+msgid "Vortex"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:9
+#, c-format
+msgid "CI_DEC^%s years"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:12
+#, c-format
+msgid "CI_ZER^%d years"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:13
+#, c-format
+msgid "CI_FIR^%d year"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:14
+#, c-format
+msgid "CI_SEC^%d years"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:15
+#, c-format
+msgid "CI_THI^%d years"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:16
+#, c-format
+msgid "CI_MUL^%d years"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:18
+#, c-format
+msgid "CI_DEC^%s weeks"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:21
+#, c-format
+msgid "CI_ZER^%d weeks"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:22
+#, c-format
+msgid "CI_FIR^%d week"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:23
+#, c-format
+msgid "CI_SEC^%d weeks"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:24
+#, c-format
+msgid "CI_THI^%d weeks"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:25
+#, c-format
+msgid "CI_MUL^%d weeks"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:27
+#, c-format
+msgid "CI_DEC^%s days"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:30
+#, c-format
+msgid "CI_ZER^%d days"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:31
+#, c-format
+msgid "CI_FIR^%d day"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:32
+#, c-format
+msgid "CI_SEC^%d days"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:33
+#, c-format
+msgid "CI_THI^%d days"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:34
+#, c-format
+msgid "CI_MUL^%d days"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:36
+#, c-format
+msgid "CI_DEC^%s hours"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:39
+#, c-format
+msgid "CI_ZER^%d hours"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:40
+#, c-format
+msgid "CI_FIR^%d hour"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:41
+#, c-format
+msgid "CI_SEC^%d hours"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:42
+#, c-format
+msgid "CI_THI^%d hours"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:43
+#, c-format
+msgid "CI_MUL^%d hours"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:46
+#, c-format
+msgid "CI_DEC^%s minutes"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:49
+#, c-format
+msgid "CI_ZER^%d minutes"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:50
+#, c-format
+msgid "CI_FIR^%d minute"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:51
+#, c-format
+msgid "CI_SEC^%d minutes"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:52
+#, c-format
+msgid "CI_THI^%d minutes"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:53
+#, c-format
+msgid "CI_MUL^%d minutes"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:55
+#, c-format
+msgid "CI_DEC^%s seconds"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:58
+#, c-format
+msgid "CI_ZER^%d seconds"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:59
+#, c-format
+msgid "CI_FIR^%d second"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:60
+#, c-format
+msgid "CI_SEC^%d seconds"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:61
+#, c-format
+msgid "CI_THI^%d seconds"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:62
+#, c-format
+msgid "CI_MUL^%d seconds"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:79
+#, c-format
+msgid "%dst"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:80
+#, c-format
+msgid "%dnd"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:81
+#, c-format
+msgid "%drd"
+msgstr ""
+
+#: qcsrc/lib/counting.qh:82 qcsrc/lib/counting.qh:85
+#, c-format
+msgid "%dth"
+msgstr ""
+
+#: qcsrc/lib/oo.qh:298
+msgid "No description"
+msgstr ""
+
+#: qcsrc/lib/spawnfunc.qh:65
+#, c-format
+msgid ""
+"Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, "
+"please file an issue."
+msgstr ""
+
+#: qcsrc/lib/string.qh:48
+#, c-format
+msgid "%d days, %02d:%02d:%02d"
+msgstr ""
+
+#: qcsrc/lib/string.qh:49
+#, c-format
+msgid "%02d:%02d:%02d"
+msgstr ""
+
+#: qcsrc/menu/command/menu_cmd.qc:48
+msgid "Usage: menu_cmd command..., where possible commands are:\n"
+msgstr ""
+
+#: qcsrc/menu/command/menu_cmd.qc:49
+msgid "  sync - reloads all cvars on the current menu page\n"
+msgstr ""
+
+#: qcsrc/menu/command/menu_cmd.qc:50
+msgid "  directmenu ITEM - select a menu item as main item\n"
+msgstr ""
+
+#: qcsrc/menu/command/menu_cmd.qc:79
+msgid "Available options:\n"
+msgstr ""
+
+#: qcsrc/menu/command/menu_cmd.qc:128
+msgid "Invalid command. For a list of supported commands, try menu_cmd help.\n"
+msgstr ""
+
+#: qcsrc/menu/item/listbox.qc:415
+#, c-format
+msgid "Item %d"
+msgstr ""
+
+#: qcsrc/menu/item/textslider.qc:11 qcsrc/menu/item/textslider.qc:12
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:37
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:68
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:115
+msgid "Custom"
+msgstr ""
+
+#: qcsrc/menu/xonotic/campaign.qc:241
+#, c-format
+msgid "Level %d: %s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:4
+msgid "Core Team"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:16
+msgid "Extended Team"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:48
+msgid "Website"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:53
+msgid "Stats"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:57
+msgid "Art"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:65
+msgid "Animation"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:69
+msgid "Level Design"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:92
+msgid "Music / Sound FX"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:108
+msgid "Game Code"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:116
+msgid "Marketing / PR"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:122
+msgid "Legal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:127
+msgid "Game Engine"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:131
+msgid "Engine Additions"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:136
+msgid "Compiler"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:142
+msgid "Other Active Contributors"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:149
+msgid "Translators"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:151
+msgid "Asturian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:156
+msgid "Belarusian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:159
+msgid "Bulgarian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:166
+msgid "Chinese (China)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:172
+msgid "Chinese (Taiwan)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:177
+msgid "Cornish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:180
+msgid "Czech"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:185
+msgid "Dutch"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:192
+msgid "English (Australia)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:197
+msgid "Finnish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:202
+msgid "French"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:210
+msgid "German"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:221
+msgid "Greek"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:227
+msgid "Hungarian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:231
+msgid "Irish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:234
+msgid "Italian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:240
+msgid "Kazakh"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:243
+msgid "Korean"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:247
+msgid "Polish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:255
+msgid "Portuguese"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:261
+msgid "Romanian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:268
+msgid "Russian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:279
+msgid "Scottish Gaelic"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:282
+msgid "Serbian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:288
+msgid "Spanish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:299
+msgid "Swedish"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:303
+msgid "Ukrainian"
+msgstr ""
+
+#: qcsrc/menu/xonotic/credits.qc:310
+msgid "Past Contributors"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:73
+msgid "forced to be saved to config.cfg"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:79 qcsrc/menu/xonotic/cvarlist.qc:89
+msgid "will not be saved"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:84
+msgid "will be saved to config.cfg"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:93
+msgid "private"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:95
+msgid "engine setting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/cvarlist.qc:97
+msgid "read only"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_credits.qc:13
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:38
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:287
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:85
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:75
+#: qcsrc/menu/xonotic/dialog_singleplayer_winner.qc:14
+msgid "OK"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_credits.qh:7
+msgid "Credits"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_credits.qh:8
+msgid "The Xonotic credits"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:39
+msgid ""
+"Welcome to Xonotic, please select your language preference and enter your "
+"player name to get started.  You can change these options later through the "
+"menu system."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:45
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:28
+msgid "Name:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:53
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
+msgid "Name under which you will appear in the game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:69
+msgid "Text language:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:78
+msgid "Allow player statistics to use your nickname at stats.xonotic.org?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:84
+msgid "Undecided"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:88
+msgid "Save settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qh:6
+msgid "Welcome"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
+msgid "Ammunition display:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:19
+msgid "Show only current ammo type"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:22
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:44
+msgid "Noncurrent alpha:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:26
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:48
+msgid "Noncurrent scale:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:30
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:24
+msgid "Align icon:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:31
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:30
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:23
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:35
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:21
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:33
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:18
+msgid "Left"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:36
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:26
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:23
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:34
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:20
+msgid "Right"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qh:6
+msgid "Ammo Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:17
+msgid "Message duration:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:21
+msgid "Fade time:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:25
+msgid "Flip messages order"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:15
+msgid "Text alignment:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:31
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:19
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:71
+msgid "Center"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:35
+msgid "Font scale:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh:6
+msgid "Centerprint Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
+msgid "Chat entries:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
+msgid "Chat size:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
+msgid "Chat lifetime:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
+msgid "Chat beep sound"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
+msgid "Chat Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
+msgid "Engine info:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:17
+msgid "Use an averaging algorithm for fps"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qh:6
+msgid "Engine Info Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
+msgid "Combine health and armor"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:15
+msgid "Enable status bar"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:19
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:17
+msgid "Status bar alignment:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:37
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:35
+msgid "Inward"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:29
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:38
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:36
+msgid "Outward"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:30
+msgid "Icon alignment:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:40
+msgid "Flip health and armor positions"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh:6
+msgid "Health/Armor Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
+msgid "Info messages:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:17
+msgid "Flip align"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qh:6
+msgid "Info Messages Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:16
+msgid "PNL^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:17
+msgid "PNL^Enabled spectating"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:18
+msgid "PNL^Enabled even playing in warmup"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:29
+msgid "Reduced"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:32
+msgid "Text/icon ratio:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:35
+msgid "Hide spawned items"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:37
+msgid "Hide big armor and health"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:39
+msgid "Dynamic size"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qh:6
+msgid "Items Time Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_modicons.qh:6
+msgid "Mod Icons Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:15
+msgid "Notifications:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:18
+msgid "Also print notifications to the console"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:21
+msgid "Flip notify order"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:24
+msgid "Entry lifetime:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:28
+msgid "Entry fadetime:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
+msgid "Notification Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:15
+msgid "Panel disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:16
+msgid "Panel enabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
+msgid "Panel enabled even observing"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:18
+msgid "Panel enabled only in Race/CTS"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
+msgid "Status bar"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:26
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:68
+msgid "Left align"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:27
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:74
+msgid "Right align"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:28
+msgid "Inward align"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:29
+msgid "Outward align"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:33
+msgid "Flip speed/acceleration positions"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:37
+msgid "Speed:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:38
+msgid "Include vertical speed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:49
+msgid "Speed unit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:51
+msgid "qu/s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:52
+msgid "m/s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:53
+msgid "km/h"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:54
+msgid "mph"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:55
+msgid "knots"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:57
+msgid "Show"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:60
+msgid "Top speed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:66
+msgid "Acceleration:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:67
+msgid "Include vertical acceleration"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qh:6
+msgid "Physics Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qh:6
+msgid "Powerups Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:15
+msgid "Panel enabled when spectating"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:16
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:17
+msgid "Panel always enabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:23
+msgid "Forced aspect:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qh:6
+msgid "Pressed Keys Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qh:6
+msgid "Quick Menu Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qh:6
+msgid "Race Timer Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
+msgid "Panel enabled in teamgames"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
+msgid "Radar:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:26
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:68
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:107
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:54
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:87
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:103
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:45
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:67
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:118
+#: qcsrc/menu/xonotic/util.qc:792
+msgid "Alpha:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:30
+msgid "Rotation:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:32
+msgid "Forward"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:33
+msgid "West"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:34
+msgid "South"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:35
+msgid "East"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:36
+msgid "North"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:40
+msgid "Scale:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:44
+msgid "Zoom mode:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:46
+msgid "Zoomed in"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:47
+msgid "Zoomed out"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:48
+msgid "Always zoomed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:49
+msgid "Never zoomed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qh:6
+msgid "Radar Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:15
+msgid "Score:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:18
+msgid "Rankings:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:19
+msgid "Off"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:20
+msgid "And me"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:21
+msgid "Pure"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qh:6
+msgid "Score Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:14
+msgid "Timer:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:17
+msgid "Show elapsed time"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qh:6
+msgid "Timer Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_vote.qc:15
+msgid "Alpha after voting:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_vote.qh:6
+msgid "Vote Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:20
+msgid "Fade out after:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:22
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:167
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:139
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:55
+msgid "Never"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:24
+#, c-format
+msgid "%ds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:28
+msgid "Fade effect:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:31
+msgid "EF^None"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:32
+msgid "Alpha"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:33
+msgid "Slide"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:34
+msgid "EF^Both"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:38
+msgid "Weapon icons:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:41
+msgid "Show only owned weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:52
+msgid "Show weapon ID as:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:53
+msgid "SHOWAS^None"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:54
+msgid "Number"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:55
+msgid "Bind"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:58
+msgid "Weapon ID scale:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:64
+msgid "Show Accuracy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:65
+msgid "Show Ammo"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:68
+msgid "Ammo bar alpha:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:74
+msgid "Ammo bar color:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qh:6
+msgid "Weapons Panel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:19
+msgid "HUD skins"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:22
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:196
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:31
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:42
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:25
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:35
+msgid "Filter:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:30
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:49
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:44
+msgid "Refresh"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:33
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:30
+msgid "Set skin"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:37
+msgid "Save current skin"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:46
+msgid "Panel background defaults:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:48
+#: qcsrc/menu/xonotic/util.qc:767
+msgid "Background:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:50
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:62
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:77
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:116
+#: qcsrc/menu/xonotic/util.qc:770 qcsrc/menu/xonotic/util.qc:786
+#: qcsrc/menu/xonotic/util.qc:803
+msgid "Disable"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:60
+#: qcsrc/menu/xonotic/util.qc:783
+msgid "Border size:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:75
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:114
+msgid "Team color:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:83
+#: qcsrc/menu/xonotic/util.qc:809
+msgid "Test team color in configure mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:86
+#: qcsrc/menu/xonotic/util.qc:812
+msgid "Padding:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:93
+msgid "HUD Dock:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
+msgid "DOCK^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:96
+msgid "DOCK^Small"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:97
+msgid "DOCK^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:98
+msgid "DOCK^Large"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:121
+msgid "Grid settings:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:124
+msgid "Snap panels to grid"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:127
+msgid "Grid size:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:129
+msgid "X:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:136
+msgid "Y:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:145
+msgid "Exit setup"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qh:6
+msgid "Panel HUD Setup"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:13
+msgid "Monster:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:22
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:20
+msgid "Spawn"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:23
+#: qcsrc/menu/xonotic/serverlist.qc:268
+msgid "Remove"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:25
+msgid "Move target:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:26
+msgid "Follow"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:27
+msgid "Wander"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:28
+msgid "Spawnpoint"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:29
+msgid "No moving"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:31
+msgid "Colors:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:33
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:39
+msgid "Set skin:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qh:6
+msgid "Monster Tools"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:14
+msgid "Servers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:15
+msgid "Find servers to play on"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:17
+msgid "Host your own game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:18
+msgid "Media"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:19
+msgid "Profile"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qh:6
+msgid "Multiplayer"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qh:7
+msgid ""
+"Play online, against your friends in LAN, view demos or change player "
+"settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:46
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:134
+#: qcsrc/menu/xonotic/skinlist.qc:88 qcsrc/menu/xonotic/util.qc:769
+#: qcsrc/menu/xonotic/util.qc:785 qcsrc/menu/xonotic/util.qc:794
+#: qcsrc/menu/xonotic/util.qc:802 qcsrc/menu/xonotic/util.qc:814
+msgid "Default"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:48
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:64
+msgid "Unlimited"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:66
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:78
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:128
+msgid "Frag limit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:66
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:78
+msgid "The amount of frags needed before the match will end"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
+msgid "Capture limit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
+msgid "The amount of captures needed before the match will end"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:68
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:73
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:74
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:75
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:76
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:77
+msgid "Point limit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:68
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:77
+msgid "The amount of points needed before the match will end"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:70
+msgid "Lives:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:71
+msgid "Laps:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
+msgid "Goals:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
+msgid "The amount of goals needed before the match will end"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:97
+msgid "Gametype"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:102
+msgid "Time limit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:104
+msgid "Timelimit in minutes that when hit, will end the match"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:105
+#, c-format
+msgid "%d minutes"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:106
+msgid "TIMLIM^Default"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:107
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:159
+msgid "1 minute"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:124
+msgid "TIMLIM^Infinite"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:132
+msgid "Teams:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:135
+msgid "2 teams"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:136
+msgid "3 teams"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:137
+msgid "4 teams"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:140
+msgid "Player slots:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:142
+msgid ""
+"The maximum amount of players or bots that can be connected to your server "
+"at once"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:144
+msgid "Number of bots:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:146
+msgid "Amount of bots on your server"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:148
+msgid "Bot skill:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:151
+msgid "Specify how experienced the bots will be"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:152
+msgid "Botlike"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:153
+msgid "Beginner"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:154
+msgid "You will win"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:155
+msgid "You can win"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:156
+msgid "You might win"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:157
+msgid "Advanced"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:158
+msgid "Expert"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:159
+msgid "Pro"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:160
+msgid "Assassin"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:161
+msgid "Unhuman"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:162
+msgid "Godlike"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:178
+msgid "Mutators..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:179
+msgid "Mutators and weapon arenas"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:188
+msgid "Maplist"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:198
+msgid ""
+"Click here or Ctrl-F to provide a keyword to narrow down the map list. Ctrl-"
+"Delete to clear; Enter when done."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:207
+msgid "Add shown"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:208
+msgid "Add the maps shown in the list to your selection"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:211
+msgid "Remove shown"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:212
+msgid "Remove the maps shown in the list from your selection"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:217
+msgid "Add all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:218
+msgid "Add every available map to your selection"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:221
+msgid "Remove all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:222
+msgid "Remove all the maps from your selection"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:229
+msgid "Start Multiplayer!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:58
+msgid "Title:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:64
+msgid "Author:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:70
+msgid "Game types:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:93
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:296
+msgid "Close"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:96
+msgid "MAP^Play"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qh:7
+msgid "Map Information"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:28
+msgid "All Weapons Arena"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:30
+msgid "Most Weapons Arena"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:49
+#, c-format
+msgid "%s Arena"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:61
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:159
+msgid "Dodging"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:63
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:267
+msgid "InstaGib"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:216
+msgid "New Toys"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:67
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:272
+msgid "NIX"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:220
+msgid "Rocket Flying"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:71
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:212
+msgid "Invincible Projectiles"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:75
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:282
+msgid "No start weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:77
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:195
+msgid "Low gravity"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:79
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:166
+msgid "Cloaked"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:81
+msgid "Hook"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:83
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:173
+msgid "Midair"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:87
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:224
+msgid "Piñata"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:89
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:229
+msgid "Weapons stay"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:91
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:184
+msgid "Blood loss"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:93
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:208
+msgid "Jet pack"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:95
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:170
+msgid "Buffs"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:97
+msgid "Overkill"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:99
+msgid "No powerups"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:101
+msgid "Powerups"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:103
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:163
+msgid "Touch explode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:105
+msgid "MUT^None"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:156
+msgid "Gameplay mutators:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:160
+msgid "Enable dodging"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:167
+msgid "All players are almost invisible"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:174
+msgid "Only possible to inflict damage on your enemy while he's airborne"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
+msgid "Damage done to your enemy gets added to your own health"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
+msgid ""
+"Amount of health below which your player gets stunned because of blood loss"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:192
+msgid "Make things fall to the ground slower, lower value means lower gravity"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:201
+msgid "Weapon & item mutators:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:204
+msgid "Grappling hook"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:205
+msgid "Players spawn with the grappling hook"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:209
+msgid "Players spawn with the jetpack"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:225
+msgid "Players will drop all weapons they possessed when they are killed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
+msgid "Weapons stay after they are picked up"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
+msgid "Regular (no arena)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:237
+msgid "Weapon arenas:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:238
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:256
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:261
+msgid ""
+"Selecting a weapon arena will give all players that weapon at spawn as well "
+"as unlimited ammo, and disable all other weapon pickups."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
+msgid "Most weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:260
+msgid "All weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:264
+msgid "Special arenas:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:268
+msgid ""
+"Players will be given only one weapon, which can instantly kill the opponent "
+"with a single shot. If the player runs out of ammo, he will have 10 seconds "
+"to find some or if he fails to do so, face death. The secondary fire mode "
+"does not inflict any damage but is good for doing trickjumps."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
+msgid ""
+"No items Xonotic - instead of pickup items, everyone plays with the same "
+"weapon. After some time, a countdown will start, after which everyone will "
+"switch to another weapon."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:277
+msgid "with blaster"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:278
+msgid "Always carry the blaster as an additional weapon in Nix"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qh:9
+msgid "Mutators"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:38
+msgid "SRVS^Categories"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:41
+msgid "SRVS^Empty"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:42
+msgid "Show empty servers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:46
+msgid "SRVS^Full"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:47
+msgid "Show full servers that have no slots available"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:51
+msgid "Pause"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:52
+msgid ""
+"Pause updating the server list to prevent servers from \"jumping around\""
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
+msgid "Reload the server list"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:67
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:223
+msgid "Address:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:78
+msgid "Info..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:79
+msgid "Show more information about the currently highlighted server"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:84
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:303
+msgid "Join!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:154
+#: qcsrc/menu/xonotic/serverlist.qc:1061
+msgid "MOD^Default"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+#, c-format
+msgid "%d modified"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+msgid "Official"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
+msgid "N/A (auth library missing, can't connect)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:171
+msgid "N/A (auth library missing)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:177
+msgid "Not supported (can't connect)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
+msgid "Not supported (won't encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:183
+msgid "Supported (will encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:185
+msgid "Supported (won't encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:189
+msgid "Requested (will encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:191
+msgid "Requested (won't encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:195
+msgid "Required (can't connect)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:197
+msgid "Required (will encrypt)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:217
+msgid "Hostname:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:231
+msgid "Gametype:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:236
+msgid "Map:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:241
+msgid "Mod:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:246
+msgid "Version:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:251
+msgid "Settings:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:258
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:290
+msgid "Players:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:263
+msgid "Bots:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:268
+msgid "Free slots:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:274
+msgid "Encryption:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:279
+msgid "ID:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:284
+msgid "Key:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh:7
+msgid "Server Information"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:25
+msgid "Demos"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:26
+msgid "Screenshots"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:27
+msgid "Music Player"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:48
+msgid "Auto record demos"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:57
+msgid "Timedemo"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:58
+msgid "Benchmark how fast your computer can run the highlighted demo"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:62
+msgid "DEMO^Play"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:13
+msgid "Playing a demo will disconnect you from the current match."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:15
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:15
+msgid "Do you really wish to disconnect now?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh:6
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qh:6
+msgid "Disconnect"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:13
+msgid "Timing a demo will disconnect you from the current match."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:37
+msgid "MUSICPL^Add"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:40
+msgid "MUSICPL^Add all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:44
+msgid "Set as menu track"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:48
+msgid "Reset default menu track"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:54
+msgid "Playlist:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:55
+msgid "Random order"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:60
+msgid "MUSICPL^Stop"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:63
+msgid "MUSICPL^Play"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:66
+msgid "MUSICPL^Pause"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:69
+msgid "MUSICPL^Prev"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:72
+msgid "MUSICPL^Next"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:76
+msgid "MUSICPL^Remove"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:79
+msgid "MUSICPL^Remove all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
+msgid "Auto screenshot scoreboard"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:63
+msgid "Open in the viewer"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:139
+msgid "Reset"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:144
+msgid "Previous"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:147
+msgid "Next"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:152
+msgid "Slide show"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:34
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:21
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:37
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:25
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:20
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:21
+msgid "Apply immediately"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
+msgid "Name"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:77
+msgid "Model"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:96
+msgid "Glowing color"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:106
+msgid "Detail color"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:121
+msgid "Statistics"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:125
+msgid "Allow player statistics to track your client"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:129
+msgid "Allow player statistics to use your nickname"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
+msgid "Country"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
+msgid "Gender:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:161
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:174
+msgid "Undisclosed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:162
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:172
+msgid "Female"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:163
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:173
+msgid "Male"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:166
+msgid "Gender"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:11
+msgid "Are you sure you want to quit?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:15
+msgid "Back to work..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:17
+msgid "I got some more fragging to do!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_quit.qh:7
+msgid "Quit the game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:15
+msgid "Model:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:21
+msgid "Remove *"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:23
+msgid "Copy *"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:24
+msgid "Paste"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:26
+msgid "Bone:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:31
+msgid "Set * as child"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:32
+msgid "Attach to *"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:34
+msgid "Detach from *"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:37
+msgid "Visual object properties for *:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:41
+msgid "Set alpha:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:44
+msgid "Set color main:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:46
+msgid "Set color glow:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:50
+msgid "Set frame:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:54
+msgid "Physical object properties for *:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:56
+msgid "Set material:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:62
+msgid "Set solidity:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:63
+msgid "Non-solid"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:64
+msgid "Solid"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:65
+msgid "Set physics:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:66
+msgid "Static"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:67
+msgid "Movable"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:68
+msgid "Physical"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:70
+msgid "Set scale:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:72
+msgid "Set force:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:76
+msgid "Claim *"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:78
+msgid "* object info"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:79
+msgid "* mesh info"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:80
+msgid "* attachment info"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:81
+msgid "Show help"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:82
+msgid "* is the object you are facing"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qh:6
+msgid "Sandbox Tools"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:18
+msgid "Video"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:19
+msgid "Effects"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:20
+msgid "Audio"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:22
+msgid "Game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:23
+msgid "Input"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:24
+msgid "User"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:25
+#: qcsrc/menu/xonotic/keybinder.qc:105
+msgid "Misc"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qh:6
+msgid "Settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings.qh:7
+msgid "Change the game settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
+msgid "Master:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:35
+msgid "Music:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:43
+msgid "VOL^Ambient:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:50
+msgid "Info:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:57
+msgid "Items:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:64
+msgid "Pain:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:71
+msgid "Player:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:78
+msgid "Shots:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:85
+msgid "Voice:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:93
+msgid "Weapons:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:99
+msgid "New style sound attenuation"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:102
+msgid "Mute sounds when not active"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:105
+msgid "Frequency:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:107
+msgid "Sound output frequency"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:108
+msgid "8 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:109
+msgid "11.025 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:110
+msgid "16 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:111
+msgid "22.05 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:112
+msgid "24 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:113
+msgid "32 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:114
+msgid "44.1 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:115
+msgid "48 kHz"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:119
+msgid "Channels:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:121
+msgid "Number of channels for the sound output"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:122
+msgid "Mono"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:123
+msgid "Stereo"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:124
+msgid "2.1"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:125
+msgid "4"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:126
+msgid "5"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:127
+msgid "5.1"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:128
+msgid "6.1"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:129
+msgid "7.1"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:134
+msgid "Swap stereo output channels"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:135
+msgid "Swap left/right channels"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:138
+msgid "Headphone friendly mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:139
+msgid ""
+"Enable spatialization (blend the right and left channel slightly to decrease "
+"stereo separation a bit for headphones)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:143
+msgid "Hit indication sound"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:144
+msgid "Play a hit indicator sound when your shot hits an enemy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:147
+msgid "Chat message sound"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:149
+msgid "Menu sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:150
+msgid "Play sounds when clicking menu items"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:151
+msgid "Focus sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:152
+msgid "Play sounds when hovering over menu items too"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:156
+msgid "Time announcer:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:158
+msgid "WRN^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:160
+msgid "5 minutes"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:161
+msgid "WRN^Both"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:164
+msgid "Automatic taunts:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:166
+msgid "Automatically taunt enemies after fragging them"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
+msgid "Sometimes"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:169
+msgid "Often"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:170
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:141
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:57
+msgid "Always"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:176
+msgid "Debug info about sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:41
+msgid "Quality preset:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:45
+msgid "PRE^OMG!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:48
+msgid "PRE^Low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:50
+msgid "PRE^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:52
+msgid "PRE^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:54
+msgid "PRE^High"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:56
+msgid "PRE^Ultra"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:60
+msgid "PRE^Ultimate"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:65
+msgid "Geometry detail:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:67
+msgid "Change the smoothness of the curves on the map (default: normal)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:68
+msgid "DET^Lowest"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:69
+msgid "DET^Low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:70
+msgid "DET^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:71
+msgid "DET^Good"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:72
+msgid "DET^Best"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:73
+msgid "DET^Insane"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:77
+msgid "Player detail:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:79
+msgid "PDET^Low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:80
+msgid "PDET^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:81
+msgid "PDET^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:82
+msgid "PDET^Good"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:83
+msgid "PDET^Best"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:87
+msgid "Texture resolution:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:91
+msgid "RES^Leet"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:92
+msgid "RES^Lowest"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:93
+msgid "RES^Very low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:94
+msgid "RES^Low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:95
+msgid "RES^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:96
+msgid "RES^Good"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:97
+msgid "RES^Best"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:110
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:115
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:120
+msgid "Avoid lossy texture compression"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:131
+msgid "Show surfaces"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:132
+msgid ""
+"Disable textures completely for very slow hardware. This gives a huge "
+"performance boost, but looks very ugly. (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:135
+msgid "Use lightmaps"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:136
+msgid ""
+"Use high resolution lightmaps, which will look pretty but use up some extra "
+"video memory (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:138
+msgid "Deluxe mapping"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:139
+msgid "Use per-pixel lighting effects (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:141
+msgid "Gloss"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:142
+msgid ""
+"Enable the use of glossmaps on textures supporting it (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:145
+msgid "Offset mapping"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:146
+msgid ""
+"Offset mapping effect that will make textures with bumpmaps appear like they "
+"\"pop out\" of the flat 2D surface (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:148
+msgid "Relief mapping"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:149
+msgid ""
+"Higher quality offset mapping, which also has a huge impact on performance "
+"(default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:152
+msgid "Reflections:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:153
+msgid ""
+"Reflection and refraction quality, has a huge impact on performance on maps "
+"with reflecting surfaces (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:156
+msgid "Resolution of reflections/refractions (default: good)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:157
+msgid "Blurred"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:158
+msgid "REFL^Good"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:159
+msgid "Sharp"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:163
+msgid "Decals"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
+msgid "Enable decals (bullet holes and blood) (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:165
+msgid "Decals on models"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:169
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:253
+msgid "Distance:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:172
+msgid "Decals further away than this will not be drawn (default: 300)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:176
+msgid "Time:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:179
+msgid "Time in seconds before decals fade away (default: 2)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:183
+msgid "Damage effects:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:185
+msgid "DMGFX^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:186
+msgid "Skeletal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:187
+msgid "DMGFX^All"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:191
+msgid "No dynamic lighting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:192
+msgid "Enable corona flares around certain lights (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:194
+msgid "Fake corona lighting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:195
+msgid ""
+"Enable faster but uglier dynamic lights by rendering bright coronas instead "
+"of real dynamic lights (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:198
+msgid "Realtime dynamic lighting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:199
+msgid ""
+"Enable rendering of dynamic lights such as explosions and rocket lights "
+"(default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:201
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:207
+msgid "Shadows"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:202
+msgid "Enable rendering of shadows from dynamic lights (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:205
+msgid "Realtime world lighting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:206
+msgid ""
+"Enable rendering of full realtime world lighting on maps that support it. "
+"Note that this might have a big impact on performance. (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:208
+msgid ""
+"Enable rendering of shadows from realtime world lights (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:212
+msgid "Use normal maps"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:213
+msgid "Enable use of directional shading on textures (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:215
+msgid "Soft shadows"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:219
+msgid "Fade corona according to visibility"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:220
+msgid "Fade coronas according to visibility (default: enabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:224
+msgid "Bloom"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:225
+msgid ""
+"Enable bloom effect, which brightens the neighboring pixels of very bright "
+"pixels. Has a big impact on performance. (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:226
+msgid "Extra postprocessing effects"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:227
+msgid ""
+"Enables special postprocessing effects for when damaged or under water or "
+"using a powerup (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:232
+msgid "Motion blur strength - 0.4 recommended"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:233
+msgid "Motion blur:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
+msgid "Particles"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:240
+msgid "Spawnpoint effects"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:241
+msgid "Particles effects at all spawn points and whenever a player spawns"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:246
+msgid "Quality:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:249
+msgid ""
+"Multiplier for amount of particles. Less means less particles, which in turn "
+"gives for better performance (default: 1.0)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:256
+msgid "Particles further away than this will not be drawn (default: 1000)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:31
+msgid "No crosshair"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:33
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:62
+msgid "Per weapon"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:34
+msgid ""
+"Set a different crosshair for each weapon, good if you play without weapon "
+"models"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:48
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:81
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:97
+msgid "Size:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:64
+msgid "By health"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:76
+msgid "Use rings to indicate weapon status"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:93
+msgid "Enable center crosshair dot"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:111
+msgid "Use normal crosshair color"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:122
+msgid "Smooth effects of crosshairs"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:125
+msgid "Hit testing:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:128
+msgid ""
+"None: do not do hit tests for the crosshair; TrueAim: blur the crosshair "
+"when there's an obstacle between your gun and the target; Enemies: also "
+"enlarge the crosshair when you would hit an enemy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:129
+msgid "HTTST^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:130
+msgid "HTTST^TrueAim"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:131
+msgid "HTTST^Enemies"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:136
+msgid "Blur crosshair if the shot is obstructed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:140
+msgid "Enlarge crosshair if targeting an enemy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:143
+msgid "Animate crosshair when hitting an enemy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:146
+msgid "Animate crosshair when picking up an item"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh:7
+msgid "Crosshair"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:48
+msgid "Fading speed:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:51
+msgid "Enable rows / columns highlighting"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:55
+msgid "Show decimals in respawn countdown"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
+msgid "Show accuracy underneath scoreboard"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
+msgid "Waypoints"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:63
+msgid "Display waypoint markers for objectives on the map"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:64
+msgid "Show various gametype specific waypoints"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:70
+msgid "Control transparency of the waypoints"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:74
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:124
+msgid "Fontsize:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:80
+msgid "Edge offset:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:89
+msgid "Fade when near the crosshair"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:94
+msgid "Damage"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:96
+msgid "Overlay:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:99
+msgid "Factor:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:104
+msgid "Fade rate:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:112
+msgid "Player Names"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:114
+msgid "Show names above players"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:130
+msgid "Max distance:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:136
+msgid "Decolorize:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:140
+#: qcsrc/menu/xonotic/keybinder.qc:99
+msgid "Teamplay"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:148
+msgid "Only when near crosshair"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
+msgid "Display health and armor"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:157
+msgid "Damage overlay:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:160
+msgid "Dynamic HUD"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:161
+msgid "HUD moves around following player's movement"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:163
+msgid "Shake the HUD when hurt"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:167
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qh:6
+msgid "Enter HUD editor"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
+msgid "HUD"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:21
+msgid "In order for the HUD editor to show, you must first be in game."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
+msgid "Do you wish to start a local game to set up the HUD?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
+msgid "Frag Information"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:26
+msgid "Display information about killing sprees"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:29
+msgid "Only display sprees if they are achievements"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:34
+msgid "Show spree information in centerprints"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:38
+msgid "Show spree information in death messages"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:43
+msgid "Sprees in info messages:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
+msgid "SPREES^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
+msgid "Target"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:48
+msgid "Attacker"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:49
+msgid "SPREES^Both"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:55
+msgid "Print on a seperate line"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:58
+msgid "Add extra frag information to centerprint when available"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
+msgid "Add frag location to death messages when available"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:65
+msgid "Gamemode Settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:67
+msgid "Display capture times in Capture The Flag"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:71
+msgid "Display name of flag stealer in Capture The Flag"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:76
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:91
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:133
+msgid "Other"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
+msgid "Display console messages in the top left corner"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
+msgid "Display all info messages in the chatbox"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
+msgid "Display player statuses in the chatbox"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
+msgid "Powerup notifications"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
+msgid "Weapon centerprint notifications"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:92
+msgid "Weapon info message notifications"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:96
+msgid "Announcers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:98
+msgid "Respawn countdown sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:101
+msgid "Killstreak sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:104
+msgid "Achievement sounds"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
+msgid "Messages"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
+msgid "Items"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:32
+msgid "Use simple 2D images instead of item models"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:34
+msgid "Unavailable alpha:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:37
+msgid "Unavailable color:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:39
+msgid "GHOITEMS^Black"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:40
+msgid "GHOITEMS^Dark"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:41
+msgid "GHOITEMS^Tinted"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:42
+msgid "GHOITEMS^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:43
+msgid "GHOITEMS^Blue"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:49
+#: qcsrc/menu/xonotic/serverlist.qc:767
+msgid "Players"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:51
+msgid "Force player models to mine"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:53
+msgid "Force player colors to mine"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:56
+msgid "In non teamplay modes only"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
+msgid "Body fading:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:63
+msgid "Gibs:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:65
+msgid "GIBS^None"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:66
+msgid "GIBS^Few"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:67
+msgid "GIBS^Many"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:68
+msgid "GIBS^Lots"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qh:7
+msgid "Models"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qh:8
+msgid "Customize how players and items are displayed in game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:26
+msgid "1st person perspective"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:30
+msgid "Slide to third person upon death"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:34
+msgid "Smooth the view when landing from a jump"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:38
+msgid "Smooth the view while crouching"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:42
+msgid "View waving while idle"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:46
+msgid "View bobbing while walking around"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:51
+msgid "3rd person perspective"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:55
+msgid "Back distance"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:61
+msgid "Up distance"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:67
+msgid "Allow passing through walls while spectating"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:70
+msgid "Field of view:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:72
+msgid "Field of vision in degrees (default: 100)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:76
+msgid "ZOOM^Zoom factor:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:78
+msgid "How big the zoom factor is when the zoom button is pressed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:81
+msgid "ZOOM^Zoom speed:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:83
+msgid "How fast the view will be zoomed, disable to zoom instantly"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:92
+msgid "ZOOM^Instant"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:96
+msgid "ZOOM^Zoom sensitivity:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:98
+msgid ""
+"How zoom changes sensitivity, from 0 (lower sensitivity) to 1 (no "
+"sensitivity change)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:101
+msgid "Velocity zoom"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:102
+msgid "Forward movement only"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:106
+msgid "VZOOM^Factor"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:113
+msgid "Display reticle 2D overlay while zooming"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:116
+msgid "Release zoom when you die or respawn"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:120
+msgid "Release zoom when you switch weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qh:7
+#: qcsrc/menu/xonotic/keybinder.qc:76
+msgid "View"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:34
+msgid "Weapon Priority List (* = mutator weapon)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:40
+msgid "Up"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:44
+msgid "Down"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:50
+msgid "Use priority list for weapon cycling"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:51
+msgid ""
+"Make use of the list above when cycling through weapons with the mouse wheel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:53
+msgid "Cycle through only usable weapon selections"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:57
+msgid "Auto switch weapons on pickup"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:58
+msgid ""
+"Automatically switch to newly picked up weapons if they are better than what "
+"you are carrying"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:61
+msgid "Release attack buttons when you switch weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:64
+msgid "Draw 1st person weapon model"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:65
+msgid "Draw the weapon model"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:69
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:72
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:75
+msgid "Position of the weapon model; requires reconnect"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:80
+msgid "Gun model swaying"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:85
+msgid "Gun model bobbing"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qh:7
+#: qcsrc/menu/xonotic/keybinder.qc:43
+msgid "Weapons"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:33
+msgid "Key Bindings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:37
+msgid "Change key..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:41
+msgid "Edit..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:47
+msgid "Clear"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:52
+msgid "Reset all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:57
+msgid "Mouse"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:59
+msgid "Sensitivity:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:61
+msgid "Mouse speed multiplier"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:63
+msgid "Smooth aiming"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:64
+msgid "Smoothes the mouse movement, but makes aiming slightly less responsive"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:66
+msgid "Invert aiming"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:67
+msgid "Invert mouse movement on the Y-axis"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:69
+msgid "Use system mouse positioning"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:74
+msgid "Enable built in mouse acceleration"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:78
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:82
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:85
+msgid "Disable system mouse acceleration"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:79
+msgid "Make use of DGA mouse input"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:93
+msgid "Pressing \"enter console\" key also closes it"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:94
+msgid "Allow the console toggling bind to also close the console"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:96
+msgid "Automatically repeat jumping if holding jump"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:99
+msgid "Jetpack on jump:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:101
+msgid "JPJUMP^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:102
+msgid "Air only"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:103
+msgid "JPJUMP^All"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:109
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:114
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:119
+msgid "Use joystick input"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:31
+msgid "Command when pressed:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:34
+msgid "Command when released:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:40
+msgid "Cancel"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
+msgid "User defined key bind"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:11
+#, c-format
+msgid "%d fps"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:12
+#, c-format
+msgid "%d KB/s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:13
+#, c-format
+msgid "%d MB/s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:27
+msgid "Network"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:29
+msgid "Client UDP port:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:31
+msgid "Force client to use chosen port unless it is set to 0"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
+msgid "Bandwidth:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:36
+msgid "Specify your network speed"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
+msgid "56k"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:38
+msgid "ISDN"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:39
+msgid "Slow ADSL"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:40
+msgid "Fast ADSL"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:41
+msgid "Broadband"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:44
+msgid "Input packets/s:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:46
+msgid "How many input packets to send to the server each second"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:48
+msgid "Server queries/s:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
+msgid "Downloads:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:54
+msgid "Maximum number of concurrent HTTP/FTP downloads"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:56
+msgid "Download speed:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:69
+msgid "Local latency:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:73
+msgid "Show netgraph"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:74
+msgid "Show a graph of packet sizes and other information"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:76
+msgid "Client-side movement prediction"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:78
+msgid "Movement error compensation"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:82
+msgid "Use encryption (AES) when available"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:85
+msgid "Framerate"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:87
+msgid "Maximum:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:99
+msgid "MAXFPS^Unlimited"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:102
+msgid "Target:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:104
+msgid "TRGT^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:116
+msgid "Idle limit:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:122
+msgid "IDLFPS^Unlimited"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:126
+msgid "Save processing time for other apps"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:129
+msgid "Show frames per second"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:130
+msgid "Show your rendered frames per second"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
+msgid "Menu tooltips:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:137
+msgid ""
+"Menu tooltips: disabled, standard or advanced (also shows cvar or console "
+"command bound to the menu item)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:138
+msgid "TLTIP^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:139
+msgid "TLTIP^Standard"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:140
+msgid "TLTIP^Advanced"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:143
+msgid "Show current date and time"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:144
+msgid "Show current date and time of day, useful on screenshots"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:147
+msgid "Enable developer mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:151
+msgid "Advanced settings..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:152
+msgid "Advanced settings where you can tweak every single variable of the game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:157
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qh:6
+msgid "Factory reset"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:31
+msgid "Cvar filter:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:38
+msgid "Modified cvars only"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:45
+msgid "Setting:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:49
+msgid "Type:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:53
+msgid "Value:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:70
+msgid "Description:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qh:7
+msgid "Advanced settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:11
+msgid "Are you sure you want to reset all settings?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:13
+msgid "This will create a backup config in your data directory"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:25
+msgid "Menu Skins"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:64
+msgid "Text Language"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:69
+msgid "Set language"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:74
+msgid "Disable gore effects and harsh language"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:75
+msgid ""
+"Replace blood and gibs with content that does not have any gore effects "
+"(default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:10
+msgid "While connected language changes will be applied only to the menu,"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
+msgid "full language changes will take effect starting from the next game"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
+msgid "Disconnect now"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:17
+msgid "Switch language"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qh:6
+msgid "Warning"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:33
+msgid "Resolution:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:37
+msgid "Font/UI size:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:39
+msgid "SZ^Unreadable"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:40
+msgid "SZ^Tiny"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:41
+msgid "SZ^Little"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:42
+msgid "SZ^Small"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:43
+msgid "SZ^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:44
+msgid "SZ^Large"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:45
+msgid "SZ^Huge"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:46
+msgid "SZ^Gigantic"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:47
+msgid "SZ^Colossal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:51
+msgid "Color depth:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:53
+msgid "How many bits per pixel (BPP) to render at, 32 is recommended"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:54
+msgid "16bit"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:55
+msgid "32bit"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:59
+msgid "Full screen"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:61
+msgid "Vertical Synchronization"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:62
+msgid ""
+"Enable vertical synchronization to prevent tearing, will cap your fps to the "
+"screen refresh rate (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:67
+msgid "Flip view horizontally"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:68
+msgid "Poor man's left handed mode (default: off)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:71
+msgid "Anisotropy:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:73
+msgid "Anisotropic filtering quality (default: 1x)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:74
+msgid "ANISO^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:75
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:86
+msgid "2x"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:76
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:87
+msgid "4x"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:77
+msgid "8x"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:78
+msgid "16x"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:81
+msgid "Antialiasing:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:84
+msgid ""
+"Enable antialiasing, which smooths the edges of 3D geometry. Note that it "
+"might decrease performance by quite a lot (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:85
+msgid "AA^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:92
+msgid "High-quality frame buffer"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:97
+msgid "Depth first:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:99
+msgid ""
+"Eliminate overdraw by rendering a depth-only version of the scene before the "
+"normal rendering starts (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:100
+msgid "DF^Disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:101
+msgid "DF^World"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:102
+msgid "DF^All"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:105
+msgid "Vertex Buffer Objects (VBOs)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:108
+msgid "VBO^Off"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:109
+msgid "Vertices, some Tris (compatible)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:110
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:114
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:116
+msgid ""
+"Make use of Vertex Buffer Objects to store static geometry in video memory "
+"for faster rendering (default: Vertex and Triangles)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:113
+msgid "Vertices"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:115
+msgid "Vertices and Triangles"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:119
+msgid "Brightness:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:121
+msgid "Brightness of black (default: 0)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:123
+msgid "Contrast:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:125
+msgid "Brightness of white (default: 1)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:127
+msgid "Gamma:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:130
+msgid ""
+"Inverse gamma correction value, a brightness effect that does not affect "
+"white or black (default: 1.125)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:133
+msgid "Contrast boost:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:136
+msgid "By how much to multiply the contrast in dark areas (default: 1)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:139
+msgid "Saturation:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:142
+msgid ""
+"Saturation adjustment (0 = grayscale, 1 = normal, 2 = oversaturated), "
+"requires GLSL color control (default: 1)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:146
+msgid "LIT^Ambient:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:148
+msgid ""
+"Ambient lighting, if set too high it tends to make light on maps look dull "
+"and flat (default: 4)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:150
+msgid "Intensity:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:152
+msgid "Global rendering brightness (default: 1)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:155
+msgid "Wait for GPU to finish each frame"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:156
+msgid ""
+"Make the CPU wait for the GPU to finish each frame, can help with some "
+"strange input or video lag on some machines (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:158
+msgid "Use OpenGL 2.0 shaders (GLSL)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:162
+msgid "Use GLSL to handle color control"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:163
+msgid ""
+"Enable use of GLSL to apply gamma correction, note that it might decrease "
+"performance by a lot (default: disabled)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:168
+msgid "Psycho coloring (easter egg)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:171
+msgid "Trippy vertices (easter egg)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:110
+msgid "Instant action! (random map with bots)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:117
+msgid "???"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:130
+msgid "Campaign Difficulty:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:131
+msgid "CSKL^Easy"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:132
+msgid "CSKL^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:133
+msgid "CSKL^Hard"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:135
+msgid "Start Singleplayer!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qh:6
+msgid "Singleplayer"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qh:7
+msgid "Play the singleplayer campaign or instant action matches against bots"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
+msgid "Winner"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:32
+msgid "join 'best' team (auto-select)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:33
+msgid "Autoselect team (recommended)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:37
+msgid "red"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:38
+msgid "blue"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:39
+msgid "yellow"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:40
+msgid "pink"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:43
+msgid "spectate"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qh:7
+msgid "Team Selection"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:10
+msgid "Allow player statistics to use your nickname?"
+msgstr ""
+
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:12
+msgid "Answering \"No\" you will appear as \"Anonymous player\""
+msgstr ""
+
+#: qcsrc/menu/xonotic/gametypelist.qc:86
+msgid "teamplay"
+msgstr ""
+
+#: qcsrc/menu/xonotic/gametypelist.qc:88
+msgid "free for all"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:29
+msgid "Moving"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:30
+msgid "forward"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:31
+msgid "backpedal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:32
+msgid "strafe left"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:33
+msgid "strafe right"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:34
+msgid "jump / swim"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:35
+msgid "crouch / sink"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:36
+msgid "off-hand hook"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:37
+msgid "jet pack"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:39
+msgid "Attacking"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:44
+msgid "WEAPON^previous"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:45
+msgid "WEAPON^next"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:46
+msgid "WEAPON^previously used"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:47
+msgid "WEAPON^best"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:48
+msgid "reload"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:49
+msgid "drop weapon / throw nade"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:77
+msgid "hold zoom"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:78
+msgid "toggle zoom"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:79
+msgid "show scores"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:80
+msgid "screen shot"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:81
+msgid "maximize radar"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:82
+msgid "3rd person view"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:83
+msgid "enter spectator mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:85
+msgid "Communicate"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:86
+msgid "public chat"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:87 qcsrc/menu/xonotic/keybinder.qc:100
+msgid "team chat"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:88
+msgid "show chat history"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:89
+msgid "vote YES"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:90
+msgid "vote NO"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:93
+msgid "Client"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:95
+msgid "enter console"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:96
+msgid "disconnect"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:97
+msgid "quit"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:101
+msgid "auto-join team"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:103
+msgid "drop key / drop flag"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:106
+msgid "quick menu"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:107
+msgid "sandbox menu"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:108
+msgid "drag object"
+msgstr ""
+
+#: qcsrc/menu/xonotic/keybinder.qc:110
+msgid "User defined"
+msgstr ""
+
+#: qcsrc/menu/xonotic/mainwindow.qc:64 qcsrc/menu/xonotic/mainwindow.qc:67
+msgid "Do not press this button again!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/maplist.qc:291
+msgid ""
+"Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"
+msgstr ""
+
+#: qcsrc/menu/xonotic/maplist.qc:299
+#, c-format
+msgid "%s's Xonotic Server"
+msgstr ""
+
+#: qcsrc/menu/xonotic/maplist.qc:304
+msgid ""
+"Huh? Can't play this (invalid game type). Refiltering so this won't happen "
+"again.\n"
+msgstr ""
+
+#: qcsrc/menu/xonotic/playerlist.qc:100 qcsrc/menu/xonotic/playerlist.qc:110
+msgid "spectator"
+msgstr ""
+
+#: qcsrc/menu/xonotic/playermodel.qc:170
+msgid "<no model found>"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:273
+msgid "Favorite"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:274
+msgid ""
+"Bookmark the currently highlighted server so that it's faster to find in the "
+"future"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:763
+msgid "Ping"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:764
+msgid "Hostname"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:765
+msgid "Map"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:766
+msgid "Type"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+#, c-format
+msgid "AES level %d"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+msgid "ENC^none"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+msgid "encryption:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1061
+#, c-format
+msgid "mod: %s"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1063
+#, c-format
+msgid "modified settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1063
+#, c-format
+msgid "official settings"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1065
+msgid "stats disabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qc:1065
+msgid "stats enabled"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:151
+msgid "SLCAT^Favorites"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:152
+msgid "SLCAT^Recommended"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:153
+msgid "SLCAT^Normal Servers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:154
+msgid "SLCAT^Servers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:155
+msgid "SLCAT^Competitive Mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:156
+msgid "SLCAT^Modified Servers"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:157
+msgid "SLCAT^Overkill"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:158
+msgid "SLCAT^InstaGib"
+msgstr ""
+
+#: qcsrc/menu/xonotic/serverlist.qh:159
+msgid "SLCAT^Defrag Mode"
+msgstr ""
+
+#: qcsrc/menu/xonotic/skinlist.qc:70
+msgid "<TITLE>"
+msgstr ""
+
+#: qcsrc/menu/xonotic/skinlist.qc:71
+msgid "<AUTHOR>"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:72
+msgid "VOL^MAX"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:74
+msgid "VOL^OFF"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:82
+#, c-format
+msgid "%s dB"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:13
+msgid ""
+"Multiplier for amount of particles. Less means less particles, which in turn "
+"gives for better performance (default: 1)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:14
+msgid "PART^OMG"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:15
+msgid "PART^Low"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:16
+msgid "PART^Medium"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:17
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:14
+msgid "PART^Normal"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:18
+msgid "PART^High"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:19
+msgid "PART^Ultra"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_particles.qc:20
+msgid "PART^Ultimate"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_picmip.qc:13
+msgid ""
+"Change the sharpness of the textures. Lowering it will effectively reduce "
+"texture memory usage, but make the textures appear very blurry. (default: "
+"good)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_resolution.qc:115
+msgid "Screen resolution"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:13
+msgid "PART^Slow"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:15
+msgid "PART^Fast"
+msgstr ""
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:16
+msgid "PART^Instant"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:29
+msgid "January"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:30
+msgid "February"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:31
+msgid "March"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:32
+msgid "April"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:33
+msgid "May"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:34
+msgid "June"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:35
+msgid "July"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:36
+msgid "August"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:37
+msgid "September"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:38
+msgid "October"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:39
+msgid "November"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:40
+msgid "December"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:96
+msgid "Joined:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:103
+msgid "Last_Seen:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:110
+msgid "Time_Played:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:117
+msgid "Favorite_Map:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:201 qcsrc/menu/xonotic/statslist.qc:245
+#, c-format
+msgid "%s_Matches:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:208
+#, c-format
+msgid "%s_ELO:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:215
+#, c-format
+msgid "%s_Rank:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:222
+#, c-format
+msgid "%s_Percentile:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:231
+#, c-format
+msgid "%s_Favorite_Map:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/statslist.qc:246
+#, c-format
+msgid "%d (unranked)"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:417
+#, c-format
+msgid ""
+"Update can be downloaded at:\n"
+"%s\n"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:528
+msgid "Autogenerating mapinfo for newly added maps..."
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:557
+#, c-format
+msgid "^1%s TEST BUILD"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:577
+#, c-format
+msgid "Update to %s now!"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:662
+msgid ""
+"^1ERROR: Texture compression is required but not supported.\n"
+"^1Expect visual problems.\n"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:780
+msgid "Use default"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qc:800
+msgid "Team Color:"
+msgstr ""
+
+#: qcsrc/menu/xonotic/util.qh:44
+msgid "Enable panel"
+msgstr ""
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Sembang"
index f8c5ab3bb4e145ab0637ed0f6d8413168984aa90..0b40453da5c9aa0dc5cfe785e3add14ea5e6ba47 100644 (file)
 # Kriss Chr <kriss7475@gmail.com>, 2017
 # Piotr Kozica <koza91@gmail.com>, 2016
 # Rafał Szymański <okavasly@gmail.com>, 2017
-# Robert Wolniak <robert.wolniak@gmail.com>, 2015
+# Robert Wolniak <robert.wolniak@gmail.com>, 2015,2018
 # Sertomas, 2014
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-20 00:10+0000\n"
-"Last-Translator: Rafał Szymański <okavasly@gmail.com>\n"
+"PO-Revision-Date: 2018-04-19 09:01+0000\n"
+"Last-Translator: Robert Wolniak <robert.wolniak@gmail.com>\n"
 "Language-Team: Polish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/pl/)\n"
 "Language: pl\n"
@@ -1158,7 +1158,7 @@ msgstr ""
 
 #: qcsrc/common/gamemodes/gamemode/nexball/weapon.qh:7
 msgid "Ball Stealer"
-msgstr ""
+msgstr "Złodziej Kuli"
 
 #: qcsrc/common/items/item/armor.qh:111
 msgid "Big armor"
@@ -1310,6 +1310,8 @@ msgid ""
 "Kill enemies to freeze them, stand next to frozen teammates to revive them; "
 "freeze all enemies to win"
 msgstr ""
+"Zabijaj przeciwników by ich zamrozić i stój obok członków swojej drużyny by "
+"ich wskrzesić; aby wygrać, zamroź wszystkich wrogów"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Hold the ball to get points for kills"
@@ -1468,6 +1470,8 @@ msgid ""
 "You lost the game!\n"
 "Select \"^1Next Match^7\" on the menu for a rematch!"
 msgstr ""
+"Przegrana meczu!\n"
+"Wybierz w menu opcję \"^1Następny Mecz^7\" po rewanż!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:444
 #: qcsrc/common/minigames/minigame/ttt.qc:325
@@ -1475,16 +1479,18 @@ msgid ""
 "You win!\n"
 "Select \"^1Next Match^7\" on the menu to start a new match!"
 msgstr ""
+"Wygrana!\n"
+"Wybierz w menu opcję \"^1Następny Mecz^7\" by rozpocząć nową grę!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:450
 #: qcsrc/common/minigames/minigame/ttt.qc:331
 msgid "Select \"^1Next Match^7\" on the menu to start a new match!"
-msgstr ""
+msgstr "Wybierz w menu opcję \"^1Następny Mecz^7\" by rozpocząć nową grę!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:451
 #: qcsrc/common/minigames/minigame/ttt.qc:332
 msgid "Wait for your opponent to confirm the rematch"
-msgstr ""
+msgstr "Poczekaj aż twój przeciwnik potwierdzi rewanż."
 
 #: qcsrc/common/minigames/minigame/pp.qc:582
 #: qcsrc/common/minigames/minigame/ttt.qc:665
index ec526d5e35b64187d305a117a1b2087a16b86cc5..b2b27a40ddf04d2d1d045765add430d030d97faf 100644 (file)
@@ -4,17 +4,18 @@
 #
 # Translators:
 # Ivan Paulos Tomé <greylica@gmail.com>, 2016
-# Jean Trindade Pereira <jean_trindade2@hotmail.com>, 2015-2017
+# Jean Trindade Pereira <jean_trindade2@hotmail.com>, 2015-2018
 # Mirio <opivy@hotmail.de>, 2017
 # NotThatPrivate Yes <henriqueferreira2009@gmail.com>, 2015
 # Ricardo Manuel da Cruz Coelho da Silva <ricardo.mccs@gmail.com>, 2015
+# Rui <xymarior@yandex.com>, 2018
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-12-21 15:23+0000\n"
-"Last-Translator: Jean Trindade Pereira <jean_trindade2@hotmail.com>\n"
+"PO-Revision-Date: 2018-05-02 10:54+0000\n"
+"Last-Translator: Rui <xymarior@yandex.com>\n"
 "Language-Team: Portuguese (http://www.transifex.com/team-xonotic/xonotic/"
 "language/pt/)\n"
 "Language: pt\n"
@@ -26,16 +27,16 @@ msgstr ""
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
 msgid "^2Successfully exported to %s! (Note: It's saved in data/data/)\n"
-msgstr "^2Exportado com sucesso para %s! (Nota: Foi salvo em data/data/)\n"
+msgstr "^2Exportado com sucesso para %s! (Nota: foi gravado em data/data/)\n"
 
 #: qcsrc/client/hud/hud_config.qc:243
 #, c-format
 msgid "^1Couldn't write to %s\n"
-msgstr "^1Não foi possível escrever para %s\n"
+msgstr "^1Não foi possível gravar para %s\n"
 
 #: qcsrc/client/hud/panel/chat.qc:82
 msgid "^3Player^7: This is the chat area."
-msgstr "^3Jogador^7: Isto é a área do bate-papo."
+msgstr "^3Jogador^7: isto é a área doe conversação."
 
 #: qcsrc/client/hud/panel/engineinfo.qc:69
 #, c-format
@@ -54,7 +55,7 @@ msgstr "^1Assistindo: ^7%s"
 #: qcsrc/client/hud/panel/infomessages.qc:100
 #, c-format
 msgid "^1Press ^3%s^1 to spectate"
-msgstr "^1Aperte ^3%s^1 para assistir"
+msgstr "^1Pressionar ^3%s^1 para assistir"
 
 #: qcsrc/client/hud/panel/infomessages.qc:100
 #: qcsrc/menu/xonotic/keybinder.qc:40
@@ -64,7 +65,7 @@ msgstr "disparo primário"
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #, c-format
 msgid "^1Press ^3%s^1 or ^3%s^1 for next or previous player"
-msgstr "^1Aperte ^3%s^1 ou ^3%s^1 para o jogador seguinte ou anterior"
+msgstr "^1Pressionar ^3%s^1 ou ^3%s^1 para o jogador seguinte ou anterior"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
@@ -79,12 +80,13 @@ msgstr "arma anterior"
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
 msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
-msgstr "^1Use ^3%s^1 ou ^3%s^1 para alterar a velocidade"
+msgstr "^1Usar ^3%s^1 ou ^3%s^1 para alterar a velocidade"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
 msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
-msgstr "^1Aperte ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmera"
+msgstr ""
+"^1Pressionar ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmara"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
@@ -99,7 +101,7 @@ msgstr "disparo secundário"
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
 msgid "^1Press ^3%s^1 for gamemode info"
-msgstr "^1Aperte ^3%s^1 para ver as informações do modo de jogo"
+msgstr "^1Pressionar ^3%s^1 para ver as informações do modo de jogo"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #: qcsrc/menu/xonotic/keybinder.qc:94
@@ -112,13 +114,13 @@ msgstr "^1A partida já começou"
 
 #: qcsrc/client/hud/panel/infomessages.qc:126
 msgid "^1You have no more lives left"
-msgstr "^1Você não tem mais vidas sobrando"
+msgstr "^1Não tens mais vidas"
 
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
 #, c-format
 msgid "^1Press ^3%s^1 to join"
-msgstr "^1Aperte ^3%s^1 para entrar no jogo"
+msgstr "^1Pressionar ^3%s^1 para entrar no jogo"
 
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
@@ -128,16 +130,16 @@ msgstr "saltar"
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
 msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1A partida iniciará em ^3%d^1 segundo(s)"
+msgstr "^1O jogo vai começar em ^3%d^1 segundo(s)"
 
 #: qcsrc/client/hud/panel/infomessages.qc:145
 msgid "^2Currently in ^1warmup^2 stage!"
-msgstr "^2Atualmente em fase de ^1aquecimento^2!"
+msgstr "^2Neste momento em fase de ^1aquecimento^2!"
 
 #: qcsrc/client/hud/panel/infomessages.qc:160
 #, c-format
 msgid "%sPress ^3%s%s to end warmup"
-msgstr "%sAperte ^3%s%s para terminar o aquecimento"
+msgstr "%sPressionar ^3%s%s para terminar o aquecimento"
 
 #: qcsrc/client/hud/panel/infomessages.qc:160
 #: qcsrc/client/hud/panel/infomessages.qc:162
@@ -149,58 +151,57 @@ msgstr "pronto"
 #: qcsrc/client/hud/panel/infomessages.qc:162
 #, c-format
 msgid "%sPress ^3%s%s once you are ready"
-msgstr "%sAperte ^3%s%s assim que estiver pronto"
+msgstr "%sPressionar ^3%s%s assim que estiveres pronto"
 
 #: qcsrc/client/hud/panel/infomessages.qc:167
 msgid "^2Waiting for others to ready up to end warmup..."
 msgstr ""
-"^2Esperando que os outros jogadores estejam prontos para acabar o "
+"^2Á espera que os outros jogadores estejam prontos para acabar o "
 "aquecimento..."
 
 #: qcsrc/client/hud/panel/infomessages.qc:169
 msgid "^2Waiting for others to ready up..."
-msgstr "^2Esperando que os outros jogadores estejam prontos..."
+msgstr "^2À espera que os outros jogadores estejam prontos..."
 
 #: qcsrc/client/hud/panel/infomessages.qc:175
 #, c-format
 msgid "^2Press ^3%s^2 to end warmup"
-msgstr "^2Aperte ^3%s^2 para terminar o aquecimento"
+msgstr "^2Pressionar ^3%s^2 para terminar o aquecimento"
 
 #: qcsrc/client/hud/panel/infomessages.qc:196
 msgid "Teamnumbers are unbalanced!"
-msgstr "As equipes estão desequilibradas!"
+msgstr "As equipas estão desequilibradas!"
 
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #, c-format
 msgid " Press ^3%s%s to adjust"
-msgstr " Aperte ^3%s%s para ajustar"
+msgstr " Pressiona ^3%s%s para ajustar"
 
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #: qcsrc/menu/xonotic/keybinder.qc:102
 msgid "team menu"
-msgstr "menu de equipe"
+msgstr "menu de equipa"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating this player:"
-msgstr "^1Também estão assistindo a este jogador:"
+msgstr "^1A assistir este jogador:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating you:"
-msgstr "^1Assistindo você:"
+msgstr "^1A assistir a ti:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:225
 msgid "^7Press ^3ESC ^7to show HUD options."
-msgstr "^7Aperte ^3ESC ^7para exibir as opções de HUD."
+msgstr "^7Pressionar ^3ESC ^7para mostrar as opções de interface."
 
 #: qcsrc/client/hud/panel/infomessages.qc:226
 msgid "^3Doubleclick ^7a panel for panel-specific options."
 msgstr ""
-"^3Clique duas vezes ^7em um painel para abrir sua janela de opções "
-"específicas."
+"^3Clica duas vezes ^7num painel para abrir a janela de opções específicas."
 
 #: qcsrc/client/hud/panel/infomessages.qc:227
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3CTRL ^7para desligar teste de colisão, ^3SHIFT ^7e"
+msgstr "^3CTRL ^7para desativar o teste de colisão, ^3SHIFT ^7e"
 
 #: qcsrc/client/hud/panel/infomessages.qc:228
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
@@ -224,7 +225,7 @@ msgstr "Jogador %d"
 #: qcsrc/client/hud/panel/quickmenu.qc:605
 #, c-format
 msgid "Submenu%d"
-msgstr "Submenu%d"
+msgstr "Sub-menu%d"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:610
 #, c-format
@@ -258,12 +259,12 @@ msgstr "Olá / Boa sorte"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:797
 msgid "QMCMD^hi / good luck and have fun"
-msgstr "Olá / Boa sorte e divirta-se"
+msgstr "Olá / Boa sorte e diverte-te"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:802
 #: qcsrc/client/hud/panel/quickmenu.qc:818
 msgid "QMCMD^Team chat"
-msgstr "Bate-papo de equipe"
+msgstr "Conversação da equipa"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:803
 msgid "QMCMD^quad soon"
@@ -271,19 +272,19 @@ msgstr "Quad em breve"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item %x^7 (l:%y^7)"
-msgstr "Item livre %x^7 (l:%y^7)"
+msgstr "Item grátis %x^7 (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item, icon"
-msgstr "Item livre, ícone"
+msgstr "Item grátis, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item (l:%l^7)"
-msgstr "Item pego (l:%l^7)"
+msgstr "Pegou no item (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item, icon"
-msgstr "Item pego, ícone"
+msgstr "Pegou no item, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:806
 msgid "QMCMD^negative"
@@ -319,27 +320,27 @@ msgstr "Bandeira avistada, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
-msgstr "Defendendo (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "A defender (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:811
 msgid "QMCMD^defending, icon"
-msgstr "Defendendo, ícone"
+msgstr "A defender, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
-msgstr "Patrulhando (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "A patrulhar (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:812
 msgid "QMCMD^roaming, icon"
-msgstr "Patrulhando, ícone"
+msgstr "A patrulhar, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
-msgstr "Atacando (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "A atacar (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:813
 msgid "QMCMD^attacking, icon"
-msgstr "Atacando, ícone"
+msgstr "A atacar, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier (l:%y^7)"
@@ -364,7 +365,7 @@ msgstr "Largar arma, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr "Arma solta %w^7 (l:%l^7)"
+msgstr "Arma largada %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -386,11 +387,11 @@ msgstr "Configurações"
 #: qcsrc/client/hud/panel/quickmenu.qc:824
 #: qcsrc/client/hud/panel/quickmenu.qc:831
 msgid "QMCMD^View/HUD settings"
-msgstr "Configurações de Exibição/HUD"
+msgstr "Configurações de Visualização/Interface"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:825
 msgid "QMCMD^3rd person view"
-msgstr "Visão em 3ª pessoa"
+msgstr "Visão na 3ª pessoa"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:826
 msgid "QMCMD^Player models like mine"
@@ -398,7 +399,7 @@ msgstr "Modelos de jogadores como o meu"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:827
 msgid "QMCMD^Names above players"
-msgstr "Nomes sobre jogadores"
+msgstr "Nomes por cima dos jogadores"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:828
 msgid "QMCMD^Crosshair per weapon"
@@ -419,16 +420,16 @@ msgstr "Configurações de som"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:834
 msgid "QMCMD^Hit sound"
-msgstr "Som de acerto"
+msgstr "Som de acertar"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:835
 msgid "QMCMD^Chat sound"
-msgstr "Som do bate-papo"
+msgstr "Som da conversação"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:840
 #: qcsrc/client/hud/panel/quickmenu.qc:844
 msgid "QMCMD^Spectator camera"
-msgstr "Câmera de espectador"
+msgstr "Câmara de espetador"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:841
 msgid "QMCMD^1st person"
@@ -436,16 +437,16 @@ msgstr "1ª pessoa"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:842
 msgid "QMCMD^3rd person around player"
-msgstr "3ª pessoa em volta do jogador"
+msgstr "3ª pessoa à volta do jogador"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:843
 msgid "QMCMD^3rd person behind"
-msgstr "3ª pessoa traseira"
+msgstr "3ª pessoa por trás"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:849
 #: qcsrc/client/hud/panel/quickmenu.qc:854
 msgid "QMCMD^Observer camera"
-msgstr "Câmera de observador"
+msgstr "Câmara de observador"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:850
 msgid "QMCMD^Increase speed"
@@ -465,11 +466,11 @@ msgstr "Colisão com paredes ligada"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:857
 msgid "QMCMD^Fullscreen"
-msgstr "Tela cheia"
+msgstr "Ecrã inteiro"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:859
 msgid "QMCMD^Translate chat messages"
-msgstr "Traduzir mensagens do bate-papo"
+msgstr "Traduzir mensagens da conversação"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:862
 #: qcsrc/client/hud/panel/quickmenu.qc:872
@@ -490,11 +491,11 @@ msgstr "Reduzir tempo de partida"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:868
 msgid "QMCMD^Extend match time"
-msgstr "Estender tempo de partida"
+msgstr "Aumentar tempo de partida"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:871
 msgid "QMCMD^Shuffle teams"
-msgstr "Misturar as equipes"
+msgstr "Misturar as equipas"
 
 #: qcsrc/client/hud/panel/racetimer.qc:37
 #, c-format
@@ -582,7 +583,7 @@ msgstr "pbndvítimas"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:89
 msgid "SCO^goals"
-msgstr "gols"
+msgstr "golos"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:90
 msgid "SCO^kckills"
@@ -684,7 +685,8 @@ msgstr "ticks"
 msgid ""
 "You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
 msgstr ""
-"Você pode modificar o placar usando o comando ^2scoreboard_columns_set.\n"
+"Podes alterar o placar de pontuações utilizando o comando "
+"^2scoreboard_columns_set.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:296
 msgid "^3|---------------------------------------------------------------|\n"
@@ -692,7 +694,7 @@ msgstr "^3|---------------------------------------------------------------|\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:297
 msgid "Usage:\n"
-msgstr "Uso:\n"
+msgstr "Utilização:\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:298
 msgid "^2scoreboard_columns_set default\n"
@@ -705,12 +707,12 @@ msgstr "^2scoreboard_columns_set ^7campo1 campo2...\n"
 #: qcsrc/client/hud/panel/scoreboard.qc:300
 msgid "The following field names are recognized (case insensitive):\n"
 msgstr ""
-"Os seguintes nomes de campos são reconhecidos (maiúsculas/minúsculas não são "
-"distintas):\n"
+"Os seguintes nomes de campos são reconhecidos (insensível a maiúsculas e "
+"minúsculas):\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:301
 msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
-msgstr "Você pode usar um ^3|^7 para iniciar os campos alinhados à direita.\n"
+msgstr "Podes usar um ^3|^7 para iniciar os campos alinhados à direita.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:304
 msgid "^3name^7 or ^3nick^7             Name of a player\n"
@@ -765,16 +767,16 @@ msgid ""
 "^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was "
 "captured\n"
 msgstr ""
-"^3capturas^7 Quão frequente uma bandeira (CTF) ou uma chave (KeyHunt) foi "
-"capturada\n"
+"^3capturas^7 Quão frequente uma bandeira (CTF) ou uma chave (Caça a Chaves) "
+"foi capturada\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:317
 msgid ""
 "^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a "
 "ball (Keepaway) was picked up\n"
 msgstr ""
-"^3coletas^7. Quão frequente uma bandeira (CTF), uma chave (KeyHunt) ou uma "
-"bola (Keepaway) foi coletada\n"
+"^3coletas^7. Quão frequente uma bandeira (CTF), uma chave (Caça a Chaves) ou "
+"uma bola (Keepaway) foi recolhida\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:318
 msgid "^3captime^7                  Time of fastest cap (CTF)\n"
@@ -787,11 +789,11 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
-msgstr "^3retornos^7 Número de bandeiras retomadas\n"
+msgstr "^3retornos^7 Número de bandeiras retornadas\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:321
 msgid "^3drops^7                    Number of flag drops\n"
-msgstr "^3quedas^7 Número de bandeiras que foram soltas\n"
+msgstr "^3quedas^7 Número de bandeiras que foram largadas\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:322
 msgid "^3lives^7                    Number of lives (LMS)\n"
@@ -862,12 +864,12 @@ msgid ""
 "field to show all fields available for the current game mode.\n"
 "\n"
 msgstr ""
-"Antes dos campos de digitação, você pode inserir um sinal de + ou -, e usar "
-"uma lista de modos de jogo separada por vírgulas.\n"
-"Insira barras para fazer com que os campos sejam mostrados somente nesses "
+"Antes dos campos de digitação, podes inserir um sinal de + ou -, e usar uma "
+"lista de modos de jogo separada por vírgulas.\n"
+"Insere barras para fazer com que os campos sejam mostrados apenas nesses "
 "modos de jogo ou em todos os modos exceto os especificados.\n"
-"Você também pode especificar a palavra 'all' como um campo para mostrar "
-"todos os campos disponíveis para o modo de jogo atual.\n"
+"Também podes especificar a palavra 'all' como um campo para mostrar todos os "
+"campos disponíveis para o modo de jogo atual.\n"
 "\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:343
@@ -876,8 +878,8 @@ msgid ""
 "include/exclude ALL teams/noteams game modes.\n"
 "\n"
 msgstr ""
-"Os nomes especiais de modos de jogo 'teams' e 'noteams' podem ser usados\n"
-"para incluir/excluir TODOS os modos de jogo de equipe/sem equipe\n"
+"Podem ser usados os nomes especiais de modos de jogo 'teams' e 'noteams'\n"
+"para incluir/excluir TODOS os modos de jogo de equipa/sem equipa\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:346
 msgid "Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"
@@ -889,7 +891,7 @@ msgid ""
 "will display name, ping and pl aligned to the left, and the fields\n"
 "right of the vertical bar aligned to the right.\n"
 msgstr ""
-"irá exibir nome, ping e pp alinhados à esquerda e os campos\n"
+"irá mostrar o nome, ping e pp alinhados à esquerda e os campos\n"
 "à direita da barra vertical alinhados à direita.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:349
@@ -897,7 +899,7 @@ msgid ""
 "'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
 "other gamemodes except DM.\n"
 msgstr ""
-"'field3' só será exibido em CTF e 'field4' será exibido em todos\n"
+"'field3' só será mostrado em CTF e 'field4' será mostrado em todos\n"
 "os outros modos de jogo, exceto DM.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:611
@@ -914,7 +916,7 @@ msgstr "N/A"
 #: qcsrc/client/hud/panel/scoreboard.qc:1156
 #, c-format
 msgid "Accuracy stats (average %d%%)"
-msgstr "Estatísticas de precisão (média %d%%)"
+msgstr "Estatísticas de pontaria (média %d%%)"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1295
 msgid "Map stats:"
@@ -930,7 +932,7 @@ msgstr "Segredos encontrados:"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Capture time rankings"
-msgstr "Classificações de tempo de capturas"
+msgstr "Classificações de tempo de captura"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Rankings"
@@ -939,12 +941,12 @@ msgstr "Classificações"
 #: qcsrc/client/hud/panel/scoreboard.qc:1519
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
 msgid "Scoreboard"
-msgstr "Placar"
+msgstr "Placar de pontuações"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1584
 #, c-format
 msgid "Speed award: %d%s ^7(%s^7)"
-msgstr "Prêmio de velocidade: %d%s ^7(%s^7)"
+msgstr "Prémio de velocidade: %d%s ^7(%s^7)"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1588
 #, c-format
@@ -954,18 +956,18 @@ msgstr "O mais rápido de todos: %d%s ^7(%s^7)"
 #: qcsrc/client/hud/panel/scoreboard.qc:1604
 #, c-format
 msgid "Spectators"
-msgstr "Espectadores"
+msgstr "Espetadores"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1619
 #, c-format
 msgid "playing ^3%s^7 on ^2%s^7"
-msgstr "jogando ^3%s^7 em ^2%s^7"
+msgstr "a jogar ^3%s^7 em ^2%s^7"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1626
 #: qcsrc/client/hud/panel/scoreboard.qc:1631
 #, c-format
 msgid " for up to ^1%1.0f minutes^7"
-msgstr " por até ^1%1.0f minutos^7"
+msgstr " até ^1%1.0f minutos^7"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1635
 #: qcsrc/client/hud/panel/scoreboard.qc:1654
@@ -1006,33 +1008,33 @@ msgstr "^1Ressurgindo em ^3%s^1..."
 #: qcsrc/client/hud/panel/scoreboard.qc:1698
 #, c-format
 msgid "You are dead, wait ^3%s^7 before respawning"
-msgstr "Você morreu. Espere ^3%s^7 antes de ressurgir"
+msgstr "Morreste. Espera ^3%s^7 antes de ressurgir"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1707
 #, c-format
 msgid "You are dead, press ^2%s^7 to respawn"
-msgstr "Você morreu. Aperte ^2%s^7 para ressurgir"
+msgstr "Morreste. Pressiona ^2%s^7 para ressurgir"
 
 #: qcsrc/client/hud/panel/vote.qc:24
 msgid "^1You must answer before entering hud configure mode\n"
 msgstr ""
-"^1Você tem que responder antes de entrar no modo de configuração do HUD\n"
+"^1Tens que responder antes de entrar no modo de configuração da interface\n"
 
 #: qcsrc/client/hud/panel/vote.qc:29
 msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
-msgstr "^2Nome ^7em vez de \"^1Jogador anônimo^7\" nas estatísticas"
+msgstr "^2Nome ^7em vez de \"^1Jogador anónimo^7\" nas estatísticas"
 
 #: qcsrc/client/hud/panel/vote.qc:115
 msgid "A vote has been called for:"
-msgstr "Uma votação foi iniciada para:"
+msgstr "Foi iniciada uma votação para:"
 
 #: qcsrc/client/hud/panel/vote.qc:117
 msgid "Allow servers to store and display your name?"
-msgstr "Permitir que servidores armazenem e mostrem o seu nome?"
+msgstr "Permitir que os servidores armazenem e mostrem o teu nome?"
 
 #: qcsrc/client/hud/panel/vote.qc:121
 msgid "^1Configure the HUD"
-msgstr "^1Configurar o HUD"
+msgstr "^1Configurar a Interface"
 
 #: qcsrc/client/hud/panel/vote.qc:125 qcsrc/menu/xonotic/dialog_firstrun.qc:82
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:18
@@ -1056,7 +1058,7 @@ msgstr "Não"
 
 #: qcsrc/client/hud/panel/weapons.qc:530
 msgid "Out of ammo"
-msgstr "Sem munição"
+msgstr "Sem munições"
 
 #: qcsrc/client/hud/panel/weapons.qc:534
 msgid "Don't have"
@@ -1110,7 +1112,7 @@ msgstr "Decidir o modo de jogo"
 
 #: qcsrc/client/mapvoting.qc:365
 msgid "Vote for a map"
-msgstr "Vote em um mapa"
+msgstr "Vota num mapa"
 
 #: qcsrc/client/mapvoting.qc:382
 #, c-format
@@ -1120,20 +1122,19 @@ msgstr "Faltam %d segundos"
 #: qcsrc/client/mapvoting.qc:497
 msgid ""
 "mv_mapdownload: ^3You're not supposed to use this command on your own!\n"
-msgstr "mv_mapdownload: ^3Você não pode usar esse comando para si próprio!\n"
+msgstr "mv_mapdownload: ^3Não podes usar esse comando para ti próprio!\n"
 
 #: qcsrc/client/mapvoting.qc:507
 msgid "^1Error:^7 Couldn't find pak index.\n"
-msgstr "^1Erro:^7 Não foi possível encontrar o índice do pak.\n"
+msgstr "^1Erro:^7 não foi possível encontrar o índice do pak.\n"
 
 #: qcsrc/client/mapvoting.qc:516
 msgid "Requesting preview...\n"
-msgstr "Solicitando previsão...\n"
+msgstr "A pedir a pré-visualização...\n"
 
 #: qcsrc/client/miscfunctions.qc:109
 msgid "Trying to remove a team which is not in the teamlist!"
-msgstr ""
-"Você está tentando remover uma equipe que não está na lista de equipes!"
+msgstr "Estás a tentar remover uma equipa que não está na lista de equipas!"
 
 #: qcsrc/client/view.qc:1380
 msgid "Nade timer"
@@ -1154,7 +1155,7 @@ msgstr "erro ao criar curl handle\n"
 #: qcsrc/common/command/generic.qc:403
 msgid "Notification restart command only works with cl_cmd and sv_cmd.\n"
 msgstr ""
-"Comando de reinício de notificação funciona apenas com cl_cmd e sv_cmd.\n"
+"O comando de reinício de notificação funciona apenas com cl_cmd e sv_cmd.\n"
 
 #: qcsrc/common/gamemodes/gamemode/nexball/weapon.qh:7
 msgid "Ball Stealer"
@@ -1195,7 +1196,7 @@ msgstr "Escudo"
 #: qcsrc/common/mapinfo.qc:639
 #, no-c-format
 msgid "@!#%'n Tuba Throwing"
-msgstr "@!#%'n Tuba Throwing"
+msgstr "@!#%'n Atirar da Tuba"
 
 #: qcsrc/common/mapinfo.qh:99
 msgid "Deathmatch"
@@ -1203,15 +1204,15 @@ msgstr "Mata-mata"
 
 #: qcsrc/common/mapinfo.qh:99
 msgid "Score as many frags as you can"
-msgstr "Consiga o máximo de execuções que puder"
+msgstr "Consegue o máximo de execuções que puderes"
 
 #: qcsrc/common/mapinfo.qh:111
 msgid "Last Man Standing"
-msgstr "Last Man Standing"
+msgstr "Último Homem de Pé"
 
 #: qcsrc/common/mapinfo.qh:111
 msgid "Survive and kill until the enemies have no lives left"
-msgstr "Sobreviva e mate até que os inimigos não tenham vidas sobrando"
+msgstr "Sobrevive e mata até que os inimigos não tenham mais vidas"
 
 #: qcsrc/common/mapinfo.qh:126
 msgid "Race"
@@ -1219,7 +1220,7 @@ msgstr "Corrida"
 
 #: qcsrc/common/mapinfo.qh:126
 msgid "Race against other players to the finish line"
-msgstr "Corra contra outros jogadores até a linha de chegada"
+msgstr "Corra contra os outros jogadores até à linha de chegada"
 
 #: qcsrc/common/mapinfo.qh:160
 msgid "Race CTS"
@@ -1227,111 +1228,113 @@ msgstr "Corrida CTS"
 
 #: qcsrc/common/mapinfo.qh:160
 msgid "Race for fastest time."
-msgstr "Corra pelo melhor tempo."
+msgstr "Corre pelo melhor tempo."
 
 #: qcsrc/common/mapinfo.qh:184
 msgid "Help your team score the most frags against the enemy team"
-msgstr "Ajude sua equipe a conseguir mais execuções do que a equipe inimiga"
+msgstr ""
+"Ajuda a tua equipa a conseguir mais execuções do que a equipa do inimigo"
 
 #: qcsrc/common/mapinfo.qh:184
 msgid "Team Deathmatch"
-msgstr "Mata-mata por Equipe"
+msgstr "Mata-mata por Equipa"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid "Capture the Flag"
-msgstr "Capture a Bandeira"
+msgstr "Captura a Bandeira"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid ""
 "Find and bring the enemy flag to your base to capture it, defend your base "
 "from the other team"
 msgstr ""
-"Encontre e retorne a bandeira inimiga à sua base para capturá-la e defenda "
-"sua base da equipe oponente"
+"Encontra e retorna a bandeira inimiga à tua base para capturá-la e defende a "
+"tua base da equipa oponente"
 
 #: qcsrc/common/mapinfo.qh:249
 msgid "Clan Arena"
-msgstr "Clan Arena"
+msgstr "Clã Arena"
 
 #: qcsrc/common/mapinfo.qh:249
 msgid "Kill all enemy teammates to win the round"
-msgstr "Mate todos os inimigos para vencer a rodada"
+msgstr "Mata todos os inimigos para vencer a rodada"
 
 #: qcsrc/common/mapinfo.qh:287
 msgid "Capture and defend all the control points to win"
-msgstr "Capture e defenda todos os pontos de controle para vencer"
+msgstr "Captura e defende todos os pontos de controlo para vencer"
 
 #: qcsrc/common/mapinfo.qh:287
 msgid "Domination"
-msgstr "Domination"
+msgstr "Dominação"
 
 #: qcsrc/common/mapinfo.qh:319
 msgid "Gather all the keys to win the round"
-msgstr "Colete todas as chaves para vencer a rodada"
+msgstr "Recolhe todas as chaves para vencer a rodada"
 
 #: qcsrc/common/mapinfo.qh:319
 msgid "Key Hunt"
-msgstr "Key Hunt"
+msgstr "Caça as Chaves"
 
 #: qcsrc/common/mapinfo.qh:353
 msgid "Assault"
-msgstr "Assault"
+msgstr "Assalto"
 
 #: qcsrc/common/mapinfo.qh:353
 msgid ""
 "Destroy obstacles to find and destroy the enemy power core before time runs "
 "out"
 msgstr ""
-"Destrua obstáculos para encontrar e destruir o núcleo de poder inimigo antes "
+"Destrói obstáculos para encontrar e destruir o núcleo de poder inimigo antes "
 "que o tempo acabe"
 
 #: qcsrc/common/mapinfo.qh:371
 msgid "Capture control points to reach and destroy the enemy generator"
-msgstr "Capture pontos de controle para alcançar e destruir o gerador inimigo"
+msgstr ""
+"Captura os pontos de controlo para alcançar e destruir o gerador inimigo"
 
 #: qcsrc/common/mapinfo.qh:371
 msgid "Onslaught"
-msgstr "Onslaught"
+msgstr "Massacre"
 
 #: qcsrc/common/mapinfo.qh:387
 msgid "Nexball"
-msgstr "Nexball"
+msgstr "Bola Nex"
 
 #: qcsrc/common/mapinfo.qh:387
 msgid "Shoot and kick the ball into the enemies goal, keep your goal clean"
-msgstr "Atire e chute a bola no gol inimigo e mantenha seu gol limpo"
+msgstr "Atira e chuta a bola na baliza do inimigo e mantém a tua baliza limpa"
 
 #: qcsrc/common/mapinfo.qh:408
 msgid "Freeze Tag"
-msgstr "Freeze Tag"
+msgstr "Congela"
 
 #: qcsrc/common/mapinfo.qh:408
 msgid ""
 "Kill enemies to freeze them, stand next to frozen teammates to revive them; "
 "freeze all enemies to win"
 msgstr ""
-"Mate inimigos para congelá-los. Fique perto de colegas para descongelá-los; "
-"congele todos os inimigos para vencer"
+"Mata os inimigos para congelá-los. Fica perto de colegas para descongelá-"
+"los; congela todos os inimigos para venceres"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Hold the ball to get points for kills"
-msgstr "Segure a bola para ganhar pontos por cada jogador aniquilado"
+msgstr "Segura a bola para ganhar pontos por cada jogador aniquilado"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Keepaway"
-msgstr "Keepaway"
+msgstr ""
 
 #: qcsrc/common/mapinfo.qh:461
 msgid "Invasion"
-msgstr "Invasion"
+msgstr "Invasão"
 
 #: qcsrc/common/mapinfo.qh:461
 msgid "Survive against waves of monsters"
-msgstr "Sobreviva contra ondas de monstros"
+msgstr "Sobrevive contra ondas de monstros"
 
 #: qcsrc/common/minigames/cl_minigames.qc:383
 msgid "It's your turn"
-msgstr "É a sua vez"
+msgstr "É a tua vez"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:331
 #: qcsrc/menu/xonotic/dialog_quit.qh:6
@@ -1361,29 +1364,29 @@ msgstr "Entrar"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:489
 msgid "Minigames"
-msgstr "Minijogos"
+msgstr "Mini-jogos"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1168
 msgid "Better luck next time!"
-msgstr "Mais sorte da próxima vez!"
+msgstr "Talvez tenhas mais sorte da próxima vez!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1172
 msgid "Tubular! Press \"Next Level\" to continue!"
-msgstr "Tubular! Clique em \"Próximo Mapa\" para continuar!"
+msgstr "Tubular! Clica em \"Próximo Mapa\" para continuar!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1174
 msgid "Wicked! Press \"Next Level\" to continue!"
-msgstr "Enfeitiçado! Clique em \"Próximo Mapa\" para continuar!"
+msgstr "Enfeitiçado! Clica em \"Próximo Mapa\" para continuar!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1177
 msgid "Press the space bar to change your currently selected tile"
 msgstr ""
-"Aperte a barra de espaço para alterar a sua imagem de equipe atualmente "
-"selecionada"
+"Carrega na tecla de barra de espaços para alterar a tua imagem da equipa "
+"atualmente selecionada"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1180
 msgid "Push the boulders onto the targets"
-msgstr "Empurre os pedregulhos em direção aos alvos"
+msgstr "Empurra os pedregulhos em direção aos alvos"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1404
 msgid "Next Level"
@@ -1400,7 +1403,7 @@ msgstr "Editor"
 #: qcsrc/common/minigames/minigame/bd.qc:1407
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:37
 msgid "Save"
-msgstr "Salvar"
+msgstr "Gravar"
 
 #: qcsrc/common/minigames/minigame/c4.qc:373
 #: qcsrc/common/minigames/minigame/pp.qc:438
@@ -1411,43 +1414,42 @@ msgstr "Empate"
 #: qcsrc/common/minigames/minigame/c4.qc:378
 #: qcsrc/common/minigames/minigame/nmm.qc:601
 msgid "You lost the game!"
-msgstr "Você perdeu o jogo!"
+msgstr "Perdeste o jogo!"
 
 #: qcsrc/common/minigames/minigame/c4.qc:379
 #: qcsrc/common/minigames/minigame/nmm.qc:602
 msgid "You win!"
-msgstr "Você venceu!"
+msgstr "Venceste!"
 
 #: qcsrc/common/minigames/minigame/c4.qc:383
 #: qcsrc/common/minigames/minigame/nmm.qc:606
 #: qcsrc/common/minigames/minigame/pp.qc:455
 #: qcsrc/common/minigames/minigame/ttt.qc:336
 msgid "Wait for your opponent to make their move"
-msgstr "Espere o seu oponente terminar a vez dele"
+msgstr "Espera que o teu oponente termine a vez dele"
 
 #: qcsrc/common/minigames/minigame/c4.qc:386
 #: qcsrc/common/minigames/minigame/nmm.qc:608
 #: qcsrc/common/minigames/minigame/pp.qc:458
 #: qcsrc/common/minigames/minigame/ttt.qc:339
 msgid "Click on the game board to place your piece"
-msgstr "Clique no tabuleiro de jogo para posicionar sua peça"
+msgstr "Clica no tabuleiro de jogo para posicionar a tua peça"
 
 #: qcsrc/common/minigames/minigame/nmm.qc:610
 msgid ""
 "You can select one of your pieces to move it in one of the surrounding places"
 msgstr ""
-"Você pode selecionar uma de suas peças para movê-la para um dos lugares ao "
-"redor"
+"Podes selecionar uma das tuas peças para movê-la para um dos lugares em redor"
 
 #: qcsrc/common/minigames/minigame/nmm.qc:612
 msgid "You can select one of your pieces to move it anywhere on the board"
 msgstr ""
-"Você pode selecionar uma de suas peças para movê-la para qualquer lugar no "
+"Podes selecionar uma das tuas peças para movê-la para qualquer lugar no "
 "tabuleiro"
 
 #: qcsrc/common/minigames/minigame/nmm.qc:614
 msgid "You can take one of the opponent's pieces"
-msgstr "Você pode tomar uma das peças do seu oponente"
+msgstr "Podes pegar numa das peças do teu oponente"
 
 #: qcsrc/common/minigames/minigame/pong.qc:570
 #: qcsrc/common/minigames/minigame/ttt.qc:299
@@ -1457,7 +1459,7 @@ msgstr "IA"
 #: qcsrc/common/minigames/minigame/pong.qc:587
 msgid "Press ^1Start Match^7 to start the match with the current players"
 msgstr ""
-"Aperte ^1Iniciar Partida^7 para iniciar a partida com os jogadores atuais"
+"Pressiona ^1Iniciar Partida^7 para iniciar a partida com os jogadores atuais"
 
 #: qcsrc/common/minigames/minigame/pong.qc:651
 msgid "Start Match"
@@ -1465,11 +1467,11 @@ msgstr "Iniciar Partida"
 
 #: qcsrc/common/minigames/minigame/pong.qc:652
 msgid "Add AI player"
-msgstr "Adicionar bot"
+msgstr "Adicionar robô"
 
 #: qcsrc/common/minigames/minigame/pong.qc:653
 msgid "Remove AI player"
-msgstr "Remover bot"
+msgstr "Remover robô"
 
 #: qcsrc/common/minigames/minigame/pp.qc:443
 #: qcsrc/common/minigames/minigame/ttt.qc:324
@@ -1477,8 +1479,8 @@ msgid ""
 "You lost the game!\n"
 "Select \"^1Next Match^7\" on the menu for a rematch!"
 msgstr ""
-"Você perdeu o jogo!\n"
-"Selecione \"^1Próxima Partida^7\" no menu para uma revanche!"
+"Perdeste o jogo!\n"
+"Seleciona \"^1Próxima Partida^7\" no menu para te vingares!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:444
 #: qcsrc/common/minigames/minigame/ttt.qc:325
@@ -1486,19 +1488,19 @@ msgid ""
 "You win!\n"
 "Select \"^1Next Match^7\" on the menu to start a new match!"
 msgstr ""
-"Você venceu!\n"
-"Selecione \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
+"Venceste!\n"
+"Seleciona \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:450
 #: qcsrc/common/minigames/minigame/ttt.qc:331
 msgid "Select \"^1Next Match^7\" on the menu to start a new match!"
 msgstr ""
-"Selecione \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
+"Seleciona \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
 
 #: qcsrc/common/minigames/minigame/pp.qc:451
 #: qcsrc/common/minigames/minigame/ttt.qc:332
 msgid "Wait for your opponent to confirm the rematch"
-msgstr "Espere o seu oponente confirmar a revanche"
+msgstr "Espera que o teu oponente confirme a vingança"
 
 #: qcsrc/common/minigames/minigame/pp.qc:582
 #: qcsrc/common/minigames/minigame/ttt.qc:665
@@ -1516,11 +1518,11 @@ msgstr "Não há mais movimentos válidos"
 
 #: qcsrc/common/minigames/minigame/ps.qc:491
 msgid "Well done, you win!"
-msgstr "Bom trabalho, você venceu!"
+msgstr "Bom trabalho, venceste!"
 
 #: qcsrc/common/minigames/minigame/ps.qc:494
 msgid "Jump a piece over another to capture it"
-msgstr "Faça uma peça saltar sobre outra para capturá-la"
+msgstr "Faz com que uma peça salte sobre outra para capturá-la"
 
 #: qcsrc/common/minigames/minigame/ttt.qc:666
 msgid "Single Player"
@@ -1538,7 +1540,7 @@ msgstr "Prego de mago"
 #: qcsrc/common/monsters/monster/shambler.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:17
 msgid "Shambler"
-msgstr "Shambler"
+msgstr ""
 
 #: qcsrc/common/monsters/monster/spider.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:16
@@ -1552,11 +1554,11 @@ msgstr "Ataque da Aranha"
 #: qcsrc/common/monsters/monster/wyvern.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:19
 msgid "Wyvern"
-msgstr "Wyvern"
+msgstr ""
 
 #: qcsrc/common/monsters/monster/wyvern.qh:28
 msgid "Wyvern attack"
-msgstr "Ataque do Wyvern"
+msgstr ""
 
 #: qcsrc/common/monsters/monster/zombie.qh:17
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:15
@@ -1565,7 +1567,7 @@ msgstr "Zumbi"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:15
 msgid "Ammo"
-msgstr "Munição"
+msgstr "Munições"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:24
 msgid "Resistance"
@@ -1616,7 +1618,7 @@ msgstr "Trocador"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:120
 msgid "Magnet"
-msgstr "Ímã"
+msgstr "Íman"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:128
 msgid "Luck"
@@ -1628,7 +1630,7 @@ msgstr "Voo"
 
 #: qcsrc/common/mutators/mutator/buffs/buffs.qh:7
 msgid "Buff"
-msgstr "Bônus"
+msgstr "Bónus"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
 msgid "Damage text"
@@ -1636,19 +1638,19 @@ msgstr "Texto de dano"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:18
 msgid "Draw damage numbers"
-msgstr "Exibir números de dano"
+msgstr "Mostrar números de dano"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:20
 msgid "Font size minimum:"
-msgstr "Tamanho da fonte mínimo:"
+msgstr "Tamanho mínimo da fonte:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:25
 msgid "Font size maximum:"
-msgstr "Tamanho da fonte máximo:"
+msgstr "Tamanho máximo da fonte:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:30
 msgid "Accumulate range:"
-msgstr "Alcance de acúmulo:"
+msgstr "Alcance de acumulação:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:35
 msgid "Lifetime:"
@@ -1666,7 +1668,7 @@ msgstr "Cor:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
 msgid "Draw damage numbers for friendly fire"
-msgstr "Exibir números de dano para fogo amigo"
+msgstr "Mostrar números de dano para fogo amigo"
 
 #: qcsrc/common/mutators/mutator/instagib/items.qh:56
 msgid "Extra life"
@@ -1710,11 +1712,11 @@ msgstr "Granada"
 
 #: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
 msgid "Heavy Machine Gun"
-msgstr "Heavy Machine Gun"
+msgstr "Metralhadora Pesada"
 
 #: qcsrc/common/mutators/mutator/overkill/rpc.qh:17
 msgid "Rocket Propelled Chainsaw"
-msgstr "Rocket Propelled Chainsaw"
+msgstr ""
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:3
 msgid "Waypoint"
@@ -1742,7 +1744,7 @@ msgstr "Item"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:12
 msgid "Checkpoint"
-msgstr "Ponto de checagem"
+msgstr "Ponto de verificação"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:13
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
@@ -1769,7 +1771,7 @@ msgstr "Empurrar"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:21
 msgid "Flag carrier"
-msgstr "Portador de bandeiras"
+msgstr "Portador de bandeira"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:22
 msgid "Enemy carrier"
@@ -1801,7 +1803,7 @@ msgstr "Base rosa"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:29
 msgid "Return flag here"
-msgstr "Traga a bandeira para cá"
+msgstr "Traz a bandeira para cá"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:31
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:32
@@ -1812,7 +1814,7 @@ msgstr "Traga a bandeira para cá"
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:52
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:53
 msgid "Control point"
-msgstr "Ponto de controle"
+msgstr "Ponto de controlo"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:37
 msgid "Dropped key"
@@ -1824,11 +1826,11 @@ msgstr "Chave largada"
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:42
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:43
 msgid "Key carrier"
-msgstr "Portador de chaves"
+msgstr "Portador de chave"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:39
 msgid "Run here"
-msgstr "Corra aqui"
+msgstr "Corre para aqui"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:45
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:48
@@ -1837,11 +1839,11 @@ msgstr "Bola"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:46
 msgid "Ball carrier"
-msgstr "Portador de bolas"
+msgstr "Portador de bola"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:49
 msgid "Goal"
-msgstr "Gol"
+msgstr "Golo"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:54
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:55
@@ -1876,7 +1878,7 @@ msgstr "Spam"
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:655
 #, c-format
 msgid "%s needing help!"
-msgstr "%s precisando de ajuda!"
+msgstr "%s a precisar de ajuda!"
 
 #: qcsrc/common/net_notice.qc:87
 msgid "^1Server notices:"
@@ -1885,7 +1887,7 @@ msgstr "^1Avisos do servidor:"
 #: qcsrc/common/notifications/all.inc:239
 msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
 msgstr ""
-"^F4NOTA: ^BGMensagens no bate-papo de espectador não serão enviadas aos "
+"^F4NOTA: ^BGas mensagens na conversação de espetador não serão enviadas aos "
 "jogadores durante a partida"
 
 #: qcsrc/common/notifications/all.inc:241
@@ -1919,7 +1921,7 @@ msgid ""
 "^BG%s^BG's previous record of ^F1%s^BG seconds"
 msgstr ""
 "^BG%s^BG capturou a bandeira ^TC^TT^BG em ^F2%s^BG segundos, não quebrando o "
-"record anterior de ^BG%s^BG de ^F1%s^BG segundos"
+"recorde anterior de ^BG%s^BG de ^F1%s^BG segundos"
 
 #: qcsrc/common/notifications/all.inc:246
 msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
@@ -1949,12 +1951,11 @@ msgstr "^BGA bandeira caiu na base e retornou sozinha"
 msgid ""
 "^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to "
 "base"
-msgstr ""
-"^BGA bandeira ^TC^TT^BG caiu em algum lugar inacessível e retornou à base"
+msgstr "^BGA bandeira ^TC^TT^BG caiu num lugar inacessível e retornou à base"
 
 #: qcsrc/common/notifications/all.inc:253
 msgid "^BGThe flag fell somewhere it couldn't be reached and returned to base"
-msgstr "^BGA bandeira caiu em algum lugar inacessível e retornou à base"
+msgstr "^BGA bandeira caiu num lugar inacessível e retornou à base"
 
 #: qcsrc/common/notifications/all.inc:254
 #, c-format
@@ -1999,7 +2000,7 @@ msgstr "^BG%s^BG pegou a bandeira ^TC^TT^BG"
 #: qcsrc/common/notifications/all.inc:261
 #, c-format
 msgid "^BG%s^BG got the flag"
-msgstr "^BG%s^BG pegou a bandeira"
+msgstr "^BG%s^BG pegou na bandeira"
 
 #: qcsrc/common/notifications/all.inc:262
 #: qcsrc/common/notifications/all.inc:263
@@ -2011,35 +2012,35 @@ msgstr "^BG%s^BG retornou a bandeira ^TC^TT^BG"
 #: qcsrc/common/notifications/all.inc:553
 #, c-format
 msgid "^F2Throwing coin... Result: %s^F2!"
-msgstr "^F2Atirando moeda... Resultado: %s^F2!"
+msgstr "^F2A atirar a moeda... Resultado: %s^F2!"
 
 #: qcsrc/common/notifications/all.inc:267
 msgid "^BGYou don't have any fuel for the ^F1Jetpack"
-msgstr "^BGVocê está sem combustível para a ^F1Mochila a Jato"
+msgstr "^BGEstás sem combustível para a ^F1Mochila a Jato"
 
 #: qcsrc/common/notifications/all.inc:269
 msgid "^F2You lack a UID, superspec options will not be saved/restored"
 msgstr ""
-"^F2Você não tem um UID, opções de sperspec não serão salvas/restauradas"
+"^F2Não tens um UID, as opções de sperspec não serão gravadas/restauradas"
 
 #: qcsrc/common/notifications/all.inc:271
 msgid "^F1Round already started, you will join the game in the next round"
-msgstr "^F1A rodada já começou, você entrará no jogo na próxima rodada"
+msgstr "^F1A rodada já começou, vais entrar no jogo na próxima rodada"
 
 #: qcsrc/common/notifications/all.inc:272
 msgid "^F2You will spectate in the next round"
-msgstr "^F2Você ficará de espectador na próxima rodada"
+msgstr "^F2Vais ficar no modo espetador na próxima rodada"
 
 #: qcsrc/common/notifications/all.inc:274
 #, c-format
 msgid "^BG%s%s^K1 was killed by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
-msgstr "^BG%s%s^K1 foi morto pelo bônus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
+msgstr "^BG%s%s^K1 foi morto pelo bónus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:274
 #, c-format
 msgid "^BG%s%s^K1 was scored against by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
 msgstr ""
-"^BG%s%s^K1 foi pontuado contra pelo bônus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
+"^BG%s%s^K1 foi pontuado contra pelo bónus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:275
 #, c-format
@@ -2060,7 +2061,7 @@ msgstr "^BG%s%s^K1 foi castigado por ^BG%s^K1%s%s"
 #, c-format
 msgid "^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s"
 msgstr ""
-"^BG%s%s^K1 se sentiu um pouco quente por causa do fogo de ^BG%s^K1^K1%s%s"
+"^BG%s%s^K1 sentiu-se um pouco quente por causa do fogo de ^BG%s^K1^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:278
 #, c-format
@@ -2075,7 +2076,7 @@ msgstr "^BG%s%s^K1 foi cozinhado por ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:280
 #, c-format
 msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 foi empurrado em frente de um monstro por ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi empurrado na frente de um monstro por ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:281
 #, c-format
@@ -2085,28 +2086,29 @@ msgstr "^BG%s%s^K1 foi explodido pela Granada de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:282
 #, c-format
 msgid "^BG%s%s^K1 got too close to a napalm explosion%s%s"
-msgstr "^BG%s%s^K1 se aproximou demais de uma explosão de napalm%s%s"
+msgstr "^BG%s%s^K1 aproximou-se demais de uma explosão de napalm%s%s"
 
 #: qcsrc/common/notifications/all.inc:282
 #, c-format
 msgid "^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"
 msgstr ""
-"^BG%s%s^K1 foi queimado até a morte pela Granada de Napalm de ^BG%s^K1%s%s"
+"^BG%s%s^K1 foi queimado até à morte pela Granada de Napalm de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:283
 #, c-format
 msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"
-msgstr "^BG%s%s^K1 foi explodido pega Granada de Gelo de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi explodido pela Granada de Gelo de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:284
 #, c-format
 msgid "^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"
-msgstr "^BG%s%s^K1 foi explodido pega Granada de Gelo de ^BG%s^K1%s%s"
+msgstr ""
+"^BG%s%s^K1  foi congelado até à morte pela Granada de Gelo de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:285
 #, c-format
 msgid "^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"
-msgstr "^BG%s%s^K1 não foi curado pela Granade de Cura de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 não foi curado pela Granada de Cura de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:286
 #, c-format
@@ -2131,23 +2133,23 @@ msgstr "^BG%s%s^K1 tentou ocupar o espaço do teletransporte de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:289
 #, c-format
 msgid "^BG%s%s^K1 was telefragged by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 levou um telefrag de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi teletransmorto por ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:290
 #, c-format
 msgid "^BG%s%s^K1 died in an accident with ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 morreu em um acidente com ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 morreu num acidente com ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:291
 #, c-format
 msgid ""
 "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Bumblebee exploded%s%s"
-msgstr "^BG%s%s^K1 foi pego pela explosão de Bumblebee de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi apanhado pela explosão de Bumblebee de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:292
 #, c-format
 msgid "^BG%s%s^K1 saw the pretty lights of ^BG%s^K1's Bumblebee gun%s%s"
-msgstr "^BG%s%s^K1 viu as lindas luzes da arma do Bumblebee de ^BG%s^K1%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:293
 #, c-format
@@ -2167,28 +2169,29 @@ msgstr "^BG%s%s^K1 não resistiu às bolhas roxas de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:296
 #, c-format
 msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Raptor exploded%s%s"
-msgstr "^BG%s%s^K1 foi pego pela explosão do Raptor de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi apanhado pela explosão do Raptor de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:297
 #, c-format
 msgid ""
 "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Spiderbot exploded%s%s"
-msgstr "^BG%s%s^K1 foi pego pela explosão do Spiderbot de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi apanhado pela explosão do Robô Aranha de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:298
 #, c-format
 msgid "^BG%s%s^K1 got shredded by ^BG%s^K1's Spiderbot%s%s"
-msgstr "^BG%s%s^K1 foi picado pelo Spiderbot de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi picado pelo Robô Aranha de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:299
 #, c-format
 msgid "^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s"
-msgstr "^BG%s%s^K1 foi explodido em pedacinhos pelo Spiderbot de ^BG%s^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 foi explodido em pedacinhos pelo Robô Aranha de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:300
 #, c-format
 msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"
-msgstr "^BG%s%s^K1 foi pego pela explosão do Racer de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi apanhado pela explosão do Racer de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:301
 #, c-format
@@ -2203,7 +2206,7 @@ msgstr "^BG%s%s^K1 não conseguiu escapar do Racer de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:303
 #, c-format
 msgid "^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 foi jogado em mundo de dor por ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi atirado para um mundo de dor por ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:305
 #, c-format
@@ -2213,18 +2216,17 @@ msgstr "^BG%s^K1 foi movido para o %s%s"
 #: qcsrc/common/notifications/all.inc:306
 #, c-format
 msgid "^BG%s^K1 became enemies with the Lord of Teamplay%s%s"
-msgstr "^BG%s^K1 tornou-se inimigo do Senhor do Trabalho em Equipe%s%s"
+msgstr "^BG%s^K1 tornou-se inimigo do Senhor do Trabalho em Equipa%s%s"
 
 #: qcsrc/common/notifications/all.inc:307
 #, c-format
 msgid "^BG%s^K1 thought they found a nice camping ground%s%s"
-msgstr ""
-"^BG%s^K1 acharam que tinham encontrado um ótimo lugar para camperar%s%s"
+msgstr "^BG%s^K1 pensou que tinham encontrado um ótimo lugar para acampar%s%s"
 
 #: qcsrc/common/notifications/all.inc:308
 #, c-format
 msgid "^BG%s^K1 unfairly eliminated themself%s%s"
-msgstr "^BG%s^K1 se eliminou injustamente%s%s"
+msgstr "^BG%s^K1 eliminou-se injustamente%s%s"
 
 #: qcsrc/common/notifications/all.inc:310
 #, c-format
@@ -2254,7 +2256,7 @@ msgstr "^BG%s^K1 ficou um pouco crocante%s%s"
 #: qcsrc/common/notifications/all.inc:312
 #, c-format
 msgid "^BG%s^K1 felt a little hot%s%s"
-msgstr "^BG%s^K1 se sentiu um pouco quente%s%s"
+msgstr "^BG%s^K1 sentiu-se um pouco quente%s%s"
 
 #: qcsrc/common/notifications/all.inc:313
 #, c-format
@@ -2264,7 +2266,7 @@ msgstr "^BG%s^K1 morreu%s%s"
 #: qcsrc/common/notifications/all.inc:314
 #, c-format
 msgid "^BG%s^K1 found a hot place%s%s"
-msgstr "^BG%s^K1 achou um lugar quente%s%s"
+msgstr "^BG%s^K1 encontrou um lugar quente%s%s"
 
 #: qcsrc/common/notifications/all.inc:314
 #, c-format
@@ -2280,18 +2282,18 @@ msgstr "^BG%s^K1 foi explodido por um Mago%s%s"
 #, c-format
 msgid "^BG%s^K1's innards became outwards by a Shambler%s%s"
 msgstr ""
-"Os órgãos internos de ^BG%s^K1 se tornaram externos por causa de um Shambler "
+"Os órgãos internos de ^BG%s^K1 tornaram-se externos por causa de um Shambler "
 "%s%s"
 
 #: qcsrc/common/notifications/all.inc:317
 #, c-format
 msgid "^BG%s^K1 was smashed by a Shambler%s%s"
-msgstr "^BG%s^K1 foi esmagado por um Shambler%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:318
 #, c-format
 msgid "^BG%s^K1 was zapped to death by a Shambler%s%s"
-msgstr "^BG%s^K1 foi eletrocutado até a morte por um Shambler%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:319
 #, c-format
@@ -2301,12 +2303,12 @@ msgstr "^BG%s^K1 foi picado por uma Aranha%s%s"
 #: qcsrc/common/notifications/all.inc:320
 #, c-format
 msgid "^BG%s^K1 was fireballed by a Wyvern%s%s"
-msgstr "^BG%s^K1 foi morto pela fireball de um Wyvern%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:321
 #, c-format
 msgid "^BG%s^K1 joins the Zombies%s%s"
-msgstr "^BG%s^K1 se juntou aos Zumbis%s%s"
+msgstr "^BG%s^K1 juntou-se aos Zumbis%s%s"
 
 #: qcsrc/common/notifications/all.inc:322
 #, c-format
@@ -2324,13 +2326,12 @@ msgstr "^BG%s^K1 dominou a arte do suicídio com granadas%s%s"
 msgid ""
 "^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s"
 msgstr ""
-"^BG%s^K1 decidiu dar uma olhada nos resultados de sua explosão de napalm%s%s"
+"^BG%s^K1 decidiu dar uma olhada nos resultados da sua explosão de napalm%s%s"
 
 #: qcsrc/common/notifications/all.inc:324
 #, c-format
 msgid "^BG%s^K1 was burned to death by their own Napalm Nade%s%s"
-msgstr ""
-"^BG%s^K1 foi queimado até a morte por sua própria Granada de Napalm%s%s"
+msgstr "^BG%s^K1 foi queimado até a morte pela própria Granada de Napalm%s%s"
 
 #: qcsrc/common/notifications/all.inc:326
 #, c-format
@@ -2340,22 +2341,23 @@ msgstr "^BG%s^K1 sentiu-se um pouco friolento%s%s"
 #: qcsrc/common/notifications/all.inc:326
 #, c-format
 msgid "^BG%s^K1 was frozen to death by their own Ice Nade%s%s"
-msgstr "^BG%s^K1 foi congelado até a morte por sua própria Granada de Gelo%s%s"
+msgstr ""
+"^BG%s^K1 foi congelado até a morte pela sua própria Granada de Gelo%s%s"
 
 #: qcsrc/common/notifications/all.inc:327
 #, c-format
 msgid "^BG%s^K1's Healing Nade didn't quite heal them%s%s"
-msgstr "A Granada de Cura de ^BG%s^K1 não lhe curou corretamente%s%s"
+msgstr "A Granada de Cura de ^BG%s^K1 não lhe fez lá muito bem%s%s"
 
 #: qcsrc/common/notifications/all.inc:328
 #, c-format
 msgid "^BG%s^K1 died%s%s. What's the point of living without ammo?"
-msgstr "^BG%s^K1 morreu%s%s. Qual o sentido de viver sem munição?"
+msgstr "^BG%s^K1 morreu%s%s. Para quê viver se não tens munições?"
 
 #: qcsrc/common/notifications/all.inc:328
 #, c-format
 msgid "^BG%s^K1 ran out of ammo%s%s"
-msgstr "^BG%s^K1 ficou sem munição%s%s"
+msgstr "^BG%s^K1 ficou sem munições%s%s"
 
 #: qcsrc/common/notifications/all.inc:329
 #, c-format
@@ -2365,7 +2367,7 @@ msgstr "^BG%s^K1 derreteu%s%s"
 #: qcsrc/common/notifications/all.inc:330
 #, c-format
 msgid "^BG%s^K1 became a shooting star%s%s"
-msgstr "^BG%s^K1 se tornou uma estrela cadente%s%s"
+msgstr "^BG%s^K1 tornou-se uma estrela cadente%s%s"
 
 #: qcsrc/common/notifications/all.inc:331
 #, c-format
@@ -2390,44 +2392,43 @@ msgstr "^BG%s^K1 trocou para o %s%s"
 #: qcsrc/common/notifications/all.inc:335
 #, c-format
 msgid "^BG%s^K1 died in an accident%s%s"
-msgstr "^BG%s^K1 morreu em um acidente%s%s"
+msgstr "^BG%s^K1 morreu num acidente%s%s"
 
 #: qcsrc/common/notifications/all.inc:336
 #, c-format
 msgid "^BG%s^K1 ran into a turret%s%s"
-msgstr "^BG%s^K1 deu de cara com uma sentinela%s%s"
+msgstr "^BG%s^K1 deu de caras com uma sentinela%s%s"
 
 #: qcsrc/common/notifications/all.inc:337
 #, c-format
 msgid "^BG%s^K1 was blasted away by an eWheel turret%s%s"
-msgstr "^BG%s^K1 foi explodido por uma sentinela eWheel%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:338
 #, c-format
 msgid "^BG%s^K1 got caught up in the FLAC turret fire%s%s"
-msgstr "^BG%s^K1 se meteu no meio do tiroteio de uma sentinela FLAC%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:339
 #, c-format
 msgid "^BG%s^K1 was blasted away by a Hellion turret%s%s"
-msgstr "^BG%s^K1 foi explodido por uma sentinela Hellion%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:340
 #, c-format
 msgid "^BG%s^K1 could not hide from the Hunter turret%s%s"
-msgstr "^BG%s^K1 não conseguiu se esconder da sentinela Hunter%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:341
 #, c-format
 msgid "^BG%s^K1 was riddled full of holes by a Machinegun turret%s%s"
 msgstr ""
-"^BG%s^K1 ficou cheio de buracos por causa de uma sentinela de Metralhadora%s"
-"%s"
+"^BG%s^K1 ficou cheio de buracos por causa de uma sentinela Metralhadora%s%s"
 
 #: qcsrc/common/notifications/all.inc:342
 #, c-format
 msgid "^BG%s^K1 got turned into smoldering gibs by an MLRS turret%s%s"
-msgstr "^BG%s^K1 foi picado em pedacinhos latentes por uma sentinela MLRS%s%s"
+msgstr "^BG%s^K1 foi triturado em pedacinhos por uma sentinela MLRS%s%s"
 
 #: qcsrc/common/notifications/all.inc:343
 #, c-format
@@ -2437,7 +2438,7 @@ msgstr "^BG%s^K1 foi eliminado por uma sentinela%s%s"
 #: qcsrc/common/notifications/all.inc:344
 #, c-format
 msgid "^BG%s^K1 got served some superheated plasma from a turret%s%s"
-msgstr "^BG%s^K1 levou um plasma superaquecido de uma sentinela%s%s"
+msgstr "^BG%s^K1 levou com um plasma super aquecido de uma sentinela%s%s"
 
 #: qcsrc/common/notifications/all.inc:345
 #, c-format
@@ -2447,22 +2448,22 @@ msgstr "^BG%s^K1 foi eletrocutado por uma sentinela Tesla%s%s"
 #: qcsrc/common/notifications/all.inc:346
 #, c-format
 msgid "^BG%s^K1 got served a lead enrichment by a Walker turret%s%s"
-msgstr "^BG%s^K1 foi entupido de chumbo por uma sentinela Walker%s%s"
+msgstr "^BG%s^K1 foi carregado de chumbo por uma sentinela Andante%s%s"
 
 #: qcsrc/common/notifications/all.inc:347
 #, c-format
 msgid "^BG%s^K1 was impaled by a Walker turret%s%s"
-msgstr "^BG%s^K1 foi empalado por uma sentinela Walker%s%s"
+msgstr "^BG%s^K1 foi empalado por uma sentinela Andante%s%s"
 
 #: qcsrc/common/notifications/all.inc:348
 #, c-format
 msgid "^BG%s^K1 was blasted away by a Walker turret%s%s"
-msgstr "^BG%s^K1 foi explodido por uma sentinela Walker%s%s"
+msgstr "^BG%s^K1 foi explodido por uma sentinela Andante%s%s"
 
 #: qcsrc/common/notifications/all.inc:349
 #, c-format
 msgid "^BG%s^K1 got caught in the blast of a Bumblebee explosion%s%s"
-msgstr "^BG%s^K1 foi pego pelo raio de uma explosão de Bumblebee%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:350
 #, c-format
@@ -2472,32 +2473,32 @@ msgstr "^BG%s^K1 foi esmagado por um veículo%s%s"
 #: qcsrc/common/notifications/all.inc:351
 #, c-format
 msgid "^BG%s^K1 was caught in a Raptor cluster bomb%s%s"
-msgstr "^BG%s^K1 foi pego por uma bomba de Raptor%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:352
 #, c-format
 msgid "^BG%s^K1 got caught in the blast of a Raptor explosion%s%s"
-msgstr "^BG%s^K1 foi pego pela explosão de um Raptor%s%s"
+msgstr ""
 
 #: qcsrc/common/notifications/all.inc:353
 #, c-format
 msgid "^BG%s^K1 got caught in the blast of a Spiderbot explosion%s%s"
-msgstr "^BG%s^K1 foi pego pela explosão de um Spiderbot%s%s"
+msgstr "^BG%s^K1 foi apanhado pela explosão de um Robô Aranha%s%s"
 
 #: qcsrc/common/notifications/all.inc:354
 #, c-format
 msgid "^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s"
-msgstr "^BG%s^K1 foi explodido em pedacinhos por um foguete de Spiderbot%s%s"
+msgstr "^BG%s^K1 foi explodido em pedacinhos por um míssil de Robô Aranha%s%s"
 
 #: qcsrc/common/notifications/all.inc:355
 #, c-format
 msgid "^BG%s^K1 got caught in the blast of a Racer explosion%s%s"
-msgstr "^BG%s^K1 foi pego pela explosão de um Racer%s%s"
+msgstr "^BG%s^K1 foi apanhado pela explosão de um Racer%s%s"
 
 #: qcsrc/common/notifications/all.inc:356
 #, c-format
 msgid "^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"
-msgstr "^BG%s^K1 não conseguiu escapar do foguete de um Racer%s%s"
+msgstr "^BG%s^K1 não conseguiu escapar ao míssil de um Racer%s%s"
 
 #: qcsrc/common/notifications/all.inc:359
 #, c-format
@@ -2537,12 +2538,12 @@ msgstr "^BG%s^K3 foi automaticamente ressuscitado depois de %s segundo(s)"
 #: qcsrc/common/notifications/all.inc:368
 #, c-format
 msgid "^BG%s^K1 froze themself"
-msgstr "^BG%s^K1 se congelou"
+msgstr "^BG%s^K1 congelou-se"
 
 #: qcsrc/common/notifications/all.inc:370
 #: qcsrc/common/notifications/all.inc:684
 msgid "^TC^TT^BG team wins the round"
-msgstr "A equipe ^TC^TT^BG venceu a rodada"
+msgstr "A equipa ^TC^TT^BG venceu a rodada"
 
 #: qcsrc/common/notifications/all.inc:371
 #: qcsrc/common/notifications/all.inc:685
@@ -2558,58 +2559,58 @@ msgstr "^BGRodada empatada"
 #: qcsrc/common/notifications/all.inc:373
 #: qcsrc/common/notifications/all.inc:549
 msgid "^BGRound over, there's no winner"
-msgstr "^BGA rodada acabou sem vencedor"
+msgstr "^BGA rodada acabou sem vencedores"
 
 #: qcsrc/common/notifications/all.inc:375
 #, c-format
 msgid "^BGGodmode saved you %s units of damage, cheater!"
-msgstr "^BGModo Deus te protegeu de %s de dano, seu trapaçeiro!"
+msgstr "^BGModo Deus protegeu-te de %s unidades de dano, batoteiro!"
 
 #: qcsrc/common/notifications/all.inc:377
 #, c-format
 msgid "^BG%s^BG got the %s^BG buff!"
-msgstr "^BG%s^BG pegou o bônus de %s^BG!"
+msgstr "^BG%s^BG apanhou o bónus de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:378
 #, c-format
 msgid "^BG%s^BG lost the %s^BG buff!"
-msgstr "^BG%s^BG perdeu o bônus de %s^BG!"
+msgstr "^BG%s^BG perdeu o bónus de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:379
 #: qcsrc/common/notifications/all.inc:692
 #, c-format
 msgid "^BGYou dropped the %s^BG buff!"
-msgstr "^BGVocê largou o bônus de %s^BG!"
+msgstr "^BGLargaste o bónus de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:380
 #: qcsrc/common/notifications/all.inc:693
 #, c-format
 msgid "^BGYou got the %s^BG buff!"
-msgstr "^BGVocê pegou o bônus de %s^BG!"
+msgstr "^BGApanhaste o bónus de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:382
 #: qcsrc/common/notifications/all.inc:696
 #, c-format
 msgid "^BGYou do not have the ^F1%s"
-msgstr "^BGVocê não tem a ^F1%s"
+msgstr "^BGNão tens a ^F1%s"
 
 #: qcsrc/common/notifications/all.inc:383
 #: qcsrc/common/notifications/all.inc:697
 #, c-format
 msgid "^BGYou dropped the ^F1%s^BG%s"
-msgstr "^BGVocê largou a ^F1%s^BG%s"
+msgstr "^BGLargaste a ^F1%s^BG%s"
 
 #: qcsrc/common/notifications/all.inc:384
 #: qcsrc/common/notifications/all.inc:698
 #, c-format
 msgid "^BGYou got the ^F1%s"
-msgstr "^BGVocê pegou a ^F1%s"
+msgstr "^BGApanhaste a ^F1%s"
 
 #: qcsrc/common/notifications/all.inc:385
 #: qcsrc/common/notifications/all.inc:699
 #, c-format
 msgid "^BGYou don't have enough ammo for the ^F1%s"
-msgstr "^BGVocê não tem munição suficiente para a ^F1%s"
+msgstr "^BGNão tens munições suficientes para a ^F1%s"
 
 #: qcsrc/common/notifications/all.inc:386
 #: qcsrc/common/notifications/all.inc:700
@@ -2626,7 +2627,7 @@ msgstr "^F1%s^BG^F4 não está disponível^BG neste mapa"
 #: qcsrc/common/notifications/all.inc:389
 #, c-format
 msgid "^BG%s^BG is connecting..."
-msgstr "^BG%s^BG está conectando..."
+msgstr "^BG%s^BG está a conectar-se..."
 
 #: qcsrc/common/notifications/all.inc:390
 #, c-format
@@ -2636,17 +2637,17 @@ msgstr "^BG%s^F3 conectou-se"
 #: qcsrc/common/notifications/all.inc:391
 #, c-format
 msgid "^BG%s^F3 connected and joined the ^TC^TT team"
-msgstr "^BG%s^F3 conectou-se e se uniu à equipe ^TC^TT"
+msgstr "^BG%s^F3 conectou-se e se juntou-se à equipa ^TC^TT"
 
 #: qcsrc/common/notifications/all.inc:392
 #, c-format
 msgid "^BG%s^F3 is now playing"
-msgstr "^BG%s^F3 está jogando agora"
+msgstr "^BG%s^F3 está agora a jogar"
 
 #: qcsrc/common/notifications/all.inc:393
 #, c-format
 msgid "^BG%s^F3 is now playing on the ^TC^TT team"
-msgstr "^BG%s^F3 está jogando agora na equipe ^TC^TT"
+msgstr "^BG%s^F3 está a jogar agora na equipa ^TC^TT"
 
 #: qcsrc/common/notifications/all.inc:395
 #: qcsrc/common/notifications/all.inc:706
@@ -2658,12 +2659,12 @@ msgstr "^BG%s^BG largou a bola!"
 #: qcsrc/common/notifications/all.inc:707
 #, c-format
 msgid "^BG%s^BG has picked up the ball!"
-msgstr "^BG%s^BG pegou a bola!"
+msgstr "^BG%s^BG apanhou a bola!"
 
 #: qcsrc/common/notifications/all.inc:398
 #, c-format
 msgid "^BG%s^BG captured the keys for the ^TC^TT team"
-msgstr "^BG%s^BG capturou as chaves para a equipe ^TC^TT"
+msgstr "^BG%s^BG capturou as chaves para a equipa ^TC^TT"
 
 #: qcsrc/common/notifications/all.inc:399
 #, c-format
@@ -2688,7 +2689,7 @@ msgstr "^BG%s^BG destruiu a Chave ^TC^TT"
 #: qcsrc/common/notifications/all.inc:403
 #, c-format
 msgid "^BG%s^BG picked up the ^TC^TT Key"
-msgstr "^BG%s^BG pegou a Chave ^TC^TT"
+msgstr "^BG%s^BG apanhou a Chave ^TC^TT"
 
 #: qcsrc/common/notifications/all.inc:405
 #, c-format
@@ -2702,21 +2703,21 @@ msgstr "^BG%s^F3 não tem mais vidas"
 
 #: qcsrc/common/notifications/all.inc:408
 msgid "^BGMonsters are currently disabled"
-msgstr "^BGMonstros estão atualmente desativados"
+msgstr "^BGOs monstros estão desativados neste momento"
 
 #: qcsrc/common/notifications/all.inc:410
 msgid "^BGThe ^TC^TT^BG team held the ball for too long"
-msgstr "^BGA ^BGequipe ^TC^TT segurou a bola por muito tempo"
+msgstr "^BGA ^BGequipa ^TC^TT segurou a bola por muito tempo"
 
 #: qcsrc/common/notifications/all.inc:412
 #, c-format
 msgid "^BG%s^BG captured %s^BG control point"
-msgstr "^BG%s^BG capturou o ponto de controle %s^BG"
+msgstr "^BG%s^BG capturou o ponto de controlo %s^BG"
 
 #: qcsrc/common/notifications/all.inc:413
 #, c-format
 msgid "^TC^TT^BG team %s^BG control point has been destroyed by %s"
-msgstr "O ponto de controle %s^BG da equipe ^TC^TT^BG foi destruído por %s"
+msgstr "O ponto de controlo %s^BG da equipa ^TC^TT^BG foi destruído por %s"
 
 #: qcsrc/common/notifications/all.inc:414
 msgid "^TC^TT^BG generator has been destroyed"
@@ -2725,28 +2726,28 @@ msgstr "O gerador ^TC^TT^BG foi destruído"
 #: qcsrc/common/notifications/all.inc:415
 msgid "^TC^TT^BG generator spontaneously combusted due to overtime!"
 msgstr ""
-"O gerador da equipe ^TC^TT^BG entrou em combustão espontaneamente devido aos "
+"O gerador da equipa ^TC^TT^BG entrou em combustão espontaneamente devido aos "
 "acréscimos!"
 
 #: qcsrc/common/notifications/all.inc:417
 #, c-format
 msgid "^BG%s^K1 picked up Invisibility"
-msgstr "^BG%s^K1 pegou Invisibilidade"
+msgstr "^BG%s^K1 apanhou a Invisibilidade"
 
 #: qcsrc/common/notifications/all.inc:418
 #, c-format
 msgid "^BG%s^K1 picked up Shield"
-msgstr "^BG%s^K1 pegou Escudo"
+msgstr "^BG%s^K1 apanhou o Escudo"
 
 #: qcsrc/common/notifications/all.inc:419
 #, c-format
 msgid "^BG%s^K1 picked up Speed"
-msgstr "^BG%s^K1 pegou Velocidade"
+msgstr "^BG%s^K1 apanhou a Velocidade"
 
 #: qcsrc/common/notifications/all.inc:420
 #, c-format
 msgid "^BG%s^K1 picked up Strength"
-msgstr "^BG%s^K1 pegou Força"
+msgstr "^BG%s^K1 apanhou a Força"
 
 #: qcsrc/common/notifications/all.inc:422
 #, c-format
@@ -2763,13 +2764,13 @@ msgid ""
 "^F2You were kicked from the server because you are a spectator and "
 "spectators aren't allowed at the moment."
 msgstr ""
-"^F2Você foi expulso do servidor porque você é um espectador e espectadores "
-"não são permitidos no momento."
+"^F2Foste expulso do servidor porque és um espetador e os espetadores não são "
+"permitidos neste momento."
 
 #: qcsrc/common/notifications/all.inc:425
 #, c-format
 msgid "^BG%s^F3 is now spectating"
-msgstr "^BG%s^F3 está assistindo agora"
+msgstr "^BG%s^F3 está agora a assistir"
 
 #: qcsrc/common/notifications/all.inc:427
 #, c-format
@@ -2779,12 +2780,12 @@ msgstr "^BG%s^BG abandonou a corrida"
 #: qcsrc/common/notifications/all.inc:428
 #, c-format
 msgid "^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"
-msgstr "^BG%s^BG não puderam quebrar o recorde de lugar %s%s^BG de %s%s %s"
+msgstr "^BG%s^BG não puderam bater o recorde de lugar %s%s^BG de %s%s %s"
 
 #: qcsrc/common/notifications/all.inc:429
 #, c-format
 msgid "^BG%s^BG couldn't break the %s%s^BG place record of %s%s %s"
-msgstr "^BG%s^BG não pode quebrar o recorde de lugar %s%s^BG de %s%s %s"
+msgstr "^BG%s^BG não pode bater o recorde de lugar %s%s^BG de %s%s %s"
 
 #: qcsrc/common/notifications/all.inc:430
 #, c-format
@@ -2795,13 +2796,13 @@ msgstr "^BG%s^BG acabou a corrida"
 #, c-format
 msgid "^BG%s^BG broke %s^BG's %s%s^BG place record with %s%s %s"
 msgstr ""
-"^BG%s^BG quebrou o recorde %s%s^BG de %s^BG e substituiu seu recorde com %s"
-"%s %s"
+"^BG%s^BG bateu o recorde %s%s^BG de %s^BG e substituiu seu recorde com %s%s "
+"%s"
 
 #: qcsrc/common/notifications/all.inc:432
 #, c-format
 msgid "^BG%s^BG improved their %s%s^BG place record with %s%s %s"
-msgstr "^BG%s^BG melhoraram seus %s%s^BG com %s%s %s"
+msgstr "^BG%s^BG melhoraram os seus %s%s^BG com %s%s %s"
 
 #: qcsrc/common/notifications/all.inc:433
 #, c-format
@@ -2810,7 +2811,7 @@ msgid ""
 "and will be lost."
 msgstr ""
 "^BG%s^BG atingiu um novo recorde com ^F2%s^BG, mas infelizmente, faltou uma "
-"identidade de usuário e sua pontuação será perdida."
+"identidade de utilizador e a sua pontuação vai para o badagaio."
 
 #: qcsrc/common/notifications/all.inc:434
 #, c-format
@@ -2818,8 +2819,8 @@ msgid ""
 "^BG%s^BG scored a new record with ^F2%s^BG, but is anonymous and will be "
 "lost."
 msgstr ""
-"^BG%s^BG quebrou um novo recorde com ^F2%s^BG, mas é anônimo e, por isso, "
-"será perdido."
+"^BG%s^BG bateu um novo recorde com ^F2%s^BG, mas é anónimo e, por isso, o "
+"recorde também ficará anónimo no esquecimento."
 
 #: qcsrc/common/notifications/all.inc:435
 #, c-format
@@ -2832,12 +2833,12 @@ msgid ""
 "^F4You have been invited by ^BG%s^F4 to join their game of ^F2%s^F4 "
 "(^F1%s^F4)"
 msgstr ""
-"^F4Você foi convidado por ^BG%s^F4 para se juntar a eles na partida de "
+"^F4Foste convidado por ^BG%s^F4 para te juntares a eles na partida de "
 "^F2%s^F4 (^F1%s^F4)"
 
 #: qcsrc/common/notifications/all.inc:439
 msgid "^TC^TT ^BGteam scores!"
-msgstr "A equipe ^TC^TT ^BG pontuou!"
+msgstr "A equipa ^TC^TT ^BG pontuou!"
 
 #: qcsrc/common/notifications/all.inc:441
 #, c-format
@@ -2845,21 +2846,21 @@ msgid ""
 "^F2You have to become a player within the next %s, otherwise you will be "
 "kicked, because spectating isn't allowed at this time!"
 msgstr ""
-"^F2Você precisa se tornar um jogador dentro de %s, caso contrário, você será "
-"expulso, pois espectadores não são permitidos no momento!"
+"^F2Tens de te tornar um jogador dentro de %s, caso contrário, serás expulso, "
+"pois os espetadores não são permitidos neste momento!"
 
 #: qcsrc/common/notifications/all.inc:443
 #, c-format
 msgid "^BG%s^K1 picked up a Superweapon"
-msgstr "^BG%s^K1 pegou uma Superarma"
+msgstr "^BG%s^K1 apanhou uma Super arma"
 
 #: qcsrc/common/notifications/all.inc:445
 msgid "^BGYou cannot change to a larger team"
-msgstr "^BGVocê não pode trocar para uma equipe maior"
+msgstr "^BGNão podes mudar para uma equipa maior"
 
 #: qcsrc/common/notifications/all.inc:446
 msgid "^BGYou are not allowed to change teams"
-msgstr "^BGVocê não pode trocar de equipe"
+msgstr "^BGNão tens permissão para trocar de equipa"
 
 #: qcsrc/common/notifications/all.inc:448
 #, c-format
@@ -2867,7 +2868,7 @@ msgid ""
 "^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have "
 "^F2Xonotic %s"
 msgstr ""
-"^F4NOTA: ^BGO servidor está rodando ^F1Xonotic %s (beta)^BG, você tem o "
+"^F4NOTA: ^BGO servidor está a executar o ^F1Xonotic %s (beta)^BG, tu tens o "
 "^F2Xonotic %s"
 
 #: qcsrc/common/notifications/all.inc:449
@@ -2875,8 +2876,8 @@ msgstr ""
 msgid ""
 "^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"
 msgstr ""
-"^F4NOTA: ^BGO servidor está rodando ^F1Xonotic %s^BG, você tem o ^F2Xonotic "
-"%s"
+"^F4NOTA: ^BGO servidor está a executar o ^F1Xonotic %s^BG, tu tens o "
+"^F2Xonotic %s"
 
 #: qcsrc/common/notifications/all.inc:450
 #, c-format
@@ -2884,8 +2885,8 @@ msgid ""
 "^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get "
 "the update from ^F3http://www.xonotic.org/^BG!"
 msgstr ""
-"^F4NOTA: ^F1Xonotic %s^BG foi lançado e você ainda está com o ^F2Xonotic "
-"%s^BG - baixe a atualização pelo site ^F3http://www.xonotic.org/^BG!"
+"^F4NOTA: ^F1Xonotic %s^BG foi lançado e ainda estás com o ^F2Xonotic %s^BG - "
+"descarrega a atualização no site ^F3http://www.xonotic.org/^BG!"
 
 #: qcsrc/common/notifications/all.inc:452
 #, c-format
@@ -2898,12 +2899,12 @@ msgid ""
 "^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon%s%s"
 msgstr ""
 "^BG%s%s^K1 morreu por causa da grande habilidade de ^BG%s^K1 com a @!#%%'n "
-"Accordeon%s%s"
+"Acordeão%s%s"
 
 #: qcsrc/common/notifications/all.inc:455
 #, c-format
 msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon%s%s"
-msgstr "^BG%s^K1 feriu seus próprios ouvidos com a @!#%%'n Accordeon%s%s"
+msgstr "^BG%s^K1 feriu seus próprios ouvidos com a @!#%%'n Acordeão%s%s"
 
 #: qcsrc/common/notifications/all.inc:456
 #, c-format
@@ -2923,7 +2924,7 @@ msgstr "^BG%s%s^K1 foi morto pelo Blaster de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:459
 #, c-format
 msgid "^BG%s^K1 shot themself to hell with their Blaster%s%s"
-msgstr "^BG%s^K1 atirou muito em si mesmo com seu Blaster%s%s"
+msgstr "^BG%s^K1 disparou para si próprio até ao inferno com o Blaster%s%s"
 
 #: qcsrc/common/notifications/all.inc:460
 #, c-format
@@ -2938,7 +2939,7 @@ msgstr "^BG%s^K1 sentiu o forte impulso de sua Crylink%s%s"
 #: qcsrc/common/notifications/all.inc:462
 #, c-format
 msgid "^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 comeu o foguete de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 comeu o míssil de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
@@ -2948,42 +2949,39 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:464
 #, c-format
 msgid "^BG%s^K1 blew themself up with their Devastator%s%s"
-msgstr "^BG%s^K1 se explodiu com sua Devastator%s%s"
+msgstr "^BG%s^K1 explodiu-se com a sua Devastadora%s%s"
 
 #: qcsrc/common/notifications/all.inc:465
 #, c-format
 msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"
-msgstr ""
-"^BG%s%s^K1 foi pulverizado por  ^BG%s^K1', usando a arma de artefato "
-"eletromagnético %s%s"
+msgstr "^BG%s%s^K1 foi pulverizado pelo Parafuso Elétrico de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:466
 #, c-format
 msgid "^BG%s%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo%s%s"
-msgstr ""
-"^BG%s%s^K1 sentiu o ar eletrocutado do combo de Electro de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 sentiu o ar eletrocutado do combo Elétrico de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:467
 #, c-format
 msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Electro orb%s%s"
-msgstr "^BG%s%s^K1 ficou muito perto da esfera de Electro de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 ficou muito perto da esfera Elétrica de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:468
 #, c-format
 msgid "^BG%s^K1 played with Electro bolts%s%s"
-msgstr "^BG%s^K1 brincou com raios de Electro%s%s"
+msgstr "^BG%s^K1 brincou com os Parafusos Elétricos%s%s"
 
 #: qcsrc/common/notifications/all.inc:469
 #, c-format
 msgid "^BG%s^K1 could not remember where they put their Electro orb%s%s"
 msgstr ""
-"^BG%s^K1 não conseguiu se lembrar onde tinha colocado a sua esfera de Electro"
-"%s%s"
+"^BG%s^K1 não conseguiu lembrar-se onde tinha colocado a sua esfera Elétrica%s"
+"%s"
 
 #: qcsrc/common/notifications/all.inc:470
 #, c-format
 msgid "^BG%s%s^K1 got too close to ^BG%s^K1's fireball%s%s"
-msgstr "^BG%s%s^K1 chegou muito perto da fireball de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 chegou muito perto da Bola de Fogo de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:471
 #, c-format
@@ -2993,28 +2991,28 @@ msgstr "^BG%s%s^K1 foi queimado pela mina de fogo de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:472
 #, c-format
 msgid "^BG%s^K1 should have used a smaller gun%s%s"
-msgstr "^BG%s^K1 deveria ter usado uma arma menor%s%s"
+msgstr "^BG%s^K1 devia ter usado uma arma mais pequena%s%s"
 
 #: qcsrc/common/notifications/all.inc:473
 #, c-format
 msgid "^BG%s^K1 forgot about their firemine%s%s"
-msgstr "^BG%s^K1 se esqueceu da sua mina de fogo%s%s"
+msgstr "^BG%s^K1 esqueceu-se da sua mina de fogo%s%s"
 
 #: qcsrc/common/notifications/all.inc:474
 #, c-format
 msgid "^BG%s%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets%s%s"
 msgstr ""
-"^BG%s%s^K1 foi atingido por uma rajada de foguetes do Hagar de ^BG%s^K1%s%s"
+"^BG%s%s^K1 foi atingido por uma rajada de mísseis do Hagar de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:475
 #, c-format
 msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s"
-msgstr "^BG%s%s^K1 foi atingido pelos foguetes do Hagar de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi atingido pelos mísseis do Hagar de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:476
 #, c-format
 msgid "^BG%s^K1 played with tiny Hagar rockets%s%s"
-msgstr "^BG%s^K1 brincou com minúsculos foguetes de Hagar%s%s"
+msgstr "^BG%s^K1 brincou com minúsculos mísseis de Hagar%s%s"
 
 #: qcsrc/common/notifications/all.inc:477
 #, c-format
@@ -3039,7 +3037,8 @@ msgstr "^BG%s%s^K1 foi despedaçado pela Metralhadora Pesada de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:481
 #, c-format
 msgid "^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s"
-msgstr "^BG%s%s^K1 foi pego pela bomba de gravidade do Gancho de ^BG%s^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 foi apanhado pela bomba de gravidade do Gancho de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:482
 #, c-format
@@ -3047,18 +3046,18 @@ msgid ""
 "^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s"
 msgstr ""
 "^BG%s%s^K1 morreu por causa da grande habilidade de ^BG%s^K1 com a @!#%%'n "
-"Klein Bottle%s%s"
+"Garrafa Klein%s%s"
 
 #: qcsrc/common/notifications/all.inc:483
 #, c-format
 msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s"
 msgstr ""
-"^BG%s^K1 machucaram seus próprios ouvidos com a @!#%%'n Klein Bottle%s%s"
+"^BG%s^K1 machucaram seus próprios ouvidos com a @!#%%'n Garrafa Klein%s%s"
 
 #: qcsrc/common/notifications/all.inc:484
 #, c-format
 msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%s%s"
-msgstr "^BG%s%s^K1 foi atingido pela Machine Gun de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi atingido pela Metralhadora de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:485
 #, c-format
@@ -3070,7 +3069,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:790
 #, c-format
 msgid "^BGYou cannot place more than ^F2%s^BG mines at a time"
-msgstr "^BGVocê não pode pôr mais do que ^F2%s^BG minas por vez"
+msgstr "^BGNão podes colocar mais do que ^F2%s^BG minas de uma vez"
 
 #: qcsrc/common/notifications/all.inc:487
 #, c-format
@@ -3080,22 +3079,22 @@ msgstr "^BG%s%s^K1 ficou muito perto da mina de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:488
 #, c-format
 msgid "^BG%s^K1 forgot about their mine%s%s"
-msgstr "^BG%s^K1 se esqueceu de sua mina%s%s"
+msgstr "^BG%s^K1 esqueceu-se de sua mina%s%s"
 
 #: qcsrc/common/notifications/all.inc:489
 #, c-format
 msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"
-msgstr "^BG%s%s^K1 ficou muito perto da granada de Mortar de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 ficou muito perto da granada de Morteiro de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:490
 #, c-format
 msgid "^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"
-msgstr "^BG%s%s^K1 comeu a granada de Mortar de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 comeu a granada de Morteiro de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:491
 #, c-format
 msgid "^BG%s^K1 didn't see their own Mortar grenade%s%s"
-msgstr "^BG%s^K1 não viu a sua própria granada de Mortar%s%s"
+msgstr "^BG%s^K1 não viu a sua própria granada de Morteiro%s%s"
 
 #: qcsrc/common/notifications/all.inc:492
 #, c-format
@@ -3105,22 +3104,23 @@ msgstr "^BG%s^K1 se explodiu com o seu próprio Mortar%s%s"
 #: qcsrc/common/notifications/all.inc:493
 #, c-format
 msgid "^BG%s%s^K1 was sniped with a Rifle by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 foi atingido pelo Rifle de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi atingido pela Espingarda de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:494
 #, c-format
 msgid "^BG%s%s^K1 died in ^BG%s^K1's Rifle bullet hail%s%s"
-msgstr "^BG%s%s^K1 morreu pela bala do Rifle de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 morreu com a bala da Espingarda de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:495
 #, c-format
 msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail%s%s"
-msgstr "^BG%s%s^K1 falhou em se esconder da bala do Rifle de ^BG%s^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 não conseguiu esconder-se da bala da Espingarda de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:496
 #, c-format
 msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle%s%s"
-msgstr "^BG%s%s^K1 falhou em se esconder do Rifle de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 não conseguiu esconder-se da Espingarda ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:497
 #, c-format
@@ -3130,17 +3130,17 @@ msgstr "^BG%s%s^K1 foi serrado ao meio pelo RPC de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:498
 #, c-format
 msgid "^BG%s%s^K1 almost dodged ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
-msgstr "^BG%s%s^K1 quase desviou do RPC de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 quase que conseguia desviar-se do RPC de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:499
 #, c-format
 msgid "^BG%s^K1 was sawn in half by their own Rocket Propelled Chainsaw%s%s"
-msgstr "^BG%s^K1 foi serrado ao meio pelo seu próprio RPC%s%s"
+msgstr "^BG%s^K1 foi serrado ao meio pelo seu RPC%s%s"
 
 #: qcsrc/common/notifications/all.inc:500
 #, c-format
 msgid "^BG%s^K1 blew themself up with their Rocket Propelled Chainsaw%s%s"
-msgstr "^BG%s^K1 se explodiu com seu próprio RPC%s%s"
+msgstr "^BG%s^K1 explodiu-se com o seu RPC%s%s"
 
 #: qcsrc/common/notifications/all.inc:501
 #, c-format
@@ -3155,32 +3155,33 @@ msgstr "^BG%s%s^K1 foi marcado pelo Seeker de ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:503
 #, c-format
 msgid "^BG%s^K1 played with tiny Seeker rockets%s%s"
-msgstr "^BG%s^K1 brincou com minúsculos foguetes de Seeker%s%s"
+msgstr "^BG%s^K1 brincou com minúsculos mísseis do Seeker%s%s"
 
 #: qcsrc/common/notifications/all.inc:504
 #, c-format
 msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shockwave%s%s"
-msgstr "^BG%s%s^K1 foi morto pela Shockwave de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi morto pela Onda de Choque de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:505
 #, c-format
 msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shockwave%s%s"
-msgstr "^BG%s%s^K1 deu uns tapas em ^BG%s^K1 com uma grande Shockwave%s%s"
+msgstr ""
+"^BG%s%s^K1 deu uns estalos em ^BG%s^K1 com uma grande Onda de Choque%s%s"
 
 #: qcsrc/common/notifications/all.inc:506
 #, c-format
 msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s"
-msgstr "^BG%s%s^K1 foi baleado pela Shotgun de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi baleado pela Caçadeira de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:507
 #, c-format
 msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun%s%s"
-msgstr "^BG%s%s^K1 deu uns tapas em ^BG%s^K1 com uma grande Shotgun%s%s"
+msgstr "^BG%s%s^K1 deu uns estalos em ^BG%s^K1 com uma grande Caçadeira%s%s"
 
 #: qcsrc/common/notifications/all.inc:508
 #, c-format
 msgid "^BG%s^K1 is now thinking with portals%s%s"
-msgstr "^BG%s^K1 agora está pensando com portais%s%s"
+msgstr "^BG%s^K1 agora está a pensar em portais%s%s"
 
 #: qcsrc/common/notifications/all.inc:509
 #, c-format
@@ -3192,29 +3193,29 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:510
 #, c-format
 msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Tuba%s%s"
-msgstr "^BG%s^K1 feriu seus próprios ouvidos com a @!#%%'n Tuba%s%s"
+msgstr "^BG%s^K1 feriu os próprios ouvidos com a @!#%%'n Tuba%s%s"
 
 #: qcsrc/common/notifications/all.inc:511
 #, c-format
 msgid "^BG%s%s^K1 has been sublimated by ^BG%s^K1's Vaporizer%s%s"
-msgstr "^BG%s%s^K1 foi sublimado pela Vaporizer de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi sublimado pelo Vaporizador de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:512
 #, c-format
 msgid "^BG%s%s^K1 has been vaporized by ^BG%s^K1's Vortex%s%s"
-msgstr "^BG%s%s^K1 foi vaporizado pela Vortex de ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi vaporizado pelo Vórtex de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:537
 msgid "^F4You are now alone!"
-msgstr "^F4Você está sozinho agora!"
+msgstr "^F4Agora estás sozinho!"
 
 #: qcsrc/common/notifications/all.inc:539
 msgid "^BGYou are attacking!"
-msgstr "^BGVocê está atacando!"
+msgstr "^BGEstás a atacar!"
 
 #: qcsrc/common/notifications/all.inc:540
 msgid "^BGYou are defending!"
-msgstr "^BGVocê está defendendo!"
+msgstr "^BGEstás a defender!"
 
 #: qcsrc/common/notifications/all.inc:541
 #, c-format
@@ -3227,19 +3228,19 @@ msgstr "^F4Começou!"
 
 #: qcsrc/common/notifications/all.inc:544
 msgid "^F4Game starts in ^COUNT"
-msgstr "^F4A partida iniciará em ^COUNT"
+msgstr "^F4A partida vai começar em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:545
 msgid "^F4Round starts in ^COUNT"
-msgstr "^F4A rodada iniciará em ^COUNT"
+msgstr "^F4A rodada vai começar em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:546
 msgid "^F4Round cannot start"
-msgstr "^F4A rodada não pode iniciar"
+msgstr "^F4A rodada não pode começar"
 
 #: qcsrc/common/notifications/all.inc:551
 msgid "^F2Don't camp!"
-msgstr "^F2Não campere!"
+msgstr "^F2Não acampes!"
 
 #: qcsrc/common/notifications/all.inc:555
 msgid ""
@@ -3247,13 +3248,13 @@ msgid ""
 "^BGFeel free to ^F2try to capture^BG the flag again\n"
 "^BGif you think you will succeed."
 msgstr ""
-"^BGVocê está livre agora.\n"
-"^BGSinta-se à vontade para ^F2tentar capturar^BG a bandeira de novo\n"
-"^BGse você acha que irá conseguir."
+"^BGAgora estás livre.\n"
+"^BGEstá à vontade para ^F2tentar capturar^BG a bandeira de novo\n"
+"^BGse achas que vais conseguir."
 
 #: qcsrc/common/notifications/all.inc:556
 msgid "^BGThis flag is currently inactive"
-msgstr "^BGEsta bandeira está atualmente inativa"
+msgstr "^BGEsta bandeira está neste momento inativa"
 
 #: qcsrc/common/notifications/all.inc:557
 msgid ""
@@ -3261,23 +3262,22 @@ msgid ""
 "^BGfor ^F2too many unsuccessful attempts^BG to capture.\n"
 "^BGMake some defensive scores before trying again."
 msgstr ""
-"^BGVocê agora está ^F1impedido^BG de carregar a(s) bandeira(s)\n"
+"^BGAgora estás ^F1impedido^BG de carregar a(s) bandeira(s)\n"
 "^BGapós ^F2várias tentativas de captura sem êxito^BG.\n"
-"^BGFaça alguns pontos defensivos antes de tentar novamente."
+"^BGConsegue alguns pontos defensivos antes de tentares novamente."
 
 #: qcsrc/common/notifications/all.inc:558
 msgid "^BGYou captured the ^TC^TT^BG flag!"
-msgstr "^BGVocê capturou a bandeira ^TC^TT^BG!"
+msgstr "^BGCapturaste a bandeira ^TC^TT^BG!"
 
 #: qcsrc/common/notifications/all.inc:559
 msgid "^BGYou captured the flag!"
-msgstr "^BGVocê capturou a bandeira!"
+msgstr "^BGCapturaste a bandeira!"
 
 #: qcsrc/common/notifications/all.inc:560
 #, c-format
 msgid "^BGToo many flag throws! Throwing disabled for %s."
-msgstr ""
-"^BGNão largue a bandeira várias vezes! Agora você não pode largar por %s."
+msgstr "^BGNão largues a bandeira várias vezes! Agora não podes largar por %s."
 
 #: qcsrc/common/notifications/all.inc:561
 #, c-format
@@ -3292,193 +3292,195 @@ msgstr "^BG%s^BG passou a bandeira para %s"
 #: qcsrc/common/notifications/all.inc:563
 #, c-format
 msgid "^BGYou received the ^TC^TT^BG flag from %s"
-msgstr "^BGVocê recebeu a bandeira ^TC^TT^BG de %s"
+msgstr "^BGRecebeste a bandeira ^TC^TT^BG de %s"
 
 #: qcsrc/common/notifications/all.inc:564
 #, c-format
 msgid "^BGYou received the flag from %s"
-msgstr "^BGVocê recebeu a bandeira de %s"
+msgstr "^BGRecebeste a bandeira de %s"
 
 #: qcsrc/common/notifications/all.inc:565
 #, c-format
 msgid "^BGPress ^F2%s^BG to receive the flag from %s^BG"
-msgstr "^BGAperte ^F2%s^BG para receber a bandeira de %s^BG"
+msgstr "^BGPressiona ^F2%s^BG para receber a bandeira de %s^BG"
 
 #: qcsrc/common/notifications/all.inc:566
 #, c-format
 msgid "^BGRequesting %s^BG to pass you the flag"
-msgstr "^BGPedindo à %s^BG para que te passe a bandeira"
+msgstr "^BGA pedir a %s^BG para que te passe a bandeira"
 
 #: qcsrc/common/notifications/all.inc:567
 #, c-format
 msgid "^BGYou passed the ^TC^TT^BG flag to %s"
-msgstr "^BGVocê passou a bandeira ^TC^TT^BG para %s"
+msgstr "^BGPassaste a bandeira ^TC^TT^BG para %s"
 
 #: qcsrc/common/notifications/all.inc:568
 #, c-format
 msgid "^BGYou passed the flag to %s"
-msgstr "^BGVocê passou a bandeira para %s"
+msgstr "^BGPassaste a bandeira para %s"
 
 #: qcsrc/common/notifications/all.inc:569
 msgid "^BGYou got the ^TC^TT^BG flag!"
-msgstr "^BGVocê pegou a bandeira ^TC^TT^BG!"
+msgstr "^BGApanhaste a bandeira ^TC^TT^BG!"
 
 #: qcsrc/common/notifications/all.inc:570
 msgid "^BGYou got the flag!"
-msgstr "^BGVocê pegou a bandeira!"
+msgstr "^BGApanhaste a bandeira!"
 
 #: qcsrc/common/notifications/all.inc:571
 #, c-format
 msgid "^BGYou got your %steam^BG's flag, return it!"
-msgstr "^BGVocê pegou a bandeira da sua %sequipe^BG, retorne-a!"
+msgstr "^BGApanhaste a bandeira da tua %sequipa^BG, retorna-a!"
 
 #: qcsrc/common/notifications/all.inc:572
 #, c-format
 msgid "^BGYou got the %senemy^BG's flag, return it!"
-msgstr "^BGVocê pegou a bandeira da %sequipe inimiga^BG, retorne-a!"
+msgstr "^BGApanhaste a bandeira da %sequipa inimiga^BG, retorna-a!"
 
 #: qcsrc/common/notifications/all.inc:573
 #, c-format
 msgid "^BGThe %senemy^BG got your flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a sua bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a tua bandeira! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:574
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a sua bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a tua bandeira! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:575
 #, c-format
 msgid "^BGThe %senemy^BG got the flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a bandeira! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:576
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a bandeira! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:577
 #, c-format
 msgid "^BGThe %senemy^BG got their flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a bandeira deles! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a bandeira deles! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:578
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira deles! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a bandeira deles! Recupera-a!"
 
 #: qcsrc/common/notifications/all.inc:579
 #, c-format
 msgid "^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira ^TC^TT^BG! Proteja-o!"
+msgstr ""
+"^BGO teu %scolega de equipa^BG apanhou a bandeira ^TC^TT^BG! Protege-o!"
 
 #: qcsrc/common/notifications/all.inc:580
 #, c-format
 msgid "^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"
 msgstr ""
-"^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira ^TC^TT^BG! Proteja-"
-"o!"
+"^BGO teu %scolega de equipa (^BG%s%s)^BG apanhou a bandeira ^TC^TT^BG! "
+"Protege-o!"
 
 #: qcsrc/common/notifications/all.inc:581
 #, c-format
 msgid "^BGYour %steam mate^BG got the flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira! Proteja-o!"
+msgstr "^BGO teu %scolega de equipa^BG apanhou a bandeira! Protege-o!"
 
 #: qcsrc/common/notifications/all.inc:582
 #, c-format
 msgid "^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira! Proteja-o!"
+msgstr ""
+"^BGO teu %scolega de equipa (^BG%s%s)^BG apanhou a bandeira! Protege-o!"
 
 #: qcsrc/common/notifications/all.inc:583
 msgid "^BGEnemies can now see you on radar!"
-msgstr "^BGAgora os inimigos podem te ver no radar!"
+msgstr "^BGAgora os inimigos podem ver-te no radar!"
 
 #: qcsrc/common/notifications/all.inc:584
 msgid "^BGYou returned the ^TC^TT^BG flag!"
-msgstr "^BGVocê retornou a bandeira ^TC^TT^BG!"
+msgstr "^BGRetornaste a bandeira ^TC^TT^BG!"
 
 #: qcsrc/common/notifications/all.inc:585
 msgid "^BGStalemate! Enemies can now see you on radar!"
-msgstr "^BGCuidado! Agora os inimigos podem te ver no radar!"
+msgstr "^BGCuidado! Agora os inimigos podem ver-te no radar!"
 
 #: qcsrc/common/notifications/all.inc:586
 msgid "^BGStalemate! Flag carriers can now be seen by enemies on radar!"
 msgstr ""
-"^BGCuidado! Agora portadores da bandeira podem ser vistos pelos inimigos no "
-"radar!"
+"^BGCuidado! Agora os portadores da bandeira podem ser vistos pelos inimigos "
+"no radar!"
 
 #: qcsrc/common/notifications/all.inc:590
 #, c-format
 msgid "^K3%sYou fragged ^BG%s"
-msgstr "^K3%sVocê executou ^BG%s"
+msgstr "^K3%sExecutaste ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:591
 #: qcsrc/common/notifications/all.inc:600
 #: qcsrc/common/notifications/all.inc:609
 #, c-format
 msgid "^K3%sYou scored against ^BG%s"
-msgstr "^K3%sVocê pontuou contra ^BG%s"
+msgstr "^K3%sPontuaste contra ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:592
 #, c-format
 msgid "^K1%sYou were fragged by ^BG%s"
-msgstr "^K1%sVocê foi executado por ^BG%s"
+msgstr "^K1%sFoste executado por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:593
 #: qcsrc/common/notifications/all.inc:602
 #: qcsrc/common/notifications/all.inc:611
 #, c-format
 msgid "^K1%sYou were scored against by ^BG%s"
-msgstr "^K1%sVocê foi pontuado contra por ^BG%s"
+msgstr "^K1%sFoste pontuado contra por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:599
 #, c-format
 msgid "^K3%sYou burned ^BG%s"
-msgstr "^K3%sVocê queimou ^BG%s"
+msgstr "^K3%sQueimaste ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:601
 #, c-format
 msgid "^K1%sYou were burned by ^BG%s"
-msgstr "^K1%sVocê foi queimado por ^BG%s"
+msgstr "^K1%sFoste queimado por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:608
 #, c-format
 msgid "^K3%sYou froze ^BG%s"
-msgstr "^K3%sVocê congelou ^BG%s"
+msgstr "^K3%sCongelaste ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:610
 #, c-format
 msgid "^K1%sYou were frozen by ^BG%s"
-msgstr "^K1%sVocê foi congelado por ^BG%s"
+msgstr "^K1%sFoste congelado por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:617
 #, c-format
 msgid "^K1%sYou typefragged ^BG%s"
-msgstr "^K1%sVocê executou ^BG%s enquanto digitava"
+msgstr "^K1%sExecutaste ^BG%s enquanto escrevias"
 
 #: qcsrc/common/notifications/all.inc:618
 #, c-format
 msgid "^K1%sYou scored against ^BG%s^K1 while they were typing"
-msgstr "^K1%sVocê pontuou contra ^BG%s^K1 enquanto estavam digitando"
+msgstr "^K1%sPontuaste contra ^BG%s^K1 enquanto estavam a escrever"
 
 #: qcsrc/common/notifications/all.inc:619
 #, c-format
 msgid "^K1%sYou were typefragged by ^BG%s"
-msgstr "^K1%sVocê foi executado enquanto digitava por ^BG%s"
+msgstr "^K1%sFoste executado enquanto escrevias por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:620
 #, c-format
 msgid "^K1%sYou were scored against by ^BG%s^K1 while typing"
-msgstr "^K1%sVocê foi pontuado contra enquanto digitava por ^BG%s^K1"
+msgstr "^K1%sFoste pontuado contra enquanto escrevias por ^BG%s^K1"
 
 #: qcsrc/common/notifications/all.inc:626
 #, c-format
 msgid "^BGPress ^F2%s^BG again to toss the nade!"
-msgstr "^BGAperte ^F2%s^BG de novo para lançar a granada!"
+msgstr "^BGPressiona ^F2%s^BG de novo para lançar a granada!"
 
 #: qcsrc/common/notifications/all.inc:627
 msgid "^F2You got a ^K1BONUS GRENADE^F2!"
-msgstr "^F2Você pegou uma ^K1GRANADA BÔNUS^F2!"
+msgstr "^F2Apanhaste uma ^K1GRANADA BÓNUS^F2!"
 
 #: qcsrc/common/notifications/all.inc:629
 #, c-format
@@ -3486,236 +3488,236 @@ msgid ""
 "^BGYou have been moved into a different team\n"
 "You are now on: %s"
 msgstr ""
-"^BGVocê foi movido para uma equipe diferente\n"
-"Agora você está na equipe: %s"
+"^BGFoste movido para uma equipa diferente\n"
+"Agora estás na equipa: %s"
 
 #: qcsrc/common/notifications/all.inc:630
 msgid "^K1Don't go against your team mates!"
-msgstr "^K1Não vá contra seus colegas de equipe!"
+msgstr "^K1Não vás contra os teus colegas de equipa!"
 
 #: qcsrc/common/notifications/all.inc:630
 msgid "^K1Don't shoot your team mates!"
-msgstr "^K1Não atire nos seus colegas de equipe!"
+msgstr "^K1Não atires nos teus colegas de equipa!"
 
 #: qcsrc/common/notifications/all.inc:631
 msgid "^K1Die camper!"
-msgstr "^K1Morra, camper!"
+msgstr "^K1Morre campista!"
 
 #: qcsrc/common/notifications/all.inc:631
 msgid "^K1Reconsider your tactics, camper!"
-msgstr "^K1Reconsidere suas táticas, camper!"
+msgstr "^K1Reconsidera as tuas táticas, campista!"
 
 #: qcsrc/common/notifications/all.inc:632
 msgid "^K1You unfairly eliminated yourself!"
-msgstr "^K1Você se matou injustamente!"
+msgstr "^K1Eliminaste-te injustamente!"
 
 #: qcsrc/common/notifications/all.inc:633
 #, c-format
 msgid "^K1You were %s"
-msgstr "^K1Você foi %s"
+msgstr "^K1Foste %s"
 
 #: qcsrc/common/notifications/all.inc:634
 msgid "^K1You couldn't catch your breath!"
-msgstr "^K1Você não recuperou seu fôlego!"
+msgstr "^K1Não recuperaste o fôlego!"
 
 #: qcsrc/common/notifications/all.inc:635
 msgid "^K1You hit the ground with a crunch!"
-msgstr "^K1Você caiu no chão rigorosamente!"
+msgstr "^K1Caíste no chão rigorosamente!"
 
 #: qcsrc/common/notifications/all.inc:636
 msgid "^K1You felt a little too hot!"
-msgstr "^K1Você se sentiu um pouco quente!"
+msgstr "^K1Sentiste-te um pouco quente!"
 
 #: qcsrc/common/notifications/all.inc:636
 msgid "^K1You got a little bit too crispy!"
-msgstr "^K1Você ficou um pouco crocante demais!"
+msgstr "^K1Fiscaste um bocadinho estaladiço!"
 
 #: qcsrc/common/notifications/all.inc:637
 msgid "^K1You killed your own dumb self!"
-msgstr "^K1Você se matou, seu burro!"
+msgstr "^K1Mataste-te seu burro!"
 
 #: qcsrc/common/notifications/all.inc:637
 msgid "^K1You need to be more careful!"
-msgstr "^K1Você precisa ter mais cuidado!"
+msgstr "^K1tens de ter mais cuidado!"
 
 #: qcsrc/common/notifications/all.inc:638
 msgid "^K1You couldn't stand the heat!"
-msgstr "^K1Você não suportou o calor!"
+msgstr "^K1Não suportaste o calor!"
 
 #: qcsrc/common/notifications/all.inc:639
 msgid "^K1You need to watch out for monsters!"
-msgstr "^K1Você tem que se cuidar dos monstros!"
+msgstr "^K1Tens de ter um olho nos monstros!"
 
 #: qcsrc/common/notifications/all.inc:639
 msgid "^K1You were killed by a monster!"
-msgstr "^K1Você foi morto por um monstro!"
+msgstr "^K1Foste morto por um monstro!"
 
 #: qcsrc/common/notifications/all.inc:640
 msgid "^K1Tastes like chicken!"
-msgstr "^K1Tem gosto de frango!"
+msgstr "^K1Sabe a frango!"
 
 #: qcsrc/common/notifications/all.inc:640
 msgid "^K1You forgot to put the pin back in!"
-msgstr "^K1Você se esqueceu de pôr o pino de volta!"
+msgstr "^K1Esqueceste-te de tornar a pôr o pino!"
 
 #: qcsrc/common/notifications/all.inc:641
 msgid "^K1Hanging around a napalm explosion is bad!"
-msgstr "^K1Brincar no meio de uma explosão de napalm é errado!"
+msgstr "^K1Brincar no meio de uma explosão de napalm é perigoso!"
 
 #: qcsrc/common/notifications/all.inc:642
 msgid "^K1You felt a little chilly!"
-msgstr "^K1Você sentiu um pouco de frio!"
+msgstr "^K1Sentiste um pouco de frio!"
 
 #: qcsrc/common/notifications/all.inc:642
 msgid "^K1You got a little bit too cold!"
-msgstr "^K1Você ficou um pouco gelado demais!"
+msgstr "^K1Ficaste um pouco gelado!"
 
 #: qcsrc/common/notifications/all.inc:643
 msgid "^K1Your Healing Nade is a bit defective"
-msgstr "^K1Sua Granada de Cura está um pouco defeituosa"
+msgstr "^K1A tua Granada de Cura está um pouco defeituosa"
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You are respawning for running out of ammo..."
-msgstr "^K1Você está ressurgindo por ficar sem munição..."
+msgstr "^K1Estás a ressurgir por ficares sem munições..."
 
 #: qcsrc/common/notifications/all.inc:644
 msgid "^K1You were killed for running out of ammo..."
-msgstr "^K1Você foi morto por ficar sem munição..."
+msgstr "^K1Foste morto por ficar sem munições..."
 
 #: qcsrc/common/notifications/all.inc:645
 msgid "^K1You grew too old without taking your medicine"
-msgstr "^K1Você ficou muito velho sem tomar o seu medicamento"
+msgstr "^K1Ficaste demasiado velho sem tomares o teu medicamento"
 
 #: qcsrc/common/notifications/all.inc:645
 msgid "^K1You need to preserve your health"
-msgstr "^K1Você precisa conservar sua saúde"
+msgstr "^K1Tens de conservar a tua saúde"
 
 #: qcsrc/common/notifications/all.inc:646
 msgid "^K1You became a shooting star!"
-msgstr "^K1Você virou uma estrela cadente!"
+msgstr "^K1Tornaste-te numa estrela cadente!"
 
 #: qcsrc/common/notifications/all.inc:647
 msgid "^K1You melted away in slime!"
-msgstr "^K1Você derreteu na lama!"
+msgstr "^K1Derreteste-te na lama!"
 
 #: qcsrc/common/notifications/all.inc:648
 msgid "^K1You committed suicide!"
-msgstr "^K1Você cometeu suicídio!"
+msgstr "^K1Cometeste suicídio!"
 
 #: qcsrc/common/notifications/all.inc:648
 msgid "^K1You ended it all!"
-msgstr "^K1Você acabou com tudo!"
+msgstr "^K1Acabaste com tudo!"
 
 #: qcsrc/common/notifications/all.inc:649
 msgid "^K1You got stuck in a swamp!"
-msgstr "^K1Você ficou preso em um pântano!"
+msgstr "^K1Ficaste preso num pântano!"
 
 #: qcsrc/common/notifications/all.inc:650
 #, c-format
 msgid "^BGYou are now on: %s"
-msgstr "^BGVocê está agora em: %s"
+msgstr "^BGEstás agora em: %s"
 
 #: qcsrc/common/notifications/all.inc:651
 msgid "^K1You died in an accident!"
-msgstr "^K1Você morreu em um acidente!"
+msgstr "^K1Morreste num acidente!"
 
 #: qcsrc/common/notifications/all.inc:652
 msgid "^K1You had an unfortunate run in with a turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela!"
 
 #: qcsrc/common/notifications/all.inc:652
 msgid "^K1You were fragged by a turret!"
-msgstr "^K1Você foi executado por uma sentinela!"
+msgstr "^K1Foste executado por uma sentinela!"
 
 #: qcsrc/common/notifications/all.inc:653
 msgid "^K1You had an unfortunate run in with an eWheel turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela eWheel!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela eWheel!"
 
 #: qcsrc/common/notifications/all.inc:653
 msgid "^K1You were fragged by an eWheel turret!"
-msgstr "^K1Você foi executado por uma sentinela eWheel!"
+msgstr "^K1Foste executado por uma sentinela eWheel!"
 
 #: qcsrc/common/notifications/all.inc:654
 msgid "^K1You had an unfortunate run in with a Walker turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela Walker!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela Walker!"
 
 #: qcsrc/common/notifications/all.inc:654
 msgid "^K1You were fragged by a Walker turret!"
-msgstr "^K1Você foi executado por uma sentinela Walker!"
+msgstr "^K1FOste executado por uma sentinela Walker!"
 
 #: qcsrc/common/notifications/all.inc:655
 msgid "^K1You got caught in the blast of a Bumblebee explosion!"
-msgstr "^K1Você foi pego pelo raio de uma explosão de Bumblebee!"
+msgstr "^K1Foste apanhado pelo raio de uma explosão de Bumblebee!"
 
 #: qcsrc/common/notifications/all.inc:656
 msgid "^K1You were crushed by a vehicle!"
-msgstr "^K1Você foi esmagado por um veículo!"
+msgstr "^K1Foste esmagado por um veículo!"
 
 #: qcsrc/common/notifications/all.inc:657
 msgid "^K1You were caught in a Raptor cluster bomb!"
-msgstr "^K1Você foi pego por uma bomba Raptor!"
+msgstr "^K1Foste apanhado por uma bomba Raptor!"
 
 #: qcsrc/common/notifications/all.inc:658
 msgid "^K1You got caught in the blast of a Raptor explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Raptor!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Raptor!"
 
 #: qcsrc/common/notifications/all.inc:659
 msgid "^K1You got caught in the blast of a Spiderbot explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Spiderbot!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Robô Aranha!"
 
 #: qcsrc/common/notifications/all.inc:660
 msgid "^K1You were blasted to bits by a Spiderbot rocket!"
-msgstr "^K1Você foi despedaçado por um foguete de Spiderbot!"
+msgstr "^K1Foste despedaçado por um míssil de Robô Aranha!"
 
 #: qcsrc/common/notifications/all.inc:661
 msgid "^K1You got caught in the blast of a Racer explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Racer!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Racer!"
 
 #: qcsrc/common/notifications/all.inc:662
 msgid "^K1You couldn't find shelter from a Racer rocket!"
-msgstr "^K1Você não conseguiu escapar do foguete de um Racer!"
+msgstr "^K1Não conseguiste escapar do míssil de um Racer!"
 
 #: qcsrc/common/notifications/all.inc:663
 msgid "^K1Watch your step!"
-msgstr "^K1Cuidado onde pisa!"
+msgstr "^K1Cuidado com o que pisas!"
 
 #: qcsrc/common/notifications/all.inc:665
 #, c-format
 msgid "^K1Moron! You fragged ^BG%s^K1, a team mate!"
-msgstr "^K1Idiota! Você executou ^BG%s^K1, um colega de equipe!"
+msgstr "^K1Idiota! Executaste ^BG%s^K1, um colega de equipa!"
 
 #: qcsrc/common/notifications/all.inc:665
 #, c-format
 msgid "^K1Moron! You went against ^BG%s^K1, a team mate!"
-msgstr "^K1Idiota! Você foi contra ^BG%s^K1, um colega de equipe!"
+msgstr "^K1Idiota! Foste contra ^BG%s^K1, um colega de equipa!"
 
 #: qcsrc/common/notifications/all.inc:666
 #, c-format
 msgid "^K1You were fragged by ^BG%s^K1, a team mate"
-msgstr "^K1Você foi executado por ^BG%s^K1, um colega de equipe"
+msgstr "^K1Foste executado por ^BG%s^K1, um colega de equipa"
 
 #: qcsrc/common/notifications/all.inc:666
 #, c-format
 msgid "^K1You were scored against by ^BG%s^K1, a team mate"
-msgstr "^K1Você foi pontuado contra por ^BG%s^K1, um colega de equipe"
+msgstr "^K1Foste pontuado contra por ^BG%s^K1, um colega de equipa"
 
 #: qcsrc/common/notifications/all.inc:668
 msgid ""
 "^K1Stop idling!\n"
 "^BGDisconnecting in ^COUNT..."
 msgstr ""
-"^K1Pare de ficar AFK!\n"
-"^BGDesconectando em ^COUNT..."
+"^K1Para de ficar parado!\n"
+"^BGA desconectar em ^COUNT..."
 
 #: qcsrc/common/notifications/all.inc:670
 #, c-format
 msgid "^BGYou need %s^BG!"
-msgstr "^BGVocê precisa %s^BG!"
+msgstr "^BGPrecisas de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:671
 #, c-format
 msgid "^BGYou also need %s^BG!"
-msgstr "^BGVocê também precisa %s^BG!"
+msgstr "^BGTambém precisas de %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:672
 msgid "^BGDoor unlocked!"
@@ -3723,42 +3725,42 @@ msgstr "^BGPorta destrancada!"
 
 #: qcsrc/common/notifications/all.inc:674
 msgid "^F2You picked up some extra lives"
-msgstr "^F2Você pegou algumas vidas extras"
+msgstr "^F2Apanhaste algumas vidas extra"
 
 #: qcsrc/common/notifications/all.inc:676
 #, c-format
 msgid "^K3You revived ^BG%s"
-msgstr "^K3Você ressuscitou ^BG%s"
+msgstr "^K3Ressuscitaste ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:677
 msgid "^K3You revived yourself"
-msgstr "^K3Você se ressuscitou"
+msgstr "^K3Ressuscitaste-te"
 
 #: qcsrc/common/notifications/all.inc:678
 #, c-format
 msgid "^K3You were revived by ^BG%s"
-msgstr "^K3Você foi ressuscitado por ^BG%s"
+msgstr "^K3Foste ressuscitado por ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:679
 #, c-format
 msgid "^K3You were automatically revived after %s second(s)"
-msgstr "^K3Você foi automaticamente ressuscitado após %s segundo(s)"
+msgstr "^K3Foste automaticamente ressuscitado após %s segundo(s)"
 
 #: qcsrc/common/notifications/all.inc:681
 msgid "^BGThe generator is under attack!"
-msgstr "^BGO gerador está sobre ataque!"
+msgstr "^BGO gerador está a ser atacado!"
 
 #: qcsrc/common/notifications/all.inc:683
 msgid "^TC^TT^BG team loses the round"
-msgstr "A equipe ^TC^TT^BG perdeu a rodada"
+msgstr "A equipa ^TC^TT^BG perdeu a rodada"
 
 #: qcsrc/common/notifications/all.inc:687
 msgid "^K1You froze yourself"
-msgstr "^K1Você se congelou"
+msgstr "^K1Congelaste-te"
 
 #: qcsrc/common/notifications/all.inc:688
 msgid "^K1Round already started, you spawn as frozen"
-msgstr "^K1A rodada já começou, você surgiu congelado"
+msgstr "^K1A rodada já começou, surgiste congelado"
 
 #: qcsrc/common/notifications/all.inc:690
 #, c-format
@@ -3767,11 +3769,11 @@ msgstr "^K1Um %s chegou!"
 
 #: qcsrc/common/notifications/all.inc:694
 msgid "^BGYou got the ^F1Fuel regenerator"
-msgstr "^BGVocê pegou o ^F1Regenerador de combustível"
+msgstr "^BGApanhaste o ^F1Regenerador de combustível"
 
 #: qcsrc/common/notifications/all.inc:695
 msgid "^BGYou got the ^F1Jet pack"
-msgstr "^BGVocê pegou a ^F1Mochila a Jato"
+msgstr "^BGApanhaste a ^F1Mochila a Jato"
 
 #: qcsrc/common/notifications/all.inc:703
 msgid ""
@@ -3779,64 +3781,63 @@ msgid ""
 "Hope your team can fix it..."
 msgstr ""
 "^K1Não há pontos de surgimento disponíveis!\n"
-"Tomara que sua equipe consiga consertar isso..."
+"Oxalá que a tua equipa consiga corrigir isso..."
 
 #: qcsrc/common/notifications/all.inc:704
 msgid ""
 "^K1You may not join the game at this time.\n"
 "The player limit reached maximum capacity."
 msgstr ""
-"^K1Você não pode entrar no jogo neste momento.\n"
-"A capacidade máxima de jogadores foi alcançada."
+"^K1Não podes entrar no jogo neste momento.\n"
+"A capacidade máxima de jogadores foi atingida."
 
 #: qcsrc/common/notifications/all.inc:708
 msgid "^BGYou picked up the ball"
-msgstr "^BGVocê pegou a bola"
+msgstr "^BGApanhaste a bola"
 
 #: qcsrc/common/notifications/all.inc:709
 msgid "^BGKilling people while you don't have the ball gives no points!"
-msgstr "^BGMatar os outros enquanto você não tiver a bola não lhe dará pontos!"
+msgstr "^BGMatar os outros enquanto não tiveres a bola não ganharás pontos!"
 
 #: qcsrc/common/notifications/all.inc:711
 msgid ""
 "^BGAll keys are in your team's hands!\n"
 "Help the key carriers to meet!"
 msgstr ""
-"^BGTodas as chaves estão com a sua equipe!\n"
-"Ajude os portadores das chaves a se encontrarem!"
+"^BGTodas as chaves estão com a tua equipa!\n"
+"Ajuda os portadores das chaves a encontrarem-se!"
 
 #: qcsrc/common/notifications/all.inc:712
 msgid ""
 "^BGAll keys are in ^TC^TT team^BG's hands!\n"
 "Interfere ^F4NOW^BG!"
 msgstr ""
-"^BGTodas as chaves estão com a equipe ^TC^TT^BG!\n"
-"Interfira ^F4AGORA^BG!"
+"^BGTodas as chaves estão com a equipa ^TC^TT^BG!\n"
+"Interfere ^F4AGORA^BG!"
 
 #: qcsrc/common/notifications/all.inc:713
 msgid ""
 "^BGAll keys are in your team's hands!\n"
 "Meet the other key carriers ^F4NOW^BG!"
 msgstr ""
-"^BGTodas as chaves estão com a sua equipe!\n"
-"Encontre-se com os outros portadores das chaves ^F4AGORA^BG!"
+"^BGTodas as chaves estão com a tua equipa!\n"
+"Encontra-te com os outros portadores das chaves ^F4AGORA^BG!"
 
 #: qcsrc/common/notifications/all.inc:714
 msgid "^F4Round will start in ^COUNT"
-msgstr "^F4A rodada iniciará em ^COUNT"
+msgstr "^F4A rodada vai começar dentro de ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:715
 msgid "^BGScanning frequency range..."
-msgstr "^BGEscaneando alcance de frequência..."
+msgstr "^BGA varrer o alcance de frequência..."
 
 #: qcsrc/common/notifications/all.inc:716
 msgid "^BGYou are starting with the ^TC^TT Key"
-msgstr "^BGVocê está começando com a Chave ^TC^TT"
+msgstr "^BGEstás a começar com a Chave ^TC^TT"
 
 #: qcsrc/common/notifications/all.inc:718
 msgid "^BGYou have no lives left, you must wait until the next match"
-msgstr ""
-"^BGVocê não tem vidas sobrando, você terá que aguardar até a próxima partida"
+msgstr "^BGNão tens mais vidas, terás que esperar até à próxima partida"
 
 #: qcsrc/common/notifications/all.inc:720
 #, c-format
@@ -3844,29 +3845,29 @@ msgid ""
 "^BGWaiting for players to join...\n"
 "Need active players for: %s"
 msgstr ""
-"^BGEsperando jogadores entrarem...\n"
+"^BGà espera que os outros jogadores entrem...\n"
 "Precisa-se de jogadores ativos para: %s"
 
 #: qcsrc/common/notifications/all.inc:721
 #, c-format
 msgid "^BGWaiting for %s player(s) to join..."
-msgstr "^BGEsperando %s jogador(es) entrar(em)..."
+msgstr "^BGÀ espera de %s jogador(es) para entrar(em)..."
 
 #: qcsrc/common/notifications/all.inc:723
 msgid "^BGYour weapon has been downgraded until you find some ammo!"
-msgstr "^BGA sua arma foi rebaixada até que você encontre alguma munição!"
+msgstr "^BGA tua arma foi rebaixada até que encontres munições!"
 
 #: qcsrc/common/notifications/all.inc:724
 msgid "^F4^COUNT^BG left to find some ammo!"
-msgstr "^F4^COUNT^BG restante(s) para encontrar alguma munição!"
+msgstr "^F4^COUNT^BG restante(s) para encontrares algumas munições!"
 
 #: qcsrc/common/notifications/all.inc:725
 msgid "^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"
-msgstr "^BGEncontre alguma munição ou você morrerá em ^F4^COUNT^BG!"
+msgstr "^BGEncontra algumas munições ou morrerás em ^F4^COUNT^BG!"
 
 #: qcsrc/common/notifications/all.inc:725
 msgid "^BGGet some ammo! ^F4^COUNT^BG left!"
-msgstr "^BGEncontre alguma munição! Falta ^F4^COUNT^BG!"
+msgstr "^BGEncontra algumas munições! Falta ^F4^COUNT^BG!"
 
 #: qcsrc/common/notifications/all.inc:726
 #, c-format
@@ -3879,7 +3880,7 @@ msgid ""
 "^F2^COUNT^BG until weapon change...\n"
 "Next weapon: ^F1%s"
 msgstr ""
-"^F2^CONTAGEM^BG até a mudança de arma...\n"
+"^F2^CONTAGEM^BG até à mudança de arma...\n"
 "Próxima arma: ^F1%s"
 
 #: qcsrc/common/notifications/all.inc:731
@@ -3890,16 +3891,16 @@ msgstr "^F2Arma ativa: ^F1%s"
 #: qcsrc/common/notifications/all.inc:733
 #, c-format
 msgid "^BGYou captured %s^BG control point"
-msgstr "^BGVocê capturou o ponto de controle %s^BG"
+msgstr "^BGCapturaste o ponto de controlo %s^BG"
 
 #: qcsrc/common/notifications/all.inc:734
 #, c-format
 msgid "^TC^TT^BG team captured %s^BG control point"
-msgstr "A equipe ^TC^TT^BG capturou o ponto de controle %s^BG"
+msgstr "A equipa ^TC^TT^BG capturou o ponto de controlo %s^BG"
 
 #: qcsrc/common/notifications/all.inc:735
 msgid "^BGThis control point currently cannot be captured"
-msgstr "^BGEste ponto de controle atualmente não pode ser capturado"
+msgstr "^BGEste ponto de controlo não pode ser capturado neste momento"
 
 #: qcsrc/common/notifications/all.inc:736
 msgid ""
@@ -3907,7 +3908,7 @@ msgid ""
 "^F2Capture some control points to unshield it"
 msgstr ""
 "^BGO gerador inimigo ainda não pode ser destruído\n"
-"^F2Capture alguns pontos de controle para desprotegê-lo"
+"^F2Captura alguns pontos de controlo para desprotegê-lo"
 
 #: qcsrc/common/notifications/all.inc:737
 msgid "^BGThe ^TCenemy^BG generator is no longer shielded!"
@@ -3918,34 +3919,34 @@ msgid ""
 "^K1Your generator is NOT shielded!\n"
 "^BGRe-capture control points to shield it!"
 msgstr ""
-"^K1O seu gerador NÃO está blindado!\n"
-"^BGRecapture pontos de controle para blindá-lo!"
+"^K1O teu gerador NÃO está blindado!\n"
+"^BGRecaptura pontos de controlo para blindá-lo!"
 
 #: qcsrc/common/notifications/all.inc:739
 #, c-format
 msgid "^BGPress ^F2%s^BG to teleport"
-msgstr "^BGAperte ^F2%s^BG para se teletransportar"
+msgstr "^BGPressiona ^F2%s^BG para te teletransportares"
 
 #: qcsrc/common/notifications/all.inc:740
 #, c-format
 msgid "^BGTeleporting disabled for %s"
-msgstr "^BGTeletransporte desabilitado para %s"
+msgstr "^BGTeletransporte desativado para %s"
 
 #: qcsrc/common/notifications/all.inc:742
 msgid ""
 "^F2Now playing ^F4OVERTIME^F2!\n"
 "Keep fragging until we have a winner!"
 msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
-"Continue executando até que tenhamos um vencedor!"
+"^F2A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continua a executar até que tenhamos um vencedor!"
 
 #: qcsrc/common/notifications/all.inc:742
 msgid ""
 "^F2Now playing ^F4OVERTIME^F2!\n"
 "Keep scoring until we have a winner!"
 msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
-"Continue pontuando até que tenhamos um vencedor!"
+"^A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continua a pontuar até que tenhamos um vencedor!"
 
 #: qcsrc/common/notifications/all.inc:743
 msgid ""
@@ -3955,10 +3956,10 @@ msgid ""
 "The more control points your team holds,\n"
 "the faster the enemy generator decays"
 msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
+"^F2A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
 "\n"
-"Os geradores estão enfraquecendo agora.\n"
-"Quanto mais pontos de controle a sua equipe tiver,\n"
+"Os geradores estão agora a enfraquecer.\n"
+"Quanto mais pontos de controlo a sua equipa tiver,\n"
 "mais rápido o gerador inimigo enfraquecerá"
 
 #: qcsrc/common/notifications/all.inc:744
@@ -3967,68 +3968,68 @@ msgid ""
 "^F2Now playing ^F4OVERTIME^F2!\n"
 "^BGAdded ^F4%s^BG to the game!"
 msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
-"^BGAdicionado ^F4%s^BG à partida!"
+"^F2A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
+"^BGFoi adicionado ^F4%s^BG ao jogo!"
 
 #: qcsrc/common/notifications/all.inc:746
 msgid "^K1In^BG-portal created"
-msgstr "^K1^BGPortal de entrada criado"
+msgstr "^K1^BGCriado portal de entrada"
 
 #: qcsrc/common/notifications/all.inc:747
 msgid "^F3Out^BG-portal created"
-msgstr "^F3^BGPortal de saída criado"
+msgstr "^F3^BGCriado portal de saída"
 
 #: qcsrc/common/notifications/all.inc:748
 msgid "^F1Portal creation failed"
-msgstr "^F1Falha ao criar portal"
+msgstr "^F1Falha ao criar portal"
 
 #: qcsrc/common/notifications/all.inc:750
 msgid "^F2Strength infuses your weapons with devastating power"
-msgstr "^F2A Força deixou suas armas com um poder devastador"
+msgstr "^F2A Força deixou as tuas armas com um poder devastador"
 
 #: qcsrc/common/notifications/all.inc:751
 msgid "^F2Strength has worn off"
-msgstr "^F2A Força se esgotou"
+msgstr "^F2A Força esgotou-se"
 
 #: qcsrc/common/notifications/all.inc:753
 msgid "^F2Shield surrounds you"
-msgstr "^F2O Escudo te cerca"
+msgstr "^F2O Escudo envolve-te"
 
 #: qcsrc/common/notifications/all.inc:754
 msgid "^F2Shield has worn off"
-msgstr "^F2O Escudo se esgotou"
+msgstr "^F2O Escudo esgotou-se"
 
 #: qcsrc/common/notifications/all.inc:756
 msgid "^F2You are on speed"
-msgstr "^F2Você tem a velocidade"
+msgstr "^F2Tens a velocidade"
 
 #: qcsrc/common/notifications/all.inc:757
 msgid "^F2Speed has worn off"
-msgstr "^F2A Velocidade se esgotou"
+msgstr "^F2A Velocidade esgotou-se"
 
 #: qcsrc/common/notifications/all.inc:759
 msgid "^F2You are invisible"
-msgstr "^F2Você está invisível"
+msgstr "^F2Estás invisível"
 
 #: qcsrc/common/notifications/all.inc:760
 msgid "^F2Invisibility has worn off"
-msgstr "^F2A Invisibilidade se esgotou"
+msgstr "^F2A Invisibilidade esgotou-se"
 
 #: qcsrc/common/notifications/all.inc:762
 msgid "^F2The race is over, finish your lap!"
-msgstr "^F2A corrida acabou, termine sua volta!"
+msgstr "^F2A corrida acabou, termina a tua volta!"
 
 #: qcsrc/common/notifications/all.inc:764
 msgid "^BGSecondary fire inflicts no damage!"
-msgstr "^BGModo de disparo secundário não causa dano!"
+msgstr "^BGO modo de disparo secundário não causa dano!"
 
 #: qcsrc/common/notifications/all.inc:766
 msgid "^BGSequence completed!"
-msgstr "^BGSequência completada!"
+msgstr "^BGSequência completa!"
 
 #: qcsrc/common/notifications/all.inc:767
 msgid "^BGThere are more to go..."
-msgstr "^BGAinda tem mais..."
+msgstr "^BGAinda  mais..."
 
 #: qcsrc/common/notifications/all.inc:768
 #, c-format
@@ -4037,7 +4038,7 @@ msgstr "^BGSó falta(m) %s^BG..."
 
 #: qcsrc/common/notifications/all.inc:770
 msgid "^F2Superweapons have broken down"
-msgstr "^F2As Superarmas quebraram"
+msgstr "^F2As Superarmas estão partidas"
 
 #: qcsrc/common/notifications/all.inc:771
 msgid "^F2Superweapons have been lost"
@@ -4045,67 +4046,67 @@ msgstr "^F2As Superarmas foram perdidas"
 
 #: qcsrc/common/notifications/all.inc:772
 msgid "^F2You now have a superweapon"
-msgstr "^F2Agora você tem uma Superarma"
+msgstr "^F2Agora tens uma Superarma"
 
 #: qcsrc/common/notifications/all.inc:774
 msgid "^K1Changing to ^TC^TT^K1 in ^COUNT"
-msgstr "^K1Trocando para ^TC^TT^K1 em ^COUNT"
+msgstr "^K1A trocar para ^TC^TT^K1 em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:775
 msgid "^K1Changing team in ^COUNT"
-msgstr "^K1Trocando de equipe em ^COUNT"
+msgstr "^K1A trocar de equipa em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:776
 msgid "^K1Spectating in ^COUNT"
-msgstr "^K1Trocando para espectador em ^COUNT"
+msgstr "^K1A trocar para espetador em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:777
 msgid "^K1Suicide in ^COUNT"
-msgstr "^K1Cometendo suicídio em ^COUNT"
+msgstr "^K1A cometer suicídio em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:779
 msgid "^F4Timeout begins in ^COUNT"
-msgstr "^F4Pausa iniciará em ^COUNT"
+msgstr "^F4A pausa começa em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:780
 msgid "^F4Timeout ends in ^COUNT"
-msgstr "^F4Pausa acabará em ^COUNT"
+msgstr "^F4A pausa termina em ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:782
 msgid "^K1Cannot join given minigame session!"
-msgstr "^K1Não foi possível entrar na sessão de mini jogo fornecida!"
+msgstr "^K1Não foi possível entrar na sessão de mini-jogo!"
 
 #: qcsrc/common/notifications/all.inc:784
 #, c-format
 msgid "^BGPress ^F2%s^BG to enter/exit the vehicle"
-msgstr "^BGAperte ^F2%s^BG para entrar/sair do veículo"
+msgstr "^BGPressiona ^F2%s^BG para entrar/sair do veículo"
 
 #: qcsrc/common/notifications/all.inc:785
 #, c-format
 msgid "^BGPress ^F2%s^BG to enter the vehicle gunner"
-msgstr "^BGAperte ^F2%s^BG para usar a arma do veículo"
+msgstr "^BGPressiona ^F2%s^BG para usar a arma do veículo"
 
 #: qcsrc/common/notifications/all.inc:786
 #, c-format
 msgid "^BGPress ^F2%s^BG to steal this vehicle"
-msgstr "^BGAperte ^F2%s^BG para roubar este veículo"
+msgstr "^BGPressiona ^F2%s^BG para roubar este veículo"
 
 #: qcsrc/common/notifications/all.inc:787
 msgid ""
 "^F2The enemy is stealing one of your vehicles!\n"
 "^F4Stop them!"
 msgstr ""
-"^F2O inimigo está roubando um de seus veículos!\n"
-"^F4Impeça-os!"
+"^F2O inimigo está a roubar um dos teus veículos!\n"
+"^F4Impede-os!"
 
 #: qcsrc/common/notifications/all.inc:788
 msgid "^F2Intruder detected, disabling shields!"
-msgstr "^F2Intruso detectado, desativando escudos!"
+msgstr "^F2Intruso detetado, a desativar escudos!"
 
 #: qcsrc/common/notifications/all.qh:188
 msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
 msgstr ""
-"Comando de despejo de notificação funciona apenas com cl_cmd e sv_cmd.\n"
+"O comando de notificação despejo funciona apenas com cl_cmd e sv_cmd.\n"
 
 #: qcsrc/common/notifications/all.qh:399 qcsrc/common/notifications/all.qh:400
 #, c-format
@@ -4134,7 +4135,7 @@ msgstr "largar bandeira"
 
 #: qcsrc/common/notifications/all.qh:420
 msgid "throw nade"
-msgstr "arremessar granada"
+msgstr "atirar granada"
 
 #: qcsrc/common/notifications/all.qh:431
 #, c-format
@@ -4186,7 +4187,7 @@ msgstr "MASSACRE! "
 #: qcsrc/common/notifications/all.qh:447
 #, c-format
 msgid "%s^K1 executed MAYHEM! %s^BG"
-msgstr "%s^K1 executou uma MUTILAÇÃO! %s^BG"
+msgstr "%s^K1 fez uma MUTILAÇÃO! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:447
 #, c-format
@@ -4214,7 +4215,7 @@ msgstr "FURIOSO!"
 #: qcsrc/common/notifications/all.qh:449
 #, c-format
 msgid "%s^K1 inflicts CARNAGE! %s^BG"
-msgstr "%s^K1 está infligindo CARNIFICINA! %s^BG"
+msgstr "%s^K1 está a infligir uma CARNIFICINA! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:449
 #, c-format
@@ -4233,11 +4234,11 @@ msgstr "%s^K1 fez TRINTA PONTUAÇÕES SEGUIDAS! %s^BG"
 #: qcsrc/common/notifications/all.qh:450
 #, c-format
 msgid "%s^K1 unleashes ARMAGEDDON! %s^BG"
-msgstr "%s^K1 desencadeou o ARMAGEDOM! %s^BG"
+msgstr "%s^K1 desencadeou o Fim do Mundo! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:450
 msgid "ARMAGEDDON! "
-msgstr "ARMAGEDDON! "
+msgstr "Fim do Mundo! "
 
 #: qcsrc/common/notifications/all.qh:457
 #, c-format
@@ -4256,7 +4257,7 @@ msgid ""
 "(Health ^1%d^BG / Armor ^2%d^BG)%s"
 msgstr ""
 "\n"
-"(Saúde ^1%d^BG / Armadura ^2%d^BG)%s"
+"(Vida ^1%d^BG / Armadura ^2%d^BG)%s"
 
 #: qcsrc/common/notifications/all.qh:468
 #, c-format
@@ -4316,22 +4317,22 @@ msgstr "%s^K1 foi o primeiro a pontuar! %s^BG"
 #: qcsrc/common/notifications/all.qh:595
 #, c-format
 msgid ", ending their %d frag spree"
-msgstr ", finalizando sua cadeia de %d execuções"
+msgstr ", a finalizar a sua cadeia de %d execuções"
 
 #: qcsrc/common/notifications/all.qh:596
 #, c-format
 msgid ", ending their %d score spree"
-msgstr ", finalizando sua cadeia de %d pontuações"
+msgstr ", a finalizar a sua cadeia de %d pontuações"
 
 #: qcsrc/common/notifications/all.qh:610
 #, c-format
 msgid ", losing their %d frag spree"
-msgstr ", perdendo sua cadeia de %d execuções"
+msgstr ", a perder a sua cadeia de %d execuções"
 
 #: qcsrc/common/notifications/all.qh:611
 #, c-format
 msgid ", losing their %d score spree"
-msgstr ", perdendo sua cadeia de %d pontuações"
+msgstr ", a perder a sua cadeia de %d pontuações"
 
 #: qcsrc/common/teams.qh:29
 msgid "TEAM^Red"
@@ -4351,7 +4352,7 @@ msgstr "Rosa"
 
 #: qcsrc/common/teams.qh:33
 msgid "Team"
-msgstr "Equipe"
+msgstr "Equipa"
 
 #: qcsrc/common/teams.qh:34
 msgid "Neutral"
@@ -4412,7 +4413,7 @@ msgstr "O comando de despejo de sentinelas funciona apenas com sv_cmd.\n"
 #: qcsrc/common/turrets/cl_turrets.qc:129
 #, c-format
 msgid "%s under attack!"
-msgstr "%s sobre ataque!"
+msgstr "%s sob ataque!"
 
 #: qcsrc/common/turrets/turret.qh:11
 msgid "Turret"
@@ -4452,7 +4453,7 @@ msgstr "Sentinela Hunter-Killer"
 
 #: qcsrc/common/turrets/turret/hk_weapon.qh:7
 msgid "Hunter-Killer"
-msgstr "Hunter-Killer"
+msgstr ""
 
 #: qcsrc/common/turrets/turret/machinegun.qh:13
 msgid "Machinegun Turret"
@@ -4476,7 +4477,7 @@ msgstr "Canhão Phaser"
 
 #: qcsrc/common/turrets/turret/phaser_weapon.qh:7
 msgid "Phaser"
-msgstr "Phaser"
+msgstr ""
 
 #: qcsrc/common/turrets/turret/plasma.qh:13
 msgid "Plasma Cannon"
@@ -4510,23 +4511,23 @@ msgstr "Walker"
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 #, c-format
 msgid "Press %s"
-msgstr "Aperte %s"
+msgstr "Pressiona %s"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
 msgid "No right gunner!"
-msgstr "Sem artilheiro na direita!"
+msgstr "Sem artilheiro à direita!"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
 msgid "No left gunner!"
-msgstr "Sem artilheiro na esquerda!"
+msgstr "Sem artilheiro à esquerda!"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
 msgid "Bumblebee"
-msgstr "Bumblebee"
+msgstr ""
 
 #: qcsrc/common/vehicles/vehicle/racer.qh:19
 msgid "Racer"
-msgstr "Racer"
+msgstr ""
 
 #: qcsrc/common/vehicles/vehicle/racer_weapon.qh:9
 msgid "Racer cannon"
@@ -4550,7 +4551,7 @@ msgstr "Chama de Raptor"
 
 #: qcsrc/common/vehicles/vehicle/spiderbot.qh:19
 msgid "Spiderbot"
-msgstr "Spiderbot"
+msgstr "Robô Aranha"
 
 #: qcsrc/common/weapons/all.qh:78
 msgid "Weapons dump command only works with sv_cmd.\n"
@@ -4578,7 +4579,7 @@ msgstr "Electro"
 
 #: qcsrc/common/weapons/weapon/fireball.qc:17
 msgid "Fireball"
-msgstr "Fireball"
+msgstr "Bola de Fogo"
 
 #: qcsrc/common/weapons/weapon/hagar.qc:17
 msgid "Hagar"
@@ -4586,23 +4587,23 @@ msgstr "Hagar"
 
 #: qcsrc/common/weapons/weapon/hlac.qc:17
 msgid "Heavy Laser Assault Cannon"
-msgstr "Heavy Laser Assault Cannon"
+msgstr "Canhão de Assalto a Laser Pesado"
 
 #: qcsrc/common/weapons/weapon/hook.qc:17
 msgid "Grappling Hook"
-msgstr "Gancho (grappling hook)"
+msgstr "Gancho"
 
 #: qcsrc/common/weapons/weapon/machinegun.qc:17
 msgid "MachineGun"
-msgstr "MachineGun"
+msgstr "Metralhadora"
 
 #: qcsrc/common/weapons/weapon/minelayer.qc:17
 msgid "Mine Layer"
-msgstr "Mine Layer"
+msgstr "Porta Minas"
 
 #: qcsrc/common/weapons/weapon/mortar.qc:17
 msgid "Mortar"
-msgstr "Mortar"
+msgstr "Morteiro"
 
 #: qcsrc/common/weapons/weapon/porto.qc:17
 msgid "Port-O-Launch"
@@ -4610,7 +4611,7 @@ msgstr "Port-O-Launch"
 
 #: qcsrc/common/weapons/weapon/rifle.qc:18
 msgid "Rifle"
-msgstr "Rifle"
+msgstr "Espingarda"
 
 #: qcsrc/common/weapons/weapon/seeker.qc:17
 msgid "T.A.G. Seeker"
@@ -4618,11 +4619,11 @@ msgstr "T.A.G. Seeker"
 
 #: qcsrc/common/weapons/weapon/shockwave.qc:17
 msgid "Shockwave"
-msgstr "Shockwave"
+msgstr "Onda de Choque"
 
 #: qcsrc/common/weapons/weapon/shotgun.qc:17
 msgid "Shotgun"
-msgstr "Shotgun"
+msgstr "Caçadeira"
 
 #: qcsrc/common/weapons/weapon/tuba.qc:17
 #, no-c-format
@@ -4631,11 +4632,11 @@ msgstr "@!#%'n Tuba"
 
 #: qcsrc/common/weapons/weapon/vaporizer.qc:18
 msgid "Vaporizer"
-msgstr "Vaporizer"
+msgstr "Vaporizador"
 
 #: qcsrc/common/weapons/weapon/vortex.qc:18
 msgid "Vortex"
-msgstr "Vortex"
+msgstr "Vórtex"
 
 #: qcsrc/lib/counting.qh:9
 #, c-format
@@ -4847,8 +4848,8 @@ msgid ""
 "Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, "
 "please file an issue."
 msgstr ""
-"Campo de entidade %s.%s (%s) não está na lista branca. Se você acredita que "
-"isso é um erro, por favor, reporte-o."
+"O campo de entidade %s.%s (%s) não está na lista branca. Se achas que é um "
+"erro, por favor, reporta-o."
 
 #: qcsrc/lib/string.qh:48
 #, c-format
@@ -4862,7 +4863,7 @@ msgstr "%02d:%02d:%02d"
 
 #: qcsrc/menu/command/menu_cmd.qc:48
 msgid "Usage: menu_cmd command..., where possible commands are:\n"
-msgstr "Uso: comando menu_cmd..., onde os possíveis comandos são:\n"
+msgstr "Uso: comando menu_cmd..., onde os comandos possíveis são:\n"
 
 #: qcsrc/menu/command/menu_cmd.qc:49
 msgid "  sync - reloads all cvars on the current menu page\n"
@@ -4870,7 +4871,7 @@ msgstr " sync - recarrega todas as cvars no menu atual\n"
 
 #: qcsrc/menu/command/menu_cmd.qc:50
 msgid "  directmenu ITEM - select a menu item as main item\n"
-msgstr " directmenu ITEM - seleciona um item do menu como principal\n"
+msgstr " directmenu ITEM - seleciona um item do menu como item principal\n"
 
 #: qcsrc/menu/command/menu_cmd.qc:79
 msgid "Available options:\n"
@@ -4879,7 +4880,7 @@ msgstr "Opções disponíveis:\n"
 #: qcsrc/menu/command/menu_cmd.qc:128
 msgid "Invalid command. For a list of supported commands, try menu_cmd help.\n"
 msgstr ""
-"Comando inválido. Para uma lista de comandos suportados, digite menu_cmd "
+"Comando inválido. Para uma lista de comandos suportados, digita menu_cmd "
 "help.\n"
 
 #: qcsrc/menu/item/listbox.qc:415
@@ -4901,11 +4902,11 @@ msgstr "Nível %d: %s"
 
 #: qcsrc/menu/xonotic/credits.qc:4
 msgid "Core Team"
-msgstr "Equipe Principal"
+msgstr "Equipa Principal"
 
 #: qcsrc/menu/xonotic/credits.qc:16
 msgid "Extended Team"
-msgstr "Equipe Estendida"
+msgstr "Equipa Estendida"
 
 #: qcsrc/menu/xonotic/credits.qc:48
 msgid "Website"
@@ -4925,7 +4926,7 @@ msgstr "Animação"
 
 #: qcsrc/menu/xonotic/credits.qc:69
 msgid "Level Design"
-msgstr "Design de Mapas"
+msgstr "Design de Níveis"
 
 #: qcsrc/menu/xonotic/credits.qc:92
 msgid "Music / Sound FX"
@@ -4933,7 +4934,7 @@ msgstr "Música / Efeitos de Som"
 
 #: qcsrc/menu/xonotic/credits.qc:108
 msgid "Game Code"
-msgstr "Codificação de Jogo"
+msgstr "Codificação do Jogo"
 
 #: qcsrc/menu/xonotic/credits.qc:116
 msgid "Marketing / PR"
@@ -4945,7 +4946,7 @@ msgstr "Assuntos Legais"
 
 #: qcsrc/menu/xonotic/credits.qc:127
 msgid "Game Engine"
-msgstr "Motor de Jogo"
+msgstr "Motor do Jogo"
 
 #: qcsrc/menu/xonotic/credits.qc:131
 msgid "Engine Additions"
@@ -4969,7 +4970,7 @@ msgstr "Asturiano"
 
 #: qcsrc/menu/xonotic/credits.qc:156
 msgid "Belarusian"
-msgstr "Bielorusso"
+msgstr "Bielorrusso"
 
 #: qcsrc/menu/xonotic/credits.qc:159
 msgid "Bulgarian"
@@ -4989,7 +4990,7 @@ msgstr "Córnico"
 
 #: qcsrc/menu/xonotic/credits.qc:180
 msgid "Czech"
-msgstr "Tcheco"
+msgstr "Checo"
 
 #: qcsrc/menu/xonotic/credits.qc:185
 msgid "Dutch"
@@ -5037,7 +5038,7 @@ msgstr "Coreano"
 
 #: qcsrc/menu/xonotic/credits.qc:247
 msgid "Polish"
-msgstr "Polônes "
+msgstr "Polaco"
 
 #: qcsrc/menu/xonotic/credits.qc:255
 msgid "Portuguese"
@@ -5073,19 +5074,19 @@ msgstr "Ucraniano"
 
 #: qcsrc/menu/xonotic/credits.qc:310
 msgid "Past Contributors"
-msgstr "Colaboradores Passados"
+msgstr "Colaboradores Anteriores"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:73
 msgid "forced to be saved to config.cfg"
-msgstr "forçado a ser salvo em config.cfg"
+msgstr "forçado a ser gravado em config.cfg"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:79 qcsrc/menu/xonotic/cvarlist.qc:89
 msgid "will not be saved"
-msgstr "não será salvo"
+msgstr "não será gravado"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:84
 msgid "will be saved to config.cfg"
-msgstr "será salvo em config.cfg"
+msgstr "será gravado em config.cfg"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:93
 msgid "private"
@@ -5097,7 +5098,7 @@ msgstr "configuração do motor"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:97
 msgid "read only"
-msgstr "somente leitura"
+msgstr "apenas leitura"
 
 #: qcsrc/menu/xonotic/dialog_credits.qc:13
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:38
@@ -5122,9 +5123,8 @@ msgid ""
 "player name to get started.  You can change these options later through the "
 "menu system."
 msgstr ""
-"Bem-vindo ao Xonotic! Escolha o seu idioma de preferência e insira o seu "
-"apelido para começar. Você pode alterar essas configurações mais tarde pelo "
-"menu."
+"Bem-vindo(a) ao Xonotic! Escolhe o teu idioma e introduz o teu apelido para "
+"começar. Podes alterar estas configurações mais tarde através do menu."
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:45
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:28
@@ -5134,7 +5134,7 @@ msgstr "Nome:"
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:53
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
 msgid "Name under which you will appear in the game"
-msgstr "Seu nome que aparecerá no jogo"
+msgstr "O teu nome que vai aparecer no jogo"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:69
 msgid "Text language:"
@@ -5143,7 +5143,7 @@ msgstr "Idioma do texto:"
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:78
 msgid "Allow player statistics to use your nickname at stats.xonotic.org?"
 msgstr ""
-"Permitir que as estatísticas de jogador usem o seu apelido em stats.xonotic."
+"Permitir que as estatísticas de jogador usem o teu apelido em stats.xonotic."
 "org?"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:84
@@ -5152,29 +5152,29 @@ msgstr "Não decidido"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:88
 msgid "Save settings"
-msgstr "Salvar configurações"
+msgstr "Gravar configurações"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qh:6
 msgid "Welcome"
-msgstr "Bem-vindo"
+msgstr "Bem-vindo(a)"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
 msgid "Ammunition display:"
-msgstr "Exibir munições:"
+msgstr "Mostrar munições:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:19
 msgid "Show only current ammo type"
-msgstr "Exibir apenas o tipo de munição atual"
+msgstr "Mostrar apenas o tipo de munição atual"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:22
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:44
 msgid "Noncurrent alpha:"
-msgstr "Alfa não circulante:"
+msgstr "Alfa não atual:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:26
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:48
 msgid "Noncurrent scale:"
-msgstr "Escala não circulante:"
+msgstr "Escala não atual:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:30
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:24
@@ -5209,7 +5209,7 @@ msgstr "Painel de Munições"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:17
 msgid "Message duration:"
-msgstr "Duração de mensagem:"
+msgstr "Duração da mensagem:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:21
 msgid "Fade time:"
@@ -5217,7 +5217,7 @@ msgstr "Tempo de desaparecimento:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:25
 msgid "Flip messages order"
-msgstr "Trocar ordem de notificações"
+msgstr "Trocar ordem de mensagens"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:27
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:15
@@ -5240,23 +5240,23 @@ msgstr "Painel Central"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
 msgid "Chat entries:"
-msgstr "Entradas do bate-papo:"
+msgstr "Entradas da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
 msgid "Chat size:"
-msgstr "Tamanho do bate-papo:"
+msgstr "Tamanho da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
 msgid "Chat lifetime:"
-msgstr "Tempo de vida do bate-papo:"
+msgstr "Tempo de vida da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
 msgid "Chat beep sound"
-msgstr "Som de aviso do bate-papo"
+msgstr "Som de aviso da conversação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
 msgid "Chat Panel"
-msgstr "Painel do Bate-papo"
+msgstr "Painel da Conversação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
 msgid "Engine info:"
@@ -5272,18 +5272,18 @@ msgstr "Painel de Informações do Motor"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
 msgid "Combine health and armor"
-msgstr "Combinar saúde e armadura"
+msgstr "Combinar vida e armadura"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:15
 msgid "Enable status bar"
-msgstr "Habilitar barra de status"
+msgstr "Ativar barra de estado"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:19
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:17
 msgid "Status bar alignment:"
-msgstr "Alinhamento da barra de status:"
+msgstr "Alinhamento da barra de estado:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:27
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:37
@@ -5302,15 +5302,15 @@ msgstr "Para fora"
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:32
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:30
 msgid "Icon alignment:"
-msgstr "Alinhamento de ícones:"
+msgstr "Alinhamento dos ícones:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:40
 msgid "Flip health and armor positions"
-msgstr "Trocar as posições da saúde e armadura"
+msgstr "Trocar as posições da vida e da armadura"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh:6
 msgid "Health/Armor Panel"
-msgstr "Painel de Saúde/Armadura"
+msgstr "Painel de Vida/Armadura"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
 msgid "Info messages:"
@@ -5326,15 +5326,15 @@ msgstr "Painel de Mensagens de Informação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:16
 msgid "PNL^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:17
 msgid "PNL^Enabled spectating"
-msgstr "Espectadores habilitados"
+msgstr "Ativado os Espetadores"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:18
 msgid "PNL^Enabled even playing in warmup"
-msgstr "Habilitado mesmo jogando em aquecimento"
+msgstr "Ativado mesmo a jogar em aquecimento"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:29
 msgid "Reduced"
@@ -5350,7 +5350,7 @@ msgstr "Ocultar itens disponíveis"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:37
 msgid "Hide big armor and health"
-msgstr "Ocultar armadura grande e saúde grande"
+msgstr "Ocultar armadura grande e vida grande"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:39
 msgid "Dynamic size"
@@ -5370,7 +5370,7 @@ msgstr "Notificações:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:18
 msgid "Also print notifications to the console"
-msgstr "Mostrar notificações no console também"
+msgstr "Mostrar notificações também na consola"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:21
 msgid "Flip notify order"
@@ -5392,23 +5392,23 @@ msgstr "Painel de Notificações"
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:15
 msgid "Panel disabled"
-msgstr "Painel desabilitado"
+msgstr "Painel desativado"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:16
 msgid "Panel enabled"
-msgstr "Painel habilitado"
+msgstr "Painel ativado"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
 msgid "Panel enabled even observing"
-msgstr "Painel habilitado enquanto estiver observando"
+msgstr "Painel ativado mesmo ao observar"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:18
 msgid "Panel enabled only in Race/CTS"
-msgstr "Painel habilitado apenas em Corrida/CTS"
+msgstr "Painel ativado apenas em Corrida/CTS"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
 msgid "Status bar"
-msgstr "Barra de status"
+msgstr "Barra de estado"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:26
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:68
@@ -5466,7 +5466,7 @@ msgstr "nós"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:57
 msgid "Show"
-msgstr "Exibir"
+msgstr "Mostrar"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:60
 msgid "Top speed"
@@ -5490,12 +5490,12 @@ msgstr "Painel de Potencializadores"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:15
 msgid "Panel enabled when spectating"
-msgstr "Painel habilitado enquanto estiver de espectador"
+msgstr "Painel ativado quando espetador"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:16
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:17
 msgid "Panel always enabled"
-msgstr "Painel sempre habilitado"
+msgstr "Painel ativado sempre"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:23
 msgid "Forced aspect:"
@@ -5511,11 +5511,11 @@ msgstr "Painel de Menu Instantâneo"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qh:6
 msgid "Race Timer Panel"
-msgstr "Painel do Cronômetro de Corrida"
+msgstr "Painel do Cronómetro da Corrida"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
 msgid "Panel enabled in teamgames"
-msgstr "Painel habilitado em jogos de equipe"
+msgstr "Painel ativado em jogos de equipa"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
 msgid "Radar:"
@@ -5540,7 +5540,7 @@ msgstr "Rotação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:32
 msgid "Forward"
-msgstr "Para frente"
+msgstr "Para frente"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:33
 msgid "West"
@@ -5612,15 +5612,15 @@ msgstr "Painel da Pontuação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:14
 msgid "Timer:"
-msgstr "Cronômetro:"
+msgstr "Cronómetro:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:17
 msgid "Show elapsed time"
-msgstr "Exibir tempo decorrido"
+msgstr "Mostrar tempo decorrido"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_timer.qh:6
 msgid "Timer Panel"
-msgstr "Painel do Cronômetro"
+msgstr "Painel do Cronómetro"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_vote.qc:15
 msgid "Alpha after voting:"
@@ -5672,11 +5672,11 @@ msgstr "Ícones das armas:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:41
 msgid "Show only owned weapons"
-msgstr "Exibir apenas armas obtidas"
+msgstr "Mostrar apenas armas obtidas"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:52
 msgid "Show weapon ID as:"
-msgstr "Exibir o ID da arma como:"
+msgstr "Mostrar o ID da arma como:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:53
 msgid "SHOWAS^None"
@@ -5696,15 +5696,15 @@ msgstr "Escala do ID da arma:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:64
 msgid "Show Accuracy"
-msgstr "Exibir precisão"
+msgstr "Mostrar Precisão"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:65
 msgid "Show Ammo"
-msgstr "Exibir munições"
+msgstr "Mostrar Munições"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:68
 msgid "Ammo bar alpha:"
-msgstr "Cor da barra de munições:"
+msgstr "Transparência da barra de munições:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:74
 msgid "Ammo bar color:"
@@ -5716,7 +5716,7 @@ msgstr "Painel das Armas"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:19
 msgid "HUD skins"
-msgstr "Visuais de HUD"
+msgstr "Visuais de Interface"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:22
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:196
@@ -5741,7 +5741,7 @@ msgstr "Definir visual"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:37
 msgid "Save current skin"
-msgstr "Salvar visual atual"
+msgstr "Gravar visual atual"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:46
 msgid "Panel background defaults:"
@@ -5759,22 +5759,22 @@ msgstr "Fundo:"
 #: qcsrc/menu/xonotic/util.qc:770 qcsrc/menu/xonotic/util.qc:786
 #: qcsrc/menu/xonotic/util.qc:803
 msgid "Disable"
-msgstr "Desabilitar"
+msgstr "Desativar"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:60
 #: qcsrc/menu/xonotic/util.qc:783
 msgid "Border size:"
-msgstr "Tamanho das bordas:"
+msgstr "Tamanho da borda:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:75
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:114
 msgid "Team color:"
-msgstr "Cor de equipe:"
+msgstr "Cor da equipa:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:83
 #: qcsrc/menu/xonotic/util.qc:809
 msgid "Test team color in configure mode"
-msgstr "Testar cor de equipe no modo de configuração"
+msgstr "Testar cor da equipa no modo de configuração"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:86
 #: qcsrc/menu/xonotic/util.qc:812
@@ -5783,11 +5783,11 @@ msgstr "Preenchimento:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:93
 msgid "HUD Dock:"
-msgstr "Camada do HUD:"
+msgstr "Camada da Interface:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
 msgid "DOCK^Disabled"
-msgstr "Desabilitada"
+msgstr "Desativada"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:96
 msgid "DOCK^Small"
@@ -5803,15 +5803,15 @@ msgstr "Grande"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:121
 msgid "Grid settings:"
-msgstr "Configurações da rede:"
+msgstr "Configurações da grelha:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:124
 msgid "Snap panels to grid"
-msgstr "Fixar painéis à grade"
+msgstr "Fixar painéis à grelha"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:127
 msgid "Grid size:"
-msgstr "Tamanho da rede:"
+msgstr "Tamanho da grelha:"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:129
 msgid "X:"
@@ -5827,7 +5827,7 @@ msgstr "Sair da configuração"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qh:6
 msgid "Panel HUD Setup"
-msgstr "Painel de Configuração do HUD"
+msgstr "Painel de Configuração da Interface"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:13
 msgid "Monster:"
@@ -5882,11 +5882,11 @@ msgstr "Servidores"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:15
 msgid "Find servers to play on"
-msgstr "Encontre servidores para jogar"
+msgstr "Encontrar servidores para jogar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:17
 msgid "Host your own game"
-msgstr "Hospede a sua própria partida"
+msgstr "Alojar o meu jogo"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:18
 msgid "Media"
@@ -5898,15 +5898,15 @@ msgstr "Perfil"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qh:6
 msgid "Multiplayer"
-msgstr "Multijogador"
+msgstr "Multi-jogador"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer.qh:7
 msgid ""
 "Play online, against your friends in LAN, view demos or change player "
 "settings"
 msgstr ""
-"Jogue online, jogue contra seus amigos em rede local, assista a demos ou "
-"altere as configurações de jogador."
+"Joga online, joga contra os teus amigos em rede local, assiste a "
+"demonstrações ou altera as configurações de jogador."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:46
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:134
@@ -5968,11 +5968,11 @@ msgstr "Voltas:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
 msgid "Goals:"
-msgstr "Gols:"
+msgstr "Golos:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
 msgid "The amount of goals needed before the match will end"
-msgstr "A quantidade de gols necessária para acabar a partida"
+msgstr "A quantidade de golos necessária para acabar a partida"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:97
 msgid "Gametype"
@@ -6007,19 +6007,19 @@ msgstr "Infinito"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:132
 msgid "Teams:"
-msgstr "Equipes:"
+msgstr "Equipas:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:135
 msgid "2 teams"
-msgstr "2 equipes"
+msgstr "2 equipas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:136
 msgid "3 teams"
-msgstr "3 equipes"
+msgstr "3 equipas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:137
 msgid "4 teams"
-msgstr "4 equipes"
+msgstr "4 equipas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:140
 msgid "Player slots:"
@@ -6030,24 +6030,24 @@ msgid ""
 "The maximum amount of players or bots that can be connected to your server "
 "at once"
 msgstr ""
-"O número máximo de jogadores ou bots que podem estar conectados ao seu "
+"O número máximo de jogadores ou robôs que podem estar conectados ao teu "
 "servidor simultaneamente."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:144
 msgid "Number of bots:"
-msgstr "Número de bots:"
+msgstr "Número de robôs:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:146
 msgid "Amount of bots on your server"
-msgstr "Quantidade de bots no seu servidor"
+msgstr "Quantidade de robôs no teu servidor"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:148
 msgid "Bot skill:"
-msgstr "Habilidade dos bots:"
+msgstr "Habilidade dos robôs:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:151
 msgid "Specify how experienced the bots will be"
-msgstr "Especifique a experiência dos bots"
+msgstr "Especifica a perícia dos robôs"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:152
 msgid "Botlike"
@@ -6059,15 +6059,15 @@ msgstr "Iniciante"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:154
 msgid "You will win"
-msgstr "Você vai ganhar"
+msgstr "Vais ganhar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:155
 msgid "You can win"
-msgstr "Você pode ganhar"
+msgstr "Podes ganhar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:156
 msgid "You might win"
-msgstr "Você talvez ganhe"
+msgstr "Talvez ganhes"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:157
 msgid "Advanced"
@@ -6110,24 +6110,25 @@ msgid ""
 "Click here or Ctrl-F to provide a keyword to narrow down the map list. Ctrl-"
 "Delete to clear; Enter when done."
 msgstr ""
-"Clique aqui ou aperte Ctrl+F para digitar uma palavra chave e buscar o mapa "
-"desejado. Você pode apertar Ctrl+Delete para apagar e Enter para confirmar."
+"Clica aqui ou pressiona Ctrl+F para digitar uma palavra-chave e diminuir a "
+"lista de mapas apresentados. Usar Ctrl+Delete para limpar e Enter para "
+"confirmar."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:207
 msgid "Add shown"
-msgstr "Adicionar exibidos"
+msgstr "Adicionar mostrados"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:208
 msgid "Add the maps shown in the list to your selection"
-msgstr "Adiciona os mapas exibidos na lista para a sua seleção"
+msgstr "Adiciona os mapas mostrados na lista para a tua seleção"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:211
 msgid "Remove shown"
-msgstr "Remover exibidos"
+msgstr "Remover mostrados"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:212
 msgid "Remove the maps shown in the list from your selection"
-msgstr "Remove os mapas exibidos na lista da sua seleção"
+msgstr "Remove os mapas mostrados na lista da tua seleção"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:217
 msgid "Add all"
@@ -6135,7 +6136,7 @@ msgstr "Adicionar todos"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:218
 msgid "Add every available map to your selection"
-msgstr "Adiciona todos os mapas disponíveis para a sua seleção"
+msgstr "Adiciona todos os mapas disponíveis para a tua seleção"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:221
 msgid "Remove all"
@@ -6143,11 +6144,11 @@ msgstr "Remover todos"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:222
 msgid "Remove all the maps from your selection"
-msgstr "Remove todos os mapas da sua seleção"
+msgstr "Remove todos os mapas da tua seleção"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:229
 msgid "Start Multiplayer!"
-msgstr "Iniciar Multijogador!"
+msgstr "Iniciar Multi-jogador!"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:58
 msgid "Title:"
@@ -6180,7 +6181,7 @@ msgstr "Arena com Todas as Armas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:30
 msgid "Most Weapons Arena"
-msgstr "Arena com Maior Parte das Armas"
+msgstr "Arena com Maior Parte das Armas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:49
 #, c-format
@@ -6210,7 +6211,7 @@ msgstr "NIX"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:69
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:220
 msgid "Rocket Flying"
-msgstr "Voar com Foguetes"
+msgstr "Voar com Mísseis"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:71
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:212
@@ -6249,7 +6250,7 @@ msgstr "Piñata"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:89
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:229
 msgid "Weapons stay"
-msgstr "Armas permanescentes "
+msgstr "Armas permanescentes"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:91
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:184
@@ -6264,7 +6265,7 @@ msgstr "Mochila a Jato"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:95
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:170
 msgid "Buffs"
-msgstr "Bônus (buffs)"
+msgstr "Bónus"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:97
 msgid "Overkill"
@@ -6293,7 +6294,7 @@ msgstr "Modificadores de jogabilidade:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:160
 msgid "Enable dodging"
-msgstr "Habilitar esquiva"
+msgstr "Ativar esquivar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:167
 msgid "All players are almost invisible"
@@ -6302,17 +6303,17 @@ msgstr "Todos jogadores ficarão quase invisíveis"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:174
 msgid "Only possible to inflict damage on your enemy while he's airborne"
 msgstr ""
-"Só é possível causar dano aos seus inimigos enquanto eles estiverem no ar"
+"Só é possível causar dano aos teus inimigos enquanto eles estiverem no ar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
 msgid "Damage done to your enemy gets added to your own health"
-msgstr "O dano causado aos seus inimigos será adicionado à sua saúde"
+msgstr "O dano causado aos teus inimigos será adicionado à sua vida"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
 msgid ""
 "Amount of health below which your player gets stunned because of blood loss"
 msgstr ""
-"Quantidade de saúde abaixo a qual o seu jogador permanecerá atordoado devido "
+"Quantidade de vida abaixo da qual o teu jogador permanecerá atordoado devido "
 "à perda de sangue"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:192
@@ -6327,24 +6328,24 @@ msgstr "Modificadores de armas e itens:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:204
 msgid "Grappling hook"
-msgstr "Gancho (grappling hook)"
+msgstr "Gancho de escalada"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:205
 msgid "Players spawn with the grappling hook"
-msgstr "Jogadores surgem com o gancho"
+msgstr "Os jogadores surgem com o gancho"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:209
 msgid "Players spawn with the jetpack"
-msgstr "Jogadores surgem com a mochila a jato"
+msgstr "Os jogadores surgem com a mochila a jato"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:225
 msgid "Players will drop all weapons they possessed when they are killed"
 msgstr ""
-"Ao morrerem, jogadores irão deixar cair no chão todas as armas que tinham"
+"Ao morrerem, os jogadores irão deixar cair no chão todas as armas que tinham"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
 msgid "Weapons stay after they are picked up"
-msgstr "Armas permanecem no chão após serem coletadas"
+msgstr "As armas permanecem no chão após serem pegadas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
 msgid "Regular (no arena)"
@@ -6362,8 +6363,8 @@ msgid ""
 "as unlimited ammo, and disable all other weapon pickups."
 msgstr ""
 "Selecionar uma arena de armas concederá a todos os jogadores a arma "
-"selecionada ao surgirem bem como munição ilimitada. Todas as outras armas "
-"ficarão indisponíveis no mapa."
+"selecionada ao surgirem, bem como as munições ilimitadas. Todas as outras "
+"armas ficarão indisponíveis no mapa."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
 msgid "Most weapons"
@@ -6385,8 +6386,8 @@ msgid ""
 "does not inflict any damage but is good for doing trickjumps."
 msgstr ""
 "Os jogadores terão uma arma, a qual pode instantaneamente matar o oponente "
-"com um Ãºnico disparo. Se o jogador ficar sem munição, ele terá 10 segundos "
-"para encontrar alguma e se não conseguir fazer isso, irá morrer. O modo de "
+"com um Ãºnico disparo. Se o jogador ficar sem munições, ele terá 10 segundos "
+"para encontrar munições e se não conseguir fazer isso, irá morrer. O modo de "
 "disparo secundário não causa nenhum dano, mas é útil para executar truques "
 "de movimento."
 
@@ -6396,9 +6397,9 @@ msgid ""
 "weapon. After some time, a countdown will start, after which everyone will "
 "switch to another weapon."
 msgstr ""
-"Sem itens Xonotic - em vez de pegar itens espalhados pelo mapa, todo mundo "
-"joga com a mesma arma. Depois de um certo tempo, uma contagem regressiva irá "
-"iniciar, e depois disso todos irão trocar para uma outra arma."
+"Sem itens Xonotic - em vez de apanhar itens espalhados pelo mapa, todos "
+"jogam com a mesma arma. Depois de um certo tempo, irá começar uma contagem, "
+"e depois disso todos irão trocar para uma outra arma."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:277
 msgid "with blaster"
@@ -6406,7 +6407,7 @@ msgstr "com blaster"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:278
 msgid "Always carry the blaster as an additional weapon in Nix"
-msgstr "Sempre carregue a blaster como uma arma adicional em Nix"
+msgstr "Carregar sempre a blaster como uma arma adicional em Nix"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qh:9
 msgid "Mutators"
@@ -6422,7 +6423,7 @@ msgstr "Vazio"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:42
 msgid "Show empty servers"
-msgstr "Exibir servidores vazios"
+msgstr "Mostrar servidores vazios"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:46
 msgid "SRVS^Full"
@@ -6430,7 +6431,7 @@ msgstr "Cheio"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:47
 msgid "Show full servers that have no slots available"
-msgstr "Exibir servidores cheios que não contêm vagas disponíveis"
+msgstr "Mostrar servidores cheios que não têm vagas disponíveis"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:51
 msgid "Pause"
@@ -6441,7 +6442,7 @@ msgid ""
 "Pause updating the server list to prevent servers from \"jumping around\""
 msgstr ""
 "Pausa a atualização da lista de servidores para evitar que os servidores "
-"fiquem saindo do lugar"
+"estejam sempre a \"saltar\" do lugar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
 msgid "Reload the server list"
@@ -6458,7 +6459,7 @@ msgstr "Informações..."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:79
 msgid "Show more information about the currently highlighted server"
-msgstr "Exibir mais informações sobre o servidor atualmente destacado"
+msgstr "Mostrar mais informações sobre o servidor atualmente destacado"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:84
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:303
@@ -6482,7 +6483,7 @@ msgstr "Oficial"
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
 msgid "N/A (auth library missing, can't connect)"
 msgstr ""
-"N/A (biblioteca de autenticação não encontrada, não foi possível se conectar)"
+"N/A (biblioteca de autenticação não encontrada, não é possível conectar)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:171
 msgid "N/A (auth library missing)"
@@ -6490,7 +6491,7 @@ msgstr "N/A (biblioteca de autenticação não encontrada)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:177
 msgid "Not supported (can't connect)"
-msgstr "Não suportado (não foi possível se conectar)"
+msgstr "Não suportado (não é possível conectar)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
 msgid "Not supported (won't encrypt)"
@@ -6514,7 +6515,7 @@ msgstr "Solicitado (não encriptará)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:195
 msgid "Required (can't connect)"
-msgstr "Necessário (não foi possível se conectar)"
+msgstr "Necessário (não é possível conectar)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:197
 msgid "Required (will encrypt)"
@@ -6551,7 +6552,7 @@ msgstr "Jogadores:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:263
 msgid "Bots:"
-msgstr "Bots:"
+msgstr "Robôs:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:268
 msgid "Free slots:"
@@ -6579,7 +6580,7 @@ msgstr "Demos"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:26
 msgid "Screenshots"
-msgstr "Screenshots"
+msgstr "Capturas de ecrã"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:27
 msgid "Music Player"
@@ -6591,13 +6592,13 @@ msgstr "Gravar demos automaticamente"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:57
 msgid "Timedemo"
-msgstr "Executar benchmark"
+msgstr "Executar teste de desempenho"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:58
 msgid "Benchmark how fast your computer can run the highlighted demo"
 msgstr ""
-"Executa um teste de desempenho para saber quão rápido seu computador pode "
-"rodar a demo destacada"
+"Executa um teste de desempenho para saber quão rápido o teu computador pode "
+"executar a demo destacada"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:62
 msgid "DEMO^Play"
@@ -6605,12 +6606,12 @@ msgstr "Reproduzir"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:13
 msgid "Playing a demo will disconnect you from the current match."
-msgstr "Reproduzir uma demo irá desconectar você da partida atual."
+msgstr "Reproduzir uma demo irá desconectar-te da partida atual."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:15
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:15
 msgid "Do you really wish to disconnect now?"
-msgstr "Você realmente deseja desconectar agora?"
+msgstr "Queres mesmo desconectar-te agora?"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh:6
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qh:6
@@ -6619,7 +6620,8 @@ msgstr "Desconectar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:13
 msgid "Timing a demo will disconnect you from the current match."
-msgstr "Executar benchmark em uma demo irá desconectá-lo da partida atual."
+msgstr ""
+"Executar teste de desempenho numa demo irá desconectar-te da partida atual."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:37
 msgid "MUSICPL^Add"
@@ -6651,11 +6653,11 @@ msgstr "Parar"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:63
 msgid "MUSICPL^Play"
-msgstr "Tocar"
+msgstr "Reproduzir"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:66
 msgid "MUSICPL^Pause"
-msgstr "Pausar"
+msgstr "Pausa"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:69
 msgid "MUSICPL^Prev"
@@ -6675,7 +6677,7 @@ msgstr "Remover todas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
 msgid "Auto screenshot scoreboard"
-msgstr "Tirar screenshot automaticamente do placar"
+msgstr "Tirar captura de ecrã automaticamente do placar de pontuação"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:63
 msgid "Open in the viewer"
@@ -6683,7 +6685,7 @@ msgstr "Abrir no visualizador"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:139
 msgid "Reset"
-msgstr "Redefinir"
+msgstr "Repor"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:144
 msgid "Previous"
@@ -6728,19 +6730,19 @@ msgstr "Estatísticas"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:125
 msgid "Allow player statistics to track your client"
-msgstr "Permitir que as estatísticas de jogadores rastreiem o seu cliente"
+msgstr "Permitir que as estatísticas de jogadores rastreiem o teu cliente"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:129
 msgid "Allow player statistics to use your nickname"
-msgstr "Permitir que as estatísticas de jogadores usem o seu apelido"
+msgstr "Permitir que as estatísticas de jogadores usem o teu apelido"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
 msgid "Country"
-msgstr "Idioma"
+msgstr "País"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
 msgid "Gender:"
-msgstr "Gênero:"
+msgstr "Género:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:161
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:174
@@ -6759,11 +6761,11 @@ msgstr "Masculino"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:166
 msgid "Gender"
-msgstr "Gênero"
+msgstr "Género"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:11
 msgid "Are you sure you want to quit?"
-msgstr "Tem certeza de que deseja sair?"
+msgstr "Tens certeza de que queres sair?"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:15
 msgid "Back to work..."
@@ -6803,7 +6805,7 @@ msgstr "Definir * como criança"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:32
 msgid "Attach to *"
-msgstr "Anexar à *"
+msgstr "Anexar a *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:34
 msgid "Detach from *"
@@ -6811,7 +6813,7 @@ msgstr "Separar de *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:37
 msgid "Visual object properties for *:"
-msgstr "Propriedades de objeto visual para *:"
+msgstr "Propriedades do objeto visual para *:"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:41
 msgid "Set alpha:"
@@ -6831,7 +6833,7 @@ msgstr "Definir frame:"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:54
 msgid "Physical object properties for *:"
-msgstr "Propriedades de objeto físico para *:"
+msgstr "Propriedades do objeto físico para *:"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:56
 msgid "Set material:"
@@ -6859,7 +6861,7 @@ msgstr "Estática"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:67
 msgid "Movable"
-msgstr "Movível"
+msgstr "Deslocável"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:68
 msgid "Physical"
@@ -6879,23 +6881,23 @@ msgstr "Resgatar *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:78
 msgid "* object info"
-msgstr "Informações de objeto *"
+msgstr "Informações do objeto *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:79
 msgid "* mesh info"
-msgstr "Informações de malha *"
+msgstr "Informações da malha *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:80
 msgid "* attachment info"
-msgstr "Informações de extras *"
+msgstr "Informações dos extras *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:81
 msgid "Show help"
-msgstr "Exibir ajuda"
+msgstr "Mostrar ajuda"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:82
 msgid "* is the object you are facing"
-msgstr "* é o objeto para o qual você está virado"
+msgstr "* é o objeto para o qual estás virado"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qh:6
 msgid "Sandbox Tools"
@@ -6923,7 +6925,7 @@ msgstr "Entrada"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:24
 msgid "User"
-msgstr "Usuário"
+msgstr "Utilizador"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:25
 #: qcsrc/menu/xonotic/keybinder.qc:105
@@ -6936,7 +6938,7 @@ msgstr "Configurações"
 
 #: qcsrc/menu/xonotic/dialog_settings.qh:7
 msgid "Change the game settings"
-msgstr "Altere as configurações do jogo"
+msgstr "Altera as configurações do jogo"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
 msgid "Master:"
@@ -6984,7 +6986,7 @@ msgstr "Novo estilo de atenuação de som"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:102
 msgid "Mute sounds when not active"
-msgstr "Desabilita o som enquanto estiver em segundo plano"
+msgstr "Desativa o som enquanto estiver em segundo plano"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:105
 msgid "Frequency:"
@@ -7076,27 +7078,27 @@ msgstr "Troca de lugar os canais esquerdo e direito"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:138
 msgid "Headphone friendly mode"
-msgstr "Modo de fones de ouvido"
+msgstr "Modo de auscultadores"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:139
 msgid ""
 "Enable spatialization (blend the right and left channel slightly to decrease "
 "stereo separation a bit for headphones)"
 msgstr ""
-"Habilita espacialização (combina levemente os canais esquerdo e direito para "
-"diminuir um pouco a separação de estéreo para fones de ouvido)"
+"Ativa a espacialização (combina levemente os canais esquerdo e direito para "
+"diminuir um pouco a separação dos canais de estéreo para auscultadores)"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:143
 msgid "Hit indication sound"
-msgstr "Som indicador de disparo acertado"
+msgstr "Som indicador de tiro certeiro"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:144
 msgid "Play a hit indicator sound when your shot hits an enemy"
-msgstr "Reproduzuz um som indicando que você acertou um inimigo"
+msgstr "Reproduz um som indicando que acertaste num inimigo"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:147
 msgid "Chat message sound"
-msgstr "Som de mensagem do bate-papo"
+msgstr "Som de mensagem da conversação"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:149
 msgid "Menu sounds"
@@ -7104,7 +7106,7 @@ msgstr "Sons do menu"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:150
 msgid "Play sounds when clicking menu items"
-msgstr "Reproduz sons quando você clica nas opções do menu"
+msgstr "Reproduz sons quando clicas nas opções do menu"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:151
 msgid "Focus sounds"
@@ -7112,7 +7114,7 @@ msgstr "Sons de foco"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:152
 msgid "Play sounds when hovering over menu items too"
-msgstr "Reproduz sons quando você passa o mouse sobre as opções do menu também"
+msgstr "Reproduz sons quando passas com o rato sobre as opções do menu também"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:156
 msgid "Time announcer:"
@@ -7120,7 +7122,7 @@ msgstr "Aviso de tempo:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:158
 msgid "WRN^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:160
 msgid "5 minutes"
@@ -7284,36 +7286,36 @@ msgstr "Evitar compressão de texturas com perdas"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:131
 msgid "Show surfaces"
-msgstr "Exibir superfícies"
+msgstr "Mostrar superfícies"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:132
 msgid ""
 "Disable textures completely for very slow hardware. This gives a huge "
 "performance boost, but looks very ugly. (default: disabled)"
 msgstr ""
-"Desabilita completamente as texturas para PCs de baixo desempenho. Isso "
-"garante uma alto ganho de desempenho, mas deixa o jogo muito feio. (padrão: "
-"desabilitado)"
+"Desativa completamente as texturas para computadores de baixo desempenho. "
+"Isto melhora o desempenho, mas deixa o aspeto do jogo um bocado feio. "
+"(padrão: desabilitado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:135
 msgid "Use lightmaps"
-msgstr "Usar lightmaps"
+msgstr "Usar mapas de luzes"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:136
 msgid ""
 "Use high resolution lightmaps, which will look pretty but use up some extra "
 "video memory (default: enabled)"
 msgstr ""
-"Usa lightmaps de alta resolução, os quais ficarão elegantes, mas irão usar "
-"um pouco mais de memória (padrão: habilitado)"
+"Usa mapas de luzes de alta resolução, os quais ficarão elegantes, mas irão "
+"usar um pouco mais de memória (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:138
 msgid "Deluxe mapping"
-msgstr "Mapeamento deluxe"
+msgstr "Mapeamento de luxo"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:139
 msgid "Use per-pixel lighting effects (default: enabled)"
-msgstr "Usa efeitos de iluminação por pixel (padrão: habilitado)"
+msgstr "Usa efeitos de iluminação por pixel (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:141
 msgid "Gloss"
@@ -7323,21 +7325,21 @@ msgstr "Lustro"
 msgid ""
 "Enable the use of glossmaps on textures supporting it (default: enabled)"
 msgstr ""
-"Habilita o uso de glossmaps em texturas que suportam esse recurso (padrão: "
-"habilitado)"
+"Ativa a utilização de mapas de lustro em texturas que suportam esse recurso "
+"(padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:145
 msgid "Offset mapping"
-msgstr "Mapeamento por paralaxe"
+msgstr "Mapeamento por deslocação"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:146
 msgid ""
 "Offset mapping effect that will make textures with bumpmaps appear like they "
 "\"pop out\" of the flat 2D surface (default: disabled)"
 msgstr ""
-"Efeito de mapeamento por paralaxe que fará as texturas com bumpmaps "
-"parecerem que estão \"saindo\" da superfície plana em 2D (padrão: "
-"desabilitado)"
+"Efeito de mapeamento por paralaxe que fará com que as texturas com mapa de "
+"relevo (bumpmaps) pareçam que estão a \"sair\" da superfície plana em 2D "
+"(padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:148
 msgid "Relief mapping"
@@ -7348,8 +7350,8 @@ msgid ""
 "Higher quality offset mapping, which also has a huge impact on performance "
 "(default: disabled)"
 msgstr ""
-"Mapeamento por paralaxe de maior qualidade, o qual também causa um grande "
-"impacto no desempenho (padrão: desabilitado)"
+"Mapeamento por relevo de maior qualidade, o qual também causa um grande "
+"impacto no desempenho (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:152
 msgid "Reflections:"
@@ -7361,7 +7363,7 @@ msgid ""
 "with reflecting surfaces (default: disabled)"
 msgstr ""
 "Qualidade de reflexos e refrações. Causa um grande impacto no desempenho em "
-"mapas que contenham superfícies com reflexos (padrão: desabilitado)"
+"mapas que contenham superfícies com reflexos (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:156
 msgid "Resolution of reflections/refractions (default: good)"
@@ -7385,7 +7387,7 @@ msgstr "Decalques"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
 msgid "Enable decals (bullet holes and blood) (default: enabled)"
-msgstr "Habilita decalques (buracos de bala e sangue) (padrão: habilitado)"
+msgstr "Ativa os decalques (buracos de bala e sangue) (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:165
 msgid "Decals on models"
@@ -7398,7 +7400,8 @@ msgstr "Distância:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:172
 msgid "Decals further away than this will not be drawn (default: 300)"
-msgstr "Decalques mais distantes que isso não serão desenhados (padrão: 300)"
+msgstr ""
+"Os decalques mais distantes que este valor não serão mostrados (padrão: 300)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:176
 msgid "Time:"
@@ -7406,7 +7409,7 @@ msgstr "Tempo:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:179
 msgid "Time in seconds before decals fade away (default: 2)"
-msgstr "Tempo em segundos antes de decalques desaparecerem (padrão: 2)"
+msgstr "Tempo em segundos antes dos decalques desaparecerem (padrão: 2)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:183
 msgid "Damage effects:"
@@ -7414,7 +7417,7 @@ msgstr "Efeitos de dano:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:185
 msgid "DMGFX^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:186
 msgid "Skeletal"
@@ -7426,23 +7429,23 @@ msgstr "Todos"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:191
 msgid "No dynamic lighting"
-msgstr "Desabilitar iluminação dinâmica"
+msgstr "Desativar iluminação dinâmica"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:192
 msgid "Enable corona flares around certain lights (default: enabled)"
-msgstr "Habilita luzes de corona ao redor de certas luzes (padrão: habilitado)"
+msgstr "Ativa luzes de coroa ao redor de certas luzes (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:194
 msgid "Fake corona lighting"
-msgstr "Iluminação de coronas falsa"
+msgstr "Iluminação de coroas falsa"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:195
 msgid ""
 "Enable faster but uglier dynamic lights by rendering bright coronas instead "
 "of real dynamic lights (default: disabled)"
 msgstr ""
-"Habilita luzes dinâmicas mais rápidas porém mais feias renderizando coronas "
-"brilhantes em vez de luzes dinâmicas reais (padrão: desabilitado)"
+"Ativa luzes dinâmicas mais rápidas mas também mais feias renderizando as "
+"coroas brilhantes em vez de luzes dinâmicas reais (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:198
 msgid "Realtime dynamic lighting"
@@ -7453,8 +7456,8 @@ msgid ""
 "Enable rendering of dynamic lights such as explosions and rocket lights "
 "(default: enabled)"
 msgstr ""
-"Habilita a renderização de luzes dinâmicas como explosões e luzes de "
-"foguetes (padrão: habilitada)"
+"Ativa a renderização de luzes dinâmicas como explosões e luzes de foguetes "
+"(padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:201
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:207
@@ -7464,8 +7467,8 @@ msgstr "Sombras"
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:202
 msgid "Enable rendering of shadows from dynamic lights (default: disabled)"
 msgstr ""
-"Habilita a renderização de sombras a partir de luzes dinâmicas (padrão: "
-"desabilitado)"
+"Ativa a renderização de sombras a partir de luzes dinâmicas (padrão: "
+"desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:205
 msgid "Realtime world lighting"
@@ -7476,16 +7479,16 @@ msgid ""
 "Enable rendering of full realtime world lighting on maps that support it. "
 "Note that this might have a big impact on performance. (default: disabled)"
 msgstr ""
-"Habilita a renderização de iluminação de mundo em tempo real em mapas que a "
-"suportam. Note que isso pode causar um grande impacto no desempenho (padrão: "
-"desabilitado)"
+"Ativa a renderização de iluminação de mundo em tempo real em mapas que a "
+"suportam. Nota que isto pode causar um grande impacto no desempenho (padrão: "
+"desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:208
 msgid ""
 "Enable rendering of shadows from realtime world lights (default: disabled)"
 msgstr ""
-"Habilita a renderização de sombras de luzes de mundo em tempo real (padrão: "
-"desabilitado)"
+"Ativa a renderização de sombras de luzes de mundo em tempo real (padrão: "
+"desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:212
 msgid "Use normal maps"
@@ -7493,7 +7496,7 @@ msgstr "Usar normal maps"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:213
 msgid "Enable use of directional shading on textures (default: enabled)"
-msgstr "Habilita o uso de shaders direcionais em texturas (padrão: habilitado)"
+msgstr "Ativa o uso de shaders direcionais em texturas (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:215
 msgid "Soft shadows"
@@ -7501,23 +7504,24 @@ msgstr "Sombras suaves"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:219
 msgid "Fade corona according to visibility"
-msgstr "Enfraquecer corona de acordo com a visibilidade"
+msgstr "Enfraquecer coroa de acordo com a visibilidade"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:220
 msgid "Fade coronas according to visibility (default: enabled)"
-msgstr "Enfraquece coronas de acordo com a visibilidade (padrão: habilitado)"
+msgstr "Enfraquece coroas de acordo com a visibilidade (padrão: ativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:224
 msgid "Bloom"
-msgstr "Bloom"
+msgstr "Incandescência"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:225
 msgid ""
 "Enable bloom effect, which brightens the neighboring pixels of very bright "
 "pixels. Has a big impact on performance. (default: disabled)"
 msgstr ""
-"Habilita o efeito bloom, o qual ilumina os pixels próximos de pixels muito "
-"brilhantes. Causa um grande impacto no desempenho (padrão: desabilitado)"
+"Ativa o efeito de incandescência, o qual ilumina os pixeis próximos de "
+"pixeis muito brilhantes. Causa um grande impacto no desempenho (padrão: "
+"desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:226
 msgid "Extra postprocessing effects"
@@ -7528,16 +7532,16 @@ msgid ""
 "Enables special postprocessing effects for when damaged or under water or "
 "using a powerup (default: disabled)"
 msgstr ""
-"Habilita efeitos especiais de pós-processamento para quando receber dano, "
-"estar debaixo d'água ou ao usar potencializadores (padrão: desabilitado)"
+"Ativa efeitos especiais de pós-processamento ao receber dano, estar debaixo "
+"d'água ou ao usar potencializadores (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:232
 msgid "Motion blur strength - 0.4 recommended"
-msgstr "Intensidade do desfoque de movimento - 0.4 recomendado"
+msgstr "Intensidade da desfocagem de movimento - 0.4 recomendado"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:233
 msgid "Motion blur:"
-msgstr "Desfoque de movimento:"
+msgstr "Desfocagem de movimento:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
 msgid "Particles"
@@ -7563,11 +7567,11 @@ msgid ""
 "gives for better performance (default: 1.0)"
 msgstr ""
 "Multiplicador para a quantidade de partículas. Menos significa menos "
-"partículas, o que resulta em um melhor desempenho (padrão: 1.0)"
+"partículas, o que resulta num melhor desempenho (padrão: 1.0)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:256
 msgid "Particles further away than this will not be drawn (default: 1000)"
-msgstr "Partículas mais distantes que isso não serão desenhadas (padrão: 1000)"
+msgstr "Partículas mais distantes que isto não irão aparecer (padrão: 1000)"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:31
 msgid "No crosshair"
@@ -7583,8 +7587,8 @@ msgid ""
 "Set a different crosshair for each weapon, good if you play without weapon "
 "models"
 msgstr ""
-"Define uma mira diferente para cada uma das armas, uma boa opção caso você "
-"jogue sem os modelos das armas na tela"
+"Define uma mira diferente para cada uma das armas, uma boa opção caso jogues "
+"sem aparecerem as armas no ecrã"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:48
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:81
@@ -7594,15 +7598,15 @@ msgstr "Tamanho:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:64
 msgid "By health"
-msgstr "Por saúde"
+msgstr "Por vida"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:76
 msgid "Use rings to indicate weapon status"
-msgstr "Usar anéis para indicar status da arma"
+msgstr "Usar anéis para indicar estado da arma"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:93
 msgid "Enable center crosshair dot"
-msgstr "Habilitar ponto no centro da mira"
+msgstr "Ativar ponto no centro da mira"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:111
 msgid "Use normal crosshair color"
@@ -7623,12 +7627,12 @@ msgid ""
 "enlarge the crosshair when you would hit an enemy"
 msgstr ""
 "Nenhum: não realiza testes de acerto para a mira; Mira Real: desfoca a mira "
-"quando há uma obstáculo entre a sua arma e o alvo; Inimigos: a mira também é "
-"ampliada quando você acertaria um inimigo"
+"quando há um obstáculo entre a tua arma e o alvo; Inimigos: a mira também é "
+"ampliada quando acertarias num inimigo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:129
 msgid "HTTST^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:130
 msgid "HTTST^TrueAim"
@@ -7640,19 +7644,19 @@ msgstr "Inimigos"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:136
 msgid "Blur crosshair if the shot is obstructed"
-msgstr "Borrar mira se o disparo for obstruído"
+msgstr "Desfocar mira se o disparo for obstruído"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:140
 msgid "Enlarge crosshair if targeting an enemy"
-msgstr "Ampliar mira ao focar em um inimigo"
+msgstr "Ampliar mira ao focar num inimigo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:143
 msgid "Animate crosshair when hitting an enemy"
-msgstr "Animar mira ao acertar um inimigo"
+msgstr "Animar mira ao acertar num inimigo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:146
 msgid "Animate crosshair when picking up an item"
-msgstr "Animar mira ao pegar um item"
+msgstr "Animar mira ao apanhar um item"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh:7
 msgid "Crosshair"
@@ -7664,15 +7668,15 @@ msgstr "Vel. de desaparecimento:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:51
 msgid "Enable rows / columns highlighting"
-msgstr "Habilitar destacamento de fileiras/colunas"
+msgstr "Ativar destaque de linhas/colunas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:55
 msgid "Show decimals in respawn countdown"
-msgstr "Exibir decimais na contagem de ressurgimento"
+msgstr "Mostrar decimais na contagem de ressurgimento"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
 msgid "Show accuracy underneath scoreboard"
-msgstr "Exibir precisão embaixo do placar"
+msgstr "Mostrar pontaria por baixo do placar de pontuação"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
 msgid "Waypoints"
@@ -7697,11 +7701,11 @@ msgstr "Tamanho da fonte:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:80
 msgid "Edge offset:"
-msgstr "Extremidade:"
+msgstr "Deslocamento da extremidade:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:89
 msgid "Fade when near the crosshair"
-msgstr "Enfraquecer ao se aproximar da mira"
+msgstr "Suavizar quando perto da mira"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:94
 msgid "Damage"
@@ -7725,7 +7729,7 @@ msgstr "Nomes de Jogadores"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:114
 msgid "Show names above players"
-msgstr "Exibir nomes sobre jogadores"
+msgstr "Mostrar nomes por cima dos jogadores"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:130
 msgid "Max distance:"
@@ -7733,20 +7737,20 @@ msgstr "Distância máxima:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:136
 msgid "Decolorize:"
-msgstr "Descolorização:"
+msgstr "Descoloração:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:140
 #: qcsrc/menu/xonotic/keybinder.qc:99
 msgid "Teamplay"
-msgstr "Equipe"
+msgstr "Equipa"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:148
 msgid "Only when near crosshair"
-msgstr "Apenas quando próximo à mira"
+msgstr "Apenas quando próximo da mira"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
 msgid "Display health and armor"
-msgstr "Exibir saúde e armadura"
+msgstr "Mostrar vida e armadura"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:157
 msgid "Damage overlay:"
@@ -7754,32 +7758,33 @@ msgstr "Sobreposição do dano:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:160
 msgid "Dynamic HUD"
-msgstr "HUD dinâmico"
+msgstr "Interface dinâmica"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:161
 msgid "HUD moves around following player's movement"
-msgstr "O HUD se move de acordo com o movimento do jogador"
+msgstr "A interface move-se de acordo com o movimento do jogador"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:163
 msgid "Shake the HUD when hurt"
-msgstr "Vibrar o HUD ao ser atingido"
+msgstr "Vibrar a interface ao ser atingido"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:167
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qh:6
 msgid "Enter HUD editor"
-msgstr "Entrar no editor do HUD"
+msgstr "Entrar no editor da interface"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
 msgid "HUD"
-msgstr "HUD"
+msgstr "Interface"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:21
 msgid "In order for the HUD editor to show, you must first be in game."
-msgstr "Para o editor do HUD aparecer, é necessário estar jogando em um mapa."
+msgstr ""
+"Para o editor da interface aparecer, é necessário estar a jogar num mapa."
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
 msgid "Do you wish to start a local game to set up the HUD?"
-msgstr "Quer iniciar um jogo local para personalizar o HUD?"
+msgstr "Queres iniciar um jogo local para personalizar a interface?"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
 msgid "Frag Information"
@@ -7787,19 +7792,19 @@ msgstr "Informações de Execuções"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:26
 msgid "Display information about killing sprees"
-msgstr "Exibir informação sobre sequências de mortes"
+msgstr "Mostrar informação sobre sequências de mortes"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:29
 msgid "Only display sprees if they are achievements"
-msgstr "Apenas exibir sequências se forem conquistas"
+msgstr "Mostrar apenas sequências se forem conquistas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:34
 msgid "Show spree information in centerprints"
-msgstr "Exibir informação de sequências em impressões centrais"
+msgstr "Mostrar informação de sequências em impressões centrais"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:38
 msgid "Show spree information in death messages"
-msgstr "Exibir informação de sequências em mensagens de morte"
+msgstr "Mostrar informação de sequências em mensagens de morte"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:43
 msgid "Sprees in info messages:"
@@ -7807,7 +7812,7 @@ msgstr "Sequências em mensagens de informação:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
 msgid "SPREES^Disabled"
-msgstr "Desabilitadas"
+msgstr "Desativadas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
 msgid "Target"
@@ -7842,11 +7847,11 @@ msgstr "Configurações do Modo de Jogo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:67
 msgid "Display capture times in Capture The Flag"
-msgstr "Exibir tempos de captura em Capture a Bandeira"
+msgstr "Mostrar tempos de captura em Capturar a Bandeira"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:71
 msgid "Display name of flag stealer in Capture The Flag"
-msgstr "Exibir nome do ladrão da bandeira em Capture a Bandeira"
+msgstr "Mostrar nome do ladrão da bandeira em Capturar a Bandeira"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:76
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:91
@@ -7856,15 +7861,15 @@ msgstr "Outros"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
 msgid "Display console messages in the top left corner"
-msgstr "Exibir mensagens de console no canto superior esquerdo"
+msgstr "Mostrar mensagens da consola no canto superior esquerdo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
 msgid "Display all info messages in the chatbox"
-msgstr "Exibir todas as mensagens de informação no bate-papo"
+msgstr "Mostrar todas as mensagens de informação na conversação"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
 msgid "Display player statuses in the chatbox"
-msgstr "Exibir status de jogadores no bate-papo"
+msgstr "Mostrar estado dos jogadores na conversação"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
 msgid "Powerup notifications"
@@ -7945,11 +7950,11 @@ msgstr "Forçar modelos dos jogadores para ficarem iguais ao meu"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:53
 msgid "Force player colors to mine"
-msgstr "Forçar cores de jogadores para ficarem iguais às minhas"
+msgstr "Forçar cores dos jogadores para ficarem iguais às minhas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:56
 msgid "In non teamplay modes only"
-msgstr "Apenas em modos de jogo que não sejam de equipes"
+msgstr "Apenas em modos de jogo que não sejam de equipas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
 msgid "Body fading:"
@@ -7961,7 +7966,7 @@ msgstr "Tripas:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:65
 msgid "GIBS^None"
-msgstr "Desabilitadas"
+msgstr "Desativadas"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:66
 msgid "GIBS^Few"
@@ -7981,19 +7986,19 @@ msgstr "Modelos"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qh:8
 msgid "Customize how players and items are displayed in game"
-msgstr "Personalize como jogadores e itens são exibidos dentro do jogo"
+msgstr "Personalizar como os jogadores e itens são mostrados dentro do jogo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:26
 msgid "1st person perspective"
-msgstr "Perspectiva em 1ª pessoa"
+msgstr "Perspetiva na 1ª pessoa"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:30
 msgid "Slide to third person upon death"
-msgstr "Mudar para terceira pessoa depois de morrer"
+msgstr "Mudar para terceira pessoa depois de morrer"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:34
 msgid "Smooth the view when landing from a jump"
-msgstr "Suavizar a visão quando aterrissar de um salto"
+msgstr "Suavizar a visão quando aterrar de um salto"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:38
 msgid "Smooth the view while crouching"
@@ -8009,7 +8014,7 @@ msgstr "Oscilação de visão ao andar"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:51
 msgid "3rd person perspective"
-msgstr "Perspectiva em 3ª pessoa"
+msgstr "Perspetiva na 3ª pessoa"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:55
 msgid "Back distance"
@@ -8021,7 +8026,7 @@ msgstr "Distância para cima"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:67
 msgid "Allow passing through walls while spectating"
-msgstr "Atravessar paredes quando estiver de espectador"
+msgstr "Atravessar paredes quando for espetador"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:70
 msgid "Field of view:"
@@ -8046,7 +8051,7 @@ msgstr "Velocidade do zoom:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:83
 msgid "How fast the view will be zoomed, disable to zoom instantly"
-msgstr "Quão rápido será o zoom da visão, desabilite para zoom instantâneo"
+msgstr "Quão rápido será o zoom da visão, desativa para zoom instantâneo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:92
 msgid "ZOOM^Instant"
@@ -8061,8 +8066,8 @@ msgid ""
 "How zoom changes sensitivity, from 0 (lower sensitivity) to 1 (no "
 "sensitivity change)"
 msgstr ""
-"Como o zoom altera a sensibilidade, a partir do valor 0 (sensibilidade mais "
-"baixa) para 1 (sem alterações na sensibilidade)"
+"Como o zoom altera a sensibilidade. A partir do valor 0 (sensibilidade mais "
+"baixa) até 1 (sem alterações na sensibilidade)"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:101
 msgid "Velocity zoom"
@@ -8070,7 +8075,7 @@ msgstr "Zoom baseado na velocidade"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:102
 msgid "Forward movement only"
-msgstr "Apenas ao movimentar-se para frente"
+msgstr "Apenas no movimento para a frente"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:106
 msgid "VZOOM^Factor"
@@ -8078,15 +8083,15 @@ msgstr "Fator"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:113
 msgid "Display reticle 2D overlay while zooming"
-msgstr "Exibe uma sobreposição reticular em 2D durante o zoom"
+msgstr "Mostra uma sobreposição reticular em 2D durante o zoom"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:116
 msgid "Release zoom when you die or respawn"
-msgstr "Soltar o zoom quando você morre ou ressurge"
+msgstr "Largar o zoom quando morro ou ressurgo"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:120
 msgid "Release zoom when you switch weapons"
-msgstr "Soltar o zoom quando você troca de arma"
+msgstr "Largar o zoom quando troco de arma"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qh:7
 #: qcsrc/menu/xonotic/keybinder.qc:76
@@ -8112,50 +8117,49 @@ msgstr "Usar lista de prioridades como ordem de alternação de armas"
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:51
 msgid ""
 "Make use of the list above when cycling through weapons with the mouse wheel"
-msgstr ""
-"Faz uso da lista acima durante a alternação de armas com a roda do mouse"
+msgstr "Usar a lista acima durante a alternação de armas com a roda do rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:53
 msgid "Cycle through only usable weapon selections"
-msgstr "Alterne somente entre armas utilizáveis"
+msgstr "Alternar apenas entre armas utilizáveis"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:57
 msgid "Auto switch weapons on pickup"
-msgstr "Trocar para a arma coletada automaticamente"
+msgstr "Trocar para a arma apanhada automaticamente"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:58
 msgid ""
 "Automatically switch to newly picked up weapons if they are better than what "
 "you are carrying"
 msgstr ""
-"Alterna automaticamente para a arma coletada caso ela seja melhor do que a "
-"que você está carregando"
+"Muda automaticamente para a arma apanhada caso ela seja melhor do que a que "
+"estiveres a carregar"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:61
 msgid "Release attack buttons when you switch weapons"
-msgstr "Soltar os botões de ataque durante a troca de arma"
+msgstr "Libertar os botões de ataque quando troco de arma"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:64
 msgid "Draw 1st person weapon model"
-msgstr "Renderizar modelo de arma em 1ª pessoa"
+msgstr "Renderizar modelo de arma na 1ª pessoa"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:65
 msgid "Draw the weapon model"
-msgstr "Exibe os modelos das armas em sua tela"
+msgstr "Mostra os modelos das armas no ecrã"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:69
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:72
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:75
 msgid "Position of the weapon model; requires reconnect"
-msgstr "Posicionamento do modelo de arma; é preciso reconectar-se"
+msgstr "Posicionamento do modelo da arma; necessita de reconexão"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:80
 msgid "Gun model swaying"
-msgstr "Mover modelo de arma ao mover o mouse"
+msgstr "Mover modelo de arma ao mover o rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:85
 msgid "Gun model bobbing"
-msgstr "Oscilar modelo de arma"
+msgstr "Oscilar modelo da arma"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qh:7
 #: qcsrc/menu/xonotic/keybinder.qc:43
@@ -8180,11 +8184,11 @@ msgstr "Limpar"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:52
 msgid "Reset all"
-msgstr "Redefinir tudo"
+msgstr "Repor tudo"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:57
 msgid "Mouse"
-msgstr "Mouse"
+msgstr "Rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:59
 msgid "Sensitivity:"
@@ -8192,50 +8196,50 @@ msgstr "Sensibilidade:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:61
 msgid "Mouse speed multiplier"
-msgstr "Multiplicador da velocidade do mouse"
+msgstr "Multiplicador da velocidade do rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:63
 msgid "Smooth aiming"
-msgstr "Suavizar mouse"
+msgstr "Suavizar rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:64
 msgid "Smoothes the mouse movement, but makes aiming slightly less responsive"
 msgstr ""
-"Suaviza os movimentos do mouse, mas torna a mira levemente menos responsiva"
+"Suaviza os movimentos do rato, mas torna a mira um pouco menos responsiva"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:66
 msgid "Invert aiming"
-msgstr "Inverter mouse"
+msgstr "Inverter rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:67
 msgid "Invert mouse movement on the Y-axis"
-msgstr "Inverter eixo Y do movimento do mouse"
+msgstr "Inverter eixo Y do movimento do rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:69
 msgid "Use system mouse positioning"
-msgstr "Usar posicionamento de mouse do sistema"
+msgstr "Usar posicionamento do rato do sistema"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:74
 msgid "Enable built in mouse acceleration"
-msgstr "Habilitar aceleração de mouse imbutida"
+msgstr "Ativar aceleração de rato embebida"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:78
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:82
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:85
 msgid "Disable system mouse acceleration"
-msgstr "Desabilitar aceleração de mouse do SO"
+msgstr "Desativar aceleração do rato do sistema"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:79
 msgid "Make use of DGA mouse input"
-msgstr "Fazer uso da entrada DGA de mouse"
+msgstr "Fazer uso da entrada DGA do rato"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:93
 msgid "Pressing \"enter console\" key also closes it"
-msgstr " Pressionar \"abrir console\" também o fecha"
+msgstr " Pressionar a tecla \"abrir consola\" também a fecha"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:94
 msgid "Allow the console toggling bind to also close the console"
-msgstr "Permite que o atalho para abrir o console também feche-o"
+msgstr "Permite que o atalho para abrir a consola também a feixe"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:96
 msgid "Automatically repeat jumping if holding jump"
@@ -8247,11 +8251,11 @@ msgstr "Mochila a jato ao saltar:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:101
 msgid "JPJUMP^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:102
 msgid "Air only"
-msgstr "Somente no ar"
+msgstr "Apenas no ar"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:103
 msgid "JPJUMP^All"
@@ -8277,7 +8281,7 @@ msgstr "Cancelar"
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
 msgid "User defined key bind"
-msgstr "Botão de atalho definido pelo usuário"
+msgstr "Botão de atalho definido pelo utilizador"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:11
 #, c-format
@@ -8306,7 +8310,7 @@ msgstr "Porta UDP do cliente:"
 msgid "Force client to use chosen port unless it is set to 0"
 msgstr ""
 "Força os clientes a utilizarem as portas escolhidas a menos que esteja "
-"definido como 0 "
+"definido como 0"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
 msgid "Bandwidth:"
@@ -8314,7 +8318,7 @@ msgstr "Largura de banda:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:36
 msgid "Specify your network speed"
-msgstr "Especifique a velocidade da sua rede"
+msgstr "Especifica a velocidade da tua rede"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
 msgid "56k"
@@ -8350,15 +8354,15 @@ msgstr "Consultas ao servidor/s:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
 msgid "Downloads:"
-msgstr "Downloads:"
+msgstr "Descarregamentos:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:54
 msgid "Maximum number of concurrent HTTP/FTP downloads"
-msgstr "Número máximo de downloads simultâneos via HTTP/FTP"
+msgstr "Número máximo de descarregamentos simultâneos via HTTP/FTP"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:56
 msgid "Download speed:"
-msgstr "Velocidade de download:"
+msgstr "Velocidade de descarregamento:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:69
 msgid "Local latency:"
@@ -8366,11 +8370,11 @@ msgstr "Latência local:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:73
 msgid "Show netgraph"
-msgstr "Exibir gráfico de rede"
+msgstr "Mostrar gráfico de rede"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:74
 msgid "Show a graph of packet sizes and other information"
-msgstr "Exibe um gráfico de tamanhos de pacotes e outras informações"
+msgstr "Mostra um gráfico de tamanhos de pacotes e outras informações"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:76
 msgid "Client-side movement prediction"
@@ -8402,11 +8406,11 @@ msgstr "Alvo:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:104
 msgid "TRGT^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:116
 msgid "Idle limit:"
-msgstr "Em segundo plano:"
+msgstr "Limite em segundo plano:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:122
 msgid "IDLFPS^Unlimited"
@@ -8414,15 +8418,15 @@ msgstr "Ilimitado"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:126
 msgid "Save processing time for other apps"
-msgstr "Salvar tempo de processamento para outras aplicações"
+msgstr "Gravar tempo de processamento para outras aplicações"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:129
 msgid "Show frames per second"
-msgstr "Exibir taxa de quadros por segundo"
+msgstr "Mostrar taxa de quadros por segundo"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:130
 msgid "Show your rendered frames per second"
-msgstr "Exibe a sua taxa de quadros por segundo"
+msgstr "Mostra a tua taxa de quadros por segundo"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
 msgid "Menu tooltips:"
@@ -8433,12 +8437,12 @@ msgid ""
 "Menu tooltips: disabled, standard or advanced (also shows cvar or console "
 "command bound to the menu item)"
 msgstr ""
-"Dicas de menu: desabilitado, padrão ou avançado (também mostra a cvar ou "
-"comando de console ligado ao item de menu)"
+"Dicas de menu: desativado, padrão ou avançado (também mostra a cvar ou "
+"comando da consola ligado ao item do menu)"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:138
 msgid "TLTIP^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:139
 msgid "TLTIP^Standard"
@@ -8450,15 +8454,15 @@ msgstr "Avançado"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:143
 msgid "Show current date and time"
-msgstr "Exibir data e hora atual"
+msgstr "Mostrar data e hora atual"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:144
 msgid "Show current date and time of day, useful on screenshots"
-msgstr "Exibe a data e hora atual do dia, útil para screenshots"
+msgstr "Mostra a data e hora atual do dia, útil para capturas de ecrã"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:147
 msgid "Enable developer mode"
-msgstr "Habilitar modo de desenvolvedor"
+msgstr "Ativar modo de programador"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:151
 msgid "Advanced settings..."
@@ -8466,13 +8470,12 @@ msgstr "Configurações avançadas..."
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:152
 msgid "Advanced settings where you can tweak every single variable of the game"
-msgstr ""
-"Definições avançadas onde você poderá ajustar cada uma das variáveis do jogo"
+msgstr "Definições avançadas onde podes ajustar cada uma das variáveis do jogo"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:157
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qh:6
 msgid "Factory reset"
-msgstr "Configurações padrões"
+msgstr "Configurações de fábrica"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:31
 msgid "Cvar filter:"
@@ -8480,7 +8483,7 @@ msgstr "Filtro de cvar:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:38
 msgid "Modified cvars only"
-msgstr "Somente cvars modificadas"
+msgstr "Apenas cvars alteradas"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:45
 msgid "Setting:"
@@ -8505,13 +8508,14 @@ msgstr "Configurações avançadas"
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:11
 msgid "Are you sure you want to reset all settings?"
 msgstr ""
-"Tem certeza de que deseja redefinir todas as configurações para o padrão?"
+"Tens certeza de que queres redefinir todas as configurações para as "
+"originais?"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:13
 msgid "This will create a backup config in your data directory"
 msgstr ""
-"Isso irá criar uma cópia da sua configuração na seguinte pasta: C:\\Users"
-"\\[usuário]\\Saved Games\\xonotic\\data"
+"Isto irá criar uma cópia da tua configuração na seguinte pasta: C:\\Users"
+"\\[utilizador]\\Saved Games\\xonotic\\data"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:25
 msgid "Menu Skins"
@@ -8527,7 +8531,7 @@ msgstr "Definir idioma"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:74
 msgid "Disable gore effects and harsh language"
-msgstr "Desabilitar sangue e linguagem inapropriada"
+msgstr "Desativar sangue e linguagem inapropriada"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:75
 msgid ""
@@ -8535,18 +8539,19 @@ msgid ""
 "(default: disabled)"
 msgstr ""
 "Substitui o sangue com conteúdo que não contém nenhum efeito violento "
-"(padrão: desabilitado)"
+"(padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:10
 msgid "While connected language changes will be applied only to the menu,"
 msgstr ""
-"Enquanto estiver conectado, alterações no idioma serão aplicadas somente no "
-"menu."
+"Enquanto estiver conectado, as alterações no idioma serão aplicadas apenas "
+"no menu."
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
 msgid "full language changes will take effect starting from the next game"
 msgstr ""
-"Alterações completas de idioma surtirão efeito a partir da próxima partida"
+"As alterações completas de idioma surtirão efeito apenas a partir da próxima "
+"partida"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
 msgid "Disconnect now"
@@ -8622,7 +8627,7 @@ msgstr "32bit"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:59
 msgid "Full screen"
-msgstr "Tela cheia"
+msgstr "Ecrã inteiro"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:61
 msgid "Vertical Synchronization"
@@ -8633,13 +8638,13 @@ msgid ""
 "Enable vertical synchronization to prevent tearing, will cap your fps to the "
 "screen refresh rate (default: disabled)"
 msgstr ""
-"Habilita a sincronização vertical para evitar cortes na tela. Isso irá "
-"limitar a quantidade de quadros por segundo em relação à taxa de atualização "
-"do monitor (padrão: desabilitado)"
+"Ativa a sincronização vertical para evitar cortes no ecrã. Isto irá limitar "
+"a quantidade de frames por segundo em relação à taxa de atualização do "
+"monitor (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:67
 msgid "Flip view horizontally"
-msgstr "Girar a visão horizontalmente"
+msgstr "Inverter a visão na horizontal"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:68
 msgid "Poor man's left handed mode (default: off)"
@@ -8655,7 +8660,7 @@ msgstr "Qualidade do filtro anisotrópico (padrão: 1x)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:74
 msgid "ANISO^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:75
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:86
@@ -8684,12 +8689,12 @@ msgid ""
 "Enable antialiasing, which smooths the edges of 3D geometry. Note that it "
 "might decrease performance by quite a lot (default: disabled)"
 msgstr ""
-"Habilita o anti-serrilhado, o qual suaviza as bordas da geometria em 3D. "
-"Note que isso pode diminuir bastante o desempenho (padrão: desabilitado)"
+"Ativa o anti-serrilhado, o qual suaviza as bordas da geometria em 3D. Nota "
+"que isto pode diminuir bastante o desempenho (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:85
 msgid "AA^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:92
 msgid "High-quality frame buffer"
@@ -8704,12 +8709,12 @@ msgid ""
 "Eliminate overdraw by rendering a depth-only version of the scene before the "
 "normal rendering starts (default: disabled)"
 msgstr ""
-"Elimina o sobredesenho renderizando uma versão de profundidade única da cena "
-"antes que a renderização normal comece (padrão: desabilitado)"
+"Elimina o sobre desenho renderizando uma versão de profundidade única da "
+"cena antes que a renderização normal comece (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:100
 msgid "DF^Disabled"
-msgstr "Desabilitado"
+msgstr "Desativado"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:101
 msgid "DF^World"
@@ -8797,19 +8802,19 @@ msgid ""
 "requires GLSL color control (default: 1)"
 msgstr ""
 "Ajuste da saturação (0 = tons de cinza, 1 = normal, 2 = muito saturado), "
-"requer controle de cor GLSL (padrão: 1)"
+"requer controlo da cor GLSL (padrão: 1)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:146
 msgid "LIT^Ambient:"
-msgstr "Iluminação ambiental:"
+msgstr "Iluminação do ambiente:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:148
 msgid ""
 "Ambient lighting, if set too high it tends to make light on maps look dull "
 "and flat (default: 4)"
 msgstr ""
-"Iluminação ambiental, caso o valor seja muito alto, poderá fazer com que as "
-"luzes dos mapas fiquem achatadas e sem graça (padrão: 4)"
+"Iluminação do ambiente, caso o valor seja muito alto, poderá fazer com que "
+"as luzes dos mapas fiquem achatadas e sem piada (padrão: 4)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:150
 msgid "Intensity:"
@@ -8821,16 +8826,16 @@ msgstr "Brilho geral da renderização (padrão: 1)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:155
 msgid "Wait for GPU to finish each frame"
-msgstr "Esperar que a placa de vídeo termine cada quadro"
+msgstr "Esperar que a placa gráfica termine cada frame"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:156
 msgid ""
 "Make the CPU wait for the GPU to finish each frame, can help with some "
 "strange input or video lag on some machines (default: disabled)"
 msgstr ""
-"Faz com que o processador espere pela placa de vídeo terminar cada quadro. "
-"Pode ajudar no caso de alguns atrasos nos dispositivos de entrada ou lag de "
-"vídeo em algumas máquinas (padrão: desabilitado)"
+"Faz com que o processador espere pela placa de gráfica termine de renderizar "
+"cada frame. Pode ajudar em alguns casos de atrasos nos dispositivos de "
+"entrada ou atrasos de vídeo em algumas máquinas (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:158
 msgid "Use OpenGL 2.0 shaders (GLSL)"
@@ -8838,27 +8843,27 @@ msgstr "Usar shaders de OpenGL 2.0 (GLSL)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:162
 msgid "Use GLSL to handle color control"
-msgstr "Usar GLSL para o controle de cores"
+msgstr "Usar GLSL para o controlo das cores"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:163
 msgid ""
 "Enable use of GLSL to apply gamma correction, note that it might decrease "
 "performance by a lot (default: disabled)"
 msgstr ""
-"Habilita o uso de GLSL para aplicar correção de gama. Note que isso pode "
-"diminuir bastante o desempenho (padrão: desabilitado)"
+"Ativa o uso de GLSL para aplicar a correção de gama. Nota que isto pode "
+"diminuir bastante o desempenho (padrão: desativado)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:168
 msgid "Psycho coloring (easter egg)"
-msgstr "Cores 'Psycho' (easter egg)"
+msgstr "Cores psicadélicas (easter egg)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:171
 msgid "Trippy vertices (easter egg)"
-msgstr "Vértices 'Trip' (easter egg)"
+msgstr "Vértices viagem (easter egg)"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer.qc:110
 msgid "Instant action! (random map with bots)"
-msgstr "Ação Instantânea! (mapa aleatório com bots)"
+msgstr "Ação instantânea! (mapa aleatório com robôs)"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer.qc:117
 msgid "???"
@@ -8891,8 +8896,8 @@ msgstr "Um Jogador"
 #: qcsrc/menu/xonotic/dialog_singleplayer.qh:7
 msgid "Play the singleplayer campaign or instant action matches against bots"
 msgstr ""
-"Jogue a campanha de um jogador ou inicie uma partida de ação instantânea "
-"contra bots"
+"Joga a campanha de um jogador ou inicia uma partida de ação instantânea "
+"contra robôs"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
 msgid "Winner"
@@ -8900,11 +8905,11 @@ msgstr "Vencedor"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:32
 msgid "join 'best' team (auto-select)"
-msgstr "juntar-se à 'melhor' equipe (seleção automática)"
+msgstr "juntar-me à 'melhor' equipa (seleção automática)"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:33
 msgid "Autoselect team (recommended)"
-msgstr "Selecionar equipe automaticamente (recomendado)"
+msgstr "Selecionar equipa automaticamente (recomendado)"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:37
 msgid "red"
@@ -8928,21 +8933,21 @@ msgstr "assistir"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qh:7
 msgid "Team Selection"
-msgstr "Seleção de Equipe"
+msgstr "Seleção de Equipa"
 
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:10
 msgid "Allow player statistics to use your nickname?"
-msgstr "Permitir que as estatísticas de jogadores usem o seu apelido?"
+msgstr "Permitir que as estatísticas de jogadores usem o teu apelido?"
 
 #: qcsrc/menu/xonotic/dialog_uid2name.qc:12
 msgid "Answering \"No\" you will appear as \"Anonymous player\""
 msgstr ""
-"Selecionando \"Não\" você aparecerá como \"Anonymous player\" (em português, "
-"\"Jogador anônimo\")"
+"Selecionando \"Não\" aparecerás como \"Anonymous player\" (em português, "
+"\"Jogador anónimo\")"
 
 #: qcsrc/menu/xonotic/gametypelist.qc:86
 msgid "teamplay"
-msgstr "jogo em equipe"
+msgstr "jogo em equipa"
 
 #: qcsrc/menu/xonotic/gametypelist.qc:88
 msgid "free for all"
@@ -8954,19 +8959,19 @@ msgstr "Movimento"
 
 #: qcsrc/menu/xonotic/keybinder.qc:30
 msgid "forward"
-msgstr "Mover-se para frente"
+msgstr "mover para frente"
 
 #: qcsrc/menu/xonotic/keybinder.qc:31
 msgid "backpedal"
-msgstr "Mover-se para trás"
+msgstr "mover para trás"
 
 #: qcsrc/menu/xonotic/keybinder.qc:32
 msgid "strafe left"
-msgstr "Mover-se para a esquerda"
+msgstr "mover para a esquerda"
 
 #: qcsrc/menu/xonotic/keybinder.qc:33
 msgid "strafe right"
-msgstr "Mover-se para a direita"
+msgstr "mover para a direita"
 
 #: qcsrc/menu/xonotic/keybinder.qc:34
 msgid "jump / swim"
@@ -9010,7 +9015,7 @@ msgstr "recarregar"
 
 #: qcsrc/menu/xonotic/keybinder.qc:49
 msgid "drop weapon / throw nade"
-msgstr "largar arma / arremessar granada"
+msgstr "largar arma / atirar granada"
 
 #: qcsrc/menu/xonotic/keybinder.qc:77
 msgid "hold zoom"
@@ -9022,11 +9027,11 @@ msgstr "ativar/desativar zoom"
 
 #: qcsrc/menu/xonotic/keybinder.qc:79
 msgid "show scores"
-msgstr "exibir pontuações"
+msgstr "mostrar pontuações"
 
 #: qcsrc/menu/xonotic/keybinder.qc:80
 msgid "screen shot"
-msgstr "tirar screenshot"
+msgstr "tirar captura de ecrã"
 
 #: qcsrc/menu/xonotic/keybinder.qc:81
 msgid "maximize radar"
@@ -9034,11 +9039,11 @@ msgstr "maximizar radar"
 
 #: qcsrc/menu/xonotic/keybinder.qc:82
 msgid "3rd person view"
-msgstr "visão em 3ª pessoa"
+msgstr "visão na 3ª pessoa"
 
 #: qcsrc/menu/xonotic/keybinder.qc:83
 msgid "enter spectator mode"
-msgstr "entrar no modo de expectador"
+msgstr "entrar no modo de espectador"
 
 #: qcsrc/menu/xonotic/keybinder.qc:85
 msgid "Communicate"
@@ -9046,15 +9051,15 @@ msgstr "Comunicação"
 
 #: qcsrc/menu/xonotic/keybinder.qc:86
 msgid "public chat"
-msgstr "Bate-papo público"
+msgstr "Conversação pública"
 
 #: qcsrc/menu/xonotic/keybinder.qc:87 qcsrc/menu/xonotic/keybinder.qc:100
 msgid "team chat"
-msgstr "Bate-papo de equipe"
+msgstr "Conversação da equipa"
 
 #: qcsrc/menu/xonotic/keybinder.qc:88
 msgid "show chat history"
-msgstr "exibir histórico do bate-papo"
+msgstr "mostrar histórico da conversação"
 
 #: qcsrc/menu/xonotic/keybinder.qc:89
 msgid "vote YES"
@@ -9070,7 +9075,7 @@ msgstr "Cliente"
 
 #: qcsrc/menu/xonotic/keybinder.qc:95
 msgid "enter console"
-msgstr "abrir o console"
+msgstr "abrir a consola"
 
 #: qcsrc/menu/xonotic/keybinder.qc:96
 msgid "disconnect"
@@ -9082,7 +9087,7 @@ msgstr "sair"
 
 #: qcsrc/menu/xonotic/keybinder.qc:101
 msgid "auto-join team"
-msgstr "juntar-se à uma equipe automáticamente"
+msgstr "juntar-me a uma equipa automaticamente"
 
 #: qcsrc/menu/xonotic/keybinder.qc:103
 msgid "drop key / drop flag"
@@ -9102,17 +9107,17 @@ msgstr "arrastar objeto"
 
 #: qcsrc/menu/xonotic/keybinder.qc:110
 msgid "User defined"
-msgstr "Definido pelo usuário"
+msgstr "Definido pelo utilizador"
 
 #: qcsrc/menu/xonotic/mainwindow.qc:64 qcsrc/menu/xonotic/mainwindow.qc:67
 msgid "Do not press this button again!"
-msgstr "Não aperte este botão novamente!"
+msgstr "Não pressiones este botão outra vez!"
 
 #: qcsrc/menu/xonotic/maplist.qc:291
 msgid ""
 "Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"
 msgstr ""
-"Huh? Não posso jogar isto (m é NULO). Refiltrando para que isso não ocorra "
+"Huh? Não posso jogar isto (m é NULO). Refiltrando para que isto não ocorra "
 "novamente.\n"
 
 #: qcsrc/menu/xonotic/maplist.qc:299
@@ -9125,12 +9130,12 @@ msgid ""
 "Huh? Can't play this (invalid game type). Refiltering so this won't happen "
 "again.\n"
 msgstr ""
-"Huh? Não posso jogar isto (modo de jogo inválido). Refiltrando para que isso "
+"Huh? Não posso jogar isto (modo de jogo inválido). Refiltrando para que isto "
 "não ocorra novamente.\n"
 
 #: qcsrc/menu/xonotic/playerlist.qc:100 qcsrc/menu/xonotic/playerlist.qc:110
 msgid "spectator"
-msgstr "espectador"
+msgstr "espetador"
 
 #: qcsrc/menu/xonotic/playermodel.qc:170
 msgid "<no model found>"
@@ -9138,7 +9143,7 @@ msgstr "<nenhum modelo encontrado>"
 
 #: qcsrc/menu/xonotic/serverlist.qc:273
 msgid "Favorite"
-msgstr "Favoritar"
+msgstr "Adicionar aos favoritos"
 
 #: qcsrc/menu/xonotic/serverlist.qc:274
 msgid ""
@@ -9185,7 +9190,7 @@ msgstr "modificação: %s"
 #: qcsrc/menu/xonotic/serverlist.qc:1063
 #, c-format
 msgid "modified settings"
-msgstr "configurações modificadas"
+msgstr "configurações alteradas"
 
 #: qcsrc/menu/xonotic/serverlist.qc:1063
 #, c-format
@@ -9194,11 +9199,11 @@ msgstr "configurações oficiais"
 
 #: qcsrc/menu/xonotic/serverlist.qc:1065
 msgid "stats disabled"
-msgstr "estatísticas desabilitadas"
+msgstr "estatísticas desativadas"
 
 #: qcsrc/menu/xonotic/serverlist.qc:1065
 msgid "stats enabled"
-msgstr "estatísticas habilitadas"
+msgstr "estatísticas ativadas"
 
 #: qcsrc/menu/xonotic/serverlist.qh:151
 msgid "SLCAT^Favorites"
@@ -9222,7 +9227,7 @@ msgstr "Modo Competitivo"
 
 #: qcsrc/menu/xonotic/serverlist.qh:156
 msgid "SLCAT^Modified Servers"
-msgstr "Servidores Modificados"
+msgstr "Servidores Alterados"
 
 #: qcsrc/menu/xonotic/serverlist.qh:157
 msgid "SLCAT^Overkill"
@@ -9263,7 +9268,7 @@ msgid ""
 "gives for better performance (default: 1)"
 msgstr ""
 "Multiplicador para a quantidade de partículas. Menos significa menos "
-"partículas, o que resulta em um melhor desempenho (padrão: 1)"
+"partículas, o que resulta num melhor desempenho (padrão: 1)"
 
 #: qcsrc/menu/xonotic/slider_particles.qc:14
 msgid "PART^OMG"
@@ -9306,7 +9311,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/slider_resolution.qc:115
 msgid "Screen resolution"
-msgstr "Resolução da tela"
+msgstr "Resolução do ecrã"
 
 #: qcsrc/menu/xonotic/slider_sbfadetime.qc:13
 msgid "PART^Slow"
@@ -9420,12 +9425,12 @@ msgid ""
 "Update can be downloaded at:\n"
 "%s\n"
 msgstr ""
-"A atualização pode ser baixada em:\n"
+"A atualização pode ser descarregada em:\n"
 "%s\n"
 
 #: qcsrc/menu/xonotic/util.qc:528
 msgid "Autogenerating mapinfo for newly added maps..."
-msgstr "Gerando mapinfo automaticamente para os novos mapas adicionados..."
+msgstr "A gerar mapinfo automaticamente para os novos mapas adicionados..."
 
 #: qcsrc/menu/xonotic/util.qc:557
 #, c-format
@@ -9435,15 +9440,15 @@ msgstr "^1%s VERSÃO DE TESTE"
 #: qcsrc/menu/xonotic/util.qc:577
 #, c-format
 msgid "Update to %s now!"
-msgstr "Atualize para %s agora!"
+msgstr "Atualizar para %s agora!"
 
 #: qcsrc/menu/xonotic/util.qc:662
 msgid ""
 "^1ERROR: Texture compression is required but not supported.\n"
 "^1Expect visual problems.\n"
 msgstr ""
-"^1ERRO: A compressão de texturas é necessária, mas não é suportada.\n"
-"^1Espere problemas visuais.\n"
+"^1ERRO: a compressão de texturas é necessária, mas não é suportada.\n"
+"^1Conta com prováveis problemas visuais.\n"
 "\n"
 
 #: qcsrc/menu/xonotic/util.qc:780
@@ -9452,14 +9457,14 @@ msgstr "Usar padrão"
 
 #: qcsrc/menu/xonotic/util.qc:800
 msgid "Team Color:"
-msgstr "Cor de Equipe:"
+msgstr "Cor da Equipa:"
 
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
-msgstr "Habilitar painel"
+msgstr "Ativar painel"
 
 #~ msgid "QMCMD^Chat"
-#~ msgstr "Bate-papo"
+#~ msgstr "Conversação"
 
 #~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-#~ msgstr "^BG%s%s^K1 chegou muito perto do foguete de ^BG%s^K1%s%s"
+#~ msgstr "^BG%s%s^K1 chegou muito perto do míssil de ^BG%s^K1%s%s"
diff --git a/common.pt_BR.po b/common.pt_BR.po
new file mode 100644 (file)
index 0000000..c3b8efc
--- /dev/null
@@ -0,0 +1,9465 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# Ivan Paulos Tomé <greylica@gmail.com>, 2016
+# Jean Trindade Pereira <jean_trindade2@hotmail.com>, 2018
+# Mirio <opivy@hotmail.de>, 2017
+# NotThatPrivate Yes <henriqueferreira2009@gmail.com>, 2015
+# Ricardo Manuel da Cruz Coelho da Silva <ricardo.mccs@gmail.com>, 2015
+# Rui <xymarior@yandex.com>, 2018
+msgid ""
+msgstr ""
+"Project-Id-Version: Xonotic\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2017-07-09 00:35+0200\n"
+"PO-Revision-Date: 2018-05-22 14:42+0000\n"
+"Last-Translator: Jean Trindade Pereira <jean_trindade2@hotmail.com>\n"
+"Language-Team: Portuguese (Brazil) (http://www.transifex.com/team-xonotic/"
+"xonotic/language/pt_BR/)\n"
+"Language: pt_BR\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+#: qcsrc/client/hud/hud_config.qc:239
+#, c-format
+msgid "^2Successfully exported to %s! (Note: It's saved in data/data/)\n"
+msgstr "^2Exportado com sucesso para %s! (Nota: Foi salvo em data/data/)\n"
+
+#: qcsrc/client/hud/hud_config.qc:243
+#, c-format
+msgid "^1Couldn't write to %s\n"
+msgstr "^1Não foi possível escrever para %s\n"
+
+#: qcsrc/client/hud/panel/chat.qc:82
+msgid "^3Player^7: This is the chat area."
+msgstr "^3Jogador^7: Isto é a área do bate-papo."
+
+#: qcsrc/client/hud/panel/engineinfo.qc:69
+#, c-format
+msgid "FPS: %.*f"
+msgstr "FPS: %.*f"
+
+#: qcsrc/client/hud/panel/infomessages.qc:87
+msgid "^1Observing"
+msgstr "^1Observando"
+
+#: qcsrc/client/hud/panel/infomessages.qc:89
+#, c-format
+msgid "^1Spectating: ^7%s"
+msgstr "^1Assistindo: ^7%s"
+
+#: qcsrc/client/hud/panel/infomessages.qc:100
+#, c-format
+msgid "^1Press ^3%s^1 to spectate"
+msgstr "^1Aperte ^3%s^1 para assistir"
+
+#: qcsrc/client/hud/panel/infomessages.qc:100
+#: qcsrc/menu/xonotic/keybinder.qc:40
+msgid "primary fire"
+msgstr "disparo primário"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#, c-format
+msgid "^1Press ^3%s^1 or ^3%s^1 for next or previous player"
+msgstr "^1Aperte ^3%s^1 ou ^3%s^1 para o jogador seguinte ou anterior"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#: qcsrc/client/hud/panel/infomessages.qc:106
+msgid "next weapon"
+msgstr "arma seguinte"
+
+#: qcsrc/client/hud/panel/infomessages.qc:102
+#: qcsrc/client/hud/panel/infomessages.qc:106
+msgid "previous weapon"
+msgstr "arma anterior"
+
+#: qcsrc/client/hud/panel/infomessages.qc:106
+#, c-format
+msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
+msgstr "^1Use ^3%s^1 ou ^3%s^1 para alterar a velocidade"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#, c-format
+msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
+msgstr "^1Aperte ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmera"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#: qcsrc/common/vehicles/cl_vehicles.qc:192
+msgid "drop weapon"
+msgstr "largar arma"
+
+#: qcsrc/client/hud/panel/infomessages.qc:108
+#: qcsrc/menu/xonotic/keybinder.qc:41
+msgid "secondary fire"
+msgstr "disparo secundário"
+
+#: qcsrc/client/hud/panel/infomessages.qc:111
+#, c-format
+msgid "^1Press ^3%s^1 for gamemode info"
+msgstr "^1Aperte ^3%s^1 para ver as informações do modo de jogo"
+
+#: qcsrc/client/hud/panel/infomessages.qc:111
+#: qcsrc/menu/xonotic/keybinder.qc:94
+msgid "server info"
+msgstr "informações do servidor"
+
+#: qcsrc/client/hud/panel/infomessages.qc:124
+msgid "^1Match has already begun"
+msgstr "^1A partida já começou"
+
+#: qcsrc/client/hud/panel/infomessages.qc:126
+msgid "^1You have no more lives left"
+msgstr "^1Você não tem mais vidas sobrando"
+
+#: qcsrc/client/hud/panel/infomessages.qc:128
+#: qcsrc/client/hud/panel/infomessages.qc:131
+#, c-format
+msgid "^1Press ^3%s^1 to join"
+msgstr "^1Aperte ^3%s^1 para entrar no jogo"
+
+#: qcsrc/client/hud/panel/infomessages.qc:128
+#: qcsrc/client/hud/panel/infomessages.qc:131
+msgid "jump"
+msgstr "saltar"
+
+#: qcsrc/client/hud/panel/infomessages.qc:139
+#, c-format
+msgid "^1Game starts in ^3%d^1 seconds"
+msgstr "^1A partida iniciará em ^3%d^1 segundo(s)"
+
+#: qcsrc/client/hud/panel/infomessages.qc:145
+msgid "^2Currently in ^1warmup^2 stage!"
+msgstr "^2Atualmente em fase de ^1aquecimento^2!"
+
+#: qcsrc/client/hud/panel/infomessages.qc:160
+#, c-format
+msgid "%sPress ^3%s%s to end warmup"
+msgstr "%sAperte ^3%s%s para terminar o aquecimento"
+
+#: qcsrc/client/hud/panel/infomessages.qc:160
+#: qcsrc/client/hud/panel/infomessages.qc:162
+#: qcsrc/client/hud/panel/infomessages.qc:175
+#: qcsrc/menu/xonotic/keybinder.qc:91
+msgid "ready"
+msgstr "pronto"
+
+#: qcsrc/client/hud/panel/infomessages.qc:162
+#, c-format
+msgid "%sPress ^3%s%s once you are ready"
+msgstr "%sAperte ^3%s%s assim que estiver pronto"
+
+#: qcsrc/client/hud/panel/infomessages.qc:167
+msgid "^2Waiting for others to ready up to end warmup..."
+msgstr ""
+"^2Esperando que os outros jogadores estejam prontos para acabar o "
+"aquecimento..."
+
+#: qcsrc/client/hud/panel/infomessages.qc:169
+msgid "^2Waiting for others to ready up..."
+msgstr "^2Esperando que os outros jogadores estejam prontos..."
+
+#: qcsrc/client/hud/panel/infomessages.qc:175
+#, c-format
+msgid "^2Press ^3%s^2 to end warmup"
+msgstr "^2Aperte ^3%s^2 para terminar o aquecimento"
+
+#: qcsrc/client/hud/panel/infomessages.qc:196
+msgid "Teamnumbers are unbalanced!"
+msgstr "As equipes estão desequilibradas!"
+
+#: qcsrc/client/hud/panel/infomessages.qc:199
+#, c-format
+msgid " Press ^3%s%s to adjust"
+msgstr " Aperte ^3%s%s para ajustar"
+
+#: qcsrc/client/hud/panel/infomessages.qc:199
+#: qcsrc/menu/xonotic/keybinder.qc:102
+msgid "team menu"
+msgstr "menu de equipe"
+
+#: qcsrc/client/hud/panel/infomessages.qc:209
+msgid "^1Spectating this player:"
+msgstr "^1Também estão assistindo a este jogador:"
+
+#: qcsrc/client/hud/panel/infomessages.qc:209
+msgid "^1Spectating you:"
+msgstr "^1Assistindo você:"
+
+#: qcsrc/client/hud/panel/infomessages.qc:225
+msgid "^7Press ^3ESC ^7to show HUD options."
+msgstr "^7Aperte ^3ESC ^7para exibir as opções de HUD."
+
+#: qcsrc/client/hud/panel/infomessages.qc:226
+msgid "^3Doubleclick ^7a panel for panel-specific options."
+msgstr ""
+"^3Clique duas vezes ^7em um painel para abrir sua janela de opções "
+"específicas."
+
+#: qcsrc/client/hud/panel/infomessages.qc:227
+msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
+msgstr "^3CTRL ^7para desligar teste de colisão, ^3SHIFT ^7e"
+
+#: qcsrc/client/hud/panel/infomessages.qc:228
+msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
+msgstr "^3ALT ^7+ ^3TECLAS DIRECIONAIS ^7para pequenos ajustes."
+
+#: qcsrc/client/hud/panel/modicons.qc:566
+msgid "Personal best"
+msgstr "Recorde pessoal"
+
+#: qcsrc/client/hud/panel/modicons.qc:576
+msgid "Server best"
+msgstr "Recorde do servidor"
+
+#: qcsrc/client/hud/panel/notify.qc:115 qcsrc/client/hud/panel/notify.qc:116
+#: qcsrc/client/hud/panel/score.qc:59
+#, c-format
+msgid "Player %d"
+msgstr "Jogador %d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:603
+#: qcsrc/client/hud/panel/quickmenu.qc:605
+#, c-format
+msgid "Submenu%d"
+msgstr "Submenu%d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:610
+#, c-format
+msgid "Command%d"
+msgstr "Comando%d"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:636
+msgid "Continue..."
+msgstr "Continuar..."
+
+#: qcsrc/client/hud/panel/quickmenu.qc:794
+#: qcsrc/client/hud/panel/quickmenu.qc:798
+msgid "Chat"
+msgstr ""
+
+#: qcsrc/client/hud/panel/quickmenu.qc:795
+msgid "QMCMD^:-) / nice one"
+msgstr ":-) / Boa jogada"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:795
+msgid "QMCMD^nice one"
+msgstr "Boa jogada"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:796
+msgid "QMCMD^good game"
+msgstr "Bom jogo"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:797
+msgid "QMCMD^hi / good luck"
+msgstr "Olá / Boa sorte"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:797
+msgid "QMCMD^hi / good luck and have fun"
+msgstr "Olá / Boa sorte e divirta-se"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:802
+#: qcsrc/client/hud/panel/quickmenu.qc:818
+msgid "QMCMD^Team chat"
+msgstr "Bate-papo de equipe"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:803
+msgid "QMCMD^quad soon"
+msgstr "Quad em breve"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:804
+msgid "QMCMD^free item %x^7 (l:%y^7)"
+msgstr "Item livre %x^7 (l:%y^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:804
+msgid "QMCMD^free item, icon"
+msgstr "Item livre, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:805
+msgid "QMCMD^took item (l:%l^7)"
+msgstr "Item pego (l:%l^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:805
+msgid "QMCMD^took item, icon"
+msgstr "Item pego, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:806
+msgid "QMCMD^negative"
+msgstr "Negativo"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:807
+msgid "QMCMD^positive"
+msgstr "Positivo"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:808
+msgid "QMCMD^need help (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "Preciso de ajuda (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:808
+msgid "QMCMD^need help, icon"
+msgstr "Preciso de ajuda, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:809
+msgid "QMCMD^enemy seen (l:%y^7)"
+msgstr "Inimigo avistado (l:%y^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:809
+msgid "QMCMD^enemy seen, icon"
+msgstr "Inimigo avistado, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:810
+msgid "QMCMD^flag seen (l:%y^7)"
+msgstr "Bandeira avistada (l:%y^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:810
+msgid "QMCMD^flag seen, icon"
+msgstr "Bandeira avistada, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:811
+msgid "QMCMD^defending (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "Defendendo (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:811
+msgid "QMCMD^defending, icon"
+msgstr "Defendendo, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:812
+msgid "QMCMD^roaming (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "Patrulhando (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:812
+msgid "QMCMD^roaming, icon"
+msgstr "Patrulhando, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:813
+msgid "QMCMD^attacking (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+msgstr "Atacando (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:813
+msgid "QMCMD^attacking, icon"
+msgstr "Atacando, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:814
+msgid "QMCMD^killed flagcarrier (l:%y^7)"
+msgstr "Portador da bandeira aniquilado (l:%y^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:814
+msgid "QMCMD^killed flagcarrier, icon"
+msgstr "Portador da bandeira aniquilado, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:815
+#, c-format
+msgid "QMCMD^dropped flag (l:%d^7)"
+msgstr "Bandeira largada (l:%d^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:815
+msgid "QMCMD^dropped flag, icon"
+msgstr "Bandeira largada, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:816
+msgid "QMCMD^drop weapon, icon"
+msgstr "Largar arma, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:816
+msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
+msgstr "Arma solta %w^7 (l:%l^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:817
+msgid "QMCMD^drop flag/key, icon"
+msgstr "Largar bandeira/chave, ícone"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:817
+msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
+msgstr "Bandeira/Chave largada %w^7 (l:%l^7)"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:821
+msgid "QMCMD^Send private message to"
+msgstr "Mandar mensagem privada para"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:823
+#: qcsrc/client/hud/panel/quickmenu.qc:860
+msgid "QMCMD^Settings"
+msgstr "Configurações"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:824
+#: qcsrc/client/hud/panel/quickmenu.qc:831
+msgid "QMCMD^View/HUD settings"
+msgstr "Configurações de Exibição/HUD"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:825
+msgid "QMCMD^3rd person view"
+msgstr "Visão em 3ª pessoa"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:826
+msgid "QMCMD^Player models like mine"
+msgstr "Modelos de jogadores como o meu"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:827
+msgid "QMCMD^Names above players"
+msgstr "Nomes sobre jogadores"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:828
+msgid "QMCMD^Crosshair per weapon"
+msgstr "Retículo por arma"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:829
+msgid "QMCMD^FPS"
+msgstr "FPS"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:830
+msgid "QMCMD^Net graph"
+msgstr "Gráfico da rede"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:833
+#: qcsrc/client/hud/panel/quickmenu.qc:836
+msgid "QMCMD^Sound settings"
+msgstr "Configurações de som"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:834
+msgid "QMCMD^Hit sound"
+msgstr "Som de acerto"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:835
+msgid "QMCMD^Chat sound"
+msgstr "Som do bate-papo"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:840
+#: qcsrc/client/hud/panel/quickmenu.qc:844
+msgid "QMCMD^Spectator camera"
+msgstr "Câmera de espectador"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:841
+msgid "QMCMD^1st person"
+msgstr "1ª pessoa"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:842
+msgid "QMCMD^3rd person around player"
+msgstr "3ª pessoa em volta do jogador"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:843
+msgid "QMCMD^3rd person behind"
+msgstr "3ª pessoa traseira"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:849
+#: qcsrc/client/hud/panel/quickmenu.qc:854
+msgid "QMCMD^Observer camera"
+msgstr "Câmera de observador"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:850
+msgid "QMCMD^Increase speed"
+msgstr "Aumentar velocidade"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:851
+msgid "QMCMD^Decrease speed"
+msgstr "Diminuir velocidade"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:852
+msgid "QMCMD^Wall collision off"
+msgstr "Colisão com paredes desligada"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:853
+msgid "QMCMD^Wall collision on"
+msgstr "Colisão com paredes ligada"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:857
+msgid "QMCMD^Fullscreen"
+msgstr "Tela cheia"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:859
+msgid "QMCMD^Translate chat messages"
+msgstr "Traduzir mensagens do bate-papo"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:862
+#: qcsrc/client/hud/panel/quickmenu.qc:872
+msgid "QMCMD^Call a vote"
+msgstr "Iniciar uma votação"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:863
+msgid "QMCMD^Restart the map"
+msgstr "Reiniciar o mapa"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:864
+msgid "QMCMD^End match"
+msgstr "Terminar a partida"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:867
+msgid "QMCMD^Reduce match time"
+msgstr "Reduzir tempo de partida"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:868
+msgid "QMCMD^Extend match time"
+msgstr "Estender tempo de partida"
+
+#: qcsrc/client/hud/panel/quickmenu.qc:871
+msgid "QMCMD^Shuffle teams"
+msgstr "Misturar as equipes"
+
+#: qcsrc/client/hud/panel/racetimer.qc:37
+#, c-format
+msgid " (-%dL)"
+msgstr " (-%dL)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:42
+#, c-format
+msgid " (+%dL)"
+msgstr " (+%dL)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:61
+msgid "Start line"
+msgstr "Linha de partida"
+
+#: qcsrc/client/hud/panel/racetimer.qc:63
+#: qcsrc/client/hud/panel/racetimer.qc:67
+msgid "Finish line"
+msgstr "Linha de chegada"
+
+#: qcsrc/client/hud/panel/racetimer.qc:65
+#, c-format
+msgid "Intermediate %d"
+msgstr "Intermediário %d"
+
+#: qcsrc/client/hud/panel/racetimer.qc:132
+msgid "^1Intermediate 1 (+15.42)"
+msgstr "^1Intermediário 1 (+15.42)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:135
+#: qcsrc/client/hud/panel/racetimer.qc:177
+#: qcsrc/client/hud/panel/racetimer.qc:227
+#, c-format
+msgid "^1PENALTY: %.1f (%s)"
+msgstr "^1PENALIDADE: %.1f (%s)"
+
+#: qcsrc/client/hud/panel/racetimer.qc:229
+#, c-format
+msgid "^2PENALTY: %.1f (%s)"
+msgstr "^2PENALIDADE: %.1f (%s)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:78
+msgid "SCO^bckills"
+msgstr "pblvítimas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:79
+msgid "SCO^bctime"
+msgstr "pbltempo"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:80
+msgid "SCO^caps"
+msgstr "capturas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:81
+msgid "SCO^captime"
+msgstr "tempo de captura"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:82
+msgid "SCO^deaths"
+msgstr "mortes"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:83
+msgid "SCO^destroyed"
+msgstr "destruído"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:84
+msgid "SCO^damage"
+msgstr "dano"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:85
+msgid "SCO^dmgtaken"
+msgstr "dano recebido"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:86
+msgid "SCO^drops"
+msgstr "quedas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:87
+msgid "SCO^faults"
+msgstr "faltas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:88
+msgid "SCO^fckills"
+msgstr "pbndvítimas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:89
+msgid "SCO^goals"
+msgstr "gols"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:90
+msgid "SCO^kckills"
+msgstr "pcvítimas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:91
+msgid "SCO^kdratio"
+msgstr "taxa de v/m"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:92
+msgid "SCO^k/d"
+msgstr "v/m"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:93
+msgid "SCO^kdr"
+msgstr "fmr"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:94
+msgid "SCO^kills"
+msgstr "vítimas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:95
+msgid "SCO^laps"
+msgstr "voltas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:96
+msgid "SCO^lives"
+msgstr "vidas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:97
+msgid "SCO^losses"
+msgstr "derrotas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:98
+msgid "SCO^name"
+msgstr "nome"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:99
+msgid "SCO^sum"
+msgstr "soma"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:100
+msgid "SCO^nick"
+msgstr "apelido"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:101
+msgid "SCO^objectives"
+msgstr "objetivos"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:102
+msgid "SCO^pickups"
+msgstr "coletas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:103
+msgid "SCO^ping"
+msgstr "ping"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:104
+msgid "SCO^pl"
+msgstr "pp"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:105
+msgid "SCO^pushes"
+msgstr "empurrões"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:106
+msgid "SCO^rank"
+msgstr "classificação"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:107
+msgid "SCO^returns"
+msgstr "retornos"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:108
+msgid "SCO^revivals"
+msgstr "ressurreições"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:109
+msgid "SCO^rounds won"
+msgstr "rodadas vencidas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:110
+msgid "SCO^score"
+msgstr "pontuação"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:111
+msgid "SCO^suicides"
+msgstr "suicídios"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:112
+msgid "SCO^takes"
+msgstr "tomadas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:113
+msgid "SCO^ticks"
+msgstr "ticks"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:295
+msgid ""
+"You can modify the scoreboard using the ^2scoreboard_columns_set command.\n"
+msgstr ""
+"Você pode modificar o placar usando o comando ^2scoreboard_columns_set.\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:296
+msgid "^3|---------------------------------------------------------------|\n"
+msgstr "^3|---------------------------------------------------------------|\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:297
+msgid "Usage:\n"
+msgstr "Uso:\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:298
+msgid "^2scoreboard_columns_set default\n"
+msgstr "^2scoreboard_columns_set padrão\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:299
+msgid "^2scoreboard_columns_set ^7field1 field2 ...\n"
+msgstr "^2scoreboard_columns_set ^7campo1 campo2...\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:300
+msgid "The following field names are recognized (case insensitive):\n"
+msgstr ""
+"Os seguintes nomes de campos são reconhecidos (maiúsculas/minúsculas não são "
+"distintas):\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:301
+msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
+msgstr "Você pode usar um ^3|^7 para iniciar os campos alinhados à direita.\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:304
+msgid "^3name^7 or ^3nick^7             Name of a player\n"
+msgstr "^3nome^7 ou ^3apelido^7 Nome de um jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:305
+msgid "^3ping^7                     Ping time\n"
+msgstr "^3ping^7 Tempo de ping\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:306
+msgid "^3pl^7                       Packet loss\n"
+msgstr "^3pp^7 Perda de pacotes\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:307
+msgid "^3elo^7                      Player ELO\n"
+msgstr "^3elo^7 ELO do jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:308
+msgid "^3kills^7                    Number of kills\n"
+msgstr "^3vítimas^7 Número de aniquilações\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:309
+msgid "^3deaths^7                   Number of deaths\n"
+msgstr "^3mortes^7 Número de mortes\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:310
+msgid "^3suicides^7                 Number of suicides\n"
+msgstr "^3suicídios^7 Número de suicídios\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:311
+msgid "^3frags^7                    kills - suicides\n"
+msgstr "^3execuções^7 vítimas - suicídios\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:312
+msgid "^3kd^7                       The kill-death ratio\n"
+msgstr "^3vm^7 A taxa de vítimas/mortes\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:313
+msgid "^3dmg^7                      The total damage done\n"
+msgstr "^3dano^7 O dano total causado\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:314
+msgid "^3dmgtaken^7                 The total damage taken\n"
+msgstr "^3dano recebido^7 O dano total recebido\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:315
+msgid "^3sum^7                      frags - deaths\n"
+msgstr "^3soma^7 execuções - mortes\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:316
+msgid ""
+"^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was "
+"captured\n"
+msgstr ""
+"^3capturas^7 Quão frequente uma bandeira (CTF) ou uma chave (Caça a Chaves) "
+"foi capturada\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:317
+msgid ""
+"^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a "
+"ball (Keepaway) was picked up\n"
+msgstr ""
+"^3coletas^7. Quão frequente uma bandeira (CTF), uma chave (Caça a Chaves) ou "
+"uma bola (Keepaway) foi coletada\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:318
+msgid "^3captime^7                  Time of fastest cap (CTF)\n"
+msgstr "^3tempodecaptura^7 Tempo da captura mais rápida (CTF)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:319
+msgid "^3fckills^7                  Number of flag carrier kills\n"
+msgstr ""
+"^3pbndvítimas^7 Número de portadores de bandeiras mortos pelo jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:320
+msgid "^3returns^7                  Number of flag returns\n"
+msgstr "^3retornos^7 Número de bandeiras retomadas\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:321
+msgid "^3drops^7                    Number of flag drops\n"
+msgstr "^3quedas^7 Número de bandeiras que foram soltas\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:322
+msgid "^3lives^7                    Number of lives (LMS)\n"
+msgstr "^3vidas^7 Número de vidas (LMS)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:323
+msgid "^3rank^7                     Player rank\n"
+msgstr "^3posição^7 Classificação do jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:324
+msgid "^3pushes^7                   Number of players pushed into void\n"
+msgstr "^3empurrões^7 Número de jogadores empurrados para fora do mapa\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:325
+msgid ""
+"^3destroyed^7                Number of keys destroyed by pushing them into "
+"void\n"
+msgstr ""
+"^3destruídas^7 Número de chaves destruídas ao empurrá-las para fora do mapa\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:326
+msgid "^3kckills^7                  Number of keys carrier kills\n"
+msgstr "^3pcvítimas^7 Número de portadores de chaves mortos pelo jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:327
+msgid "^3losses^7                   Number of times a key was lost\n"
+msgstr "^3perdas^7 Número de vezes em que uma chave foi perdida\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:328
+msgid "^3laps^7                     Number of laps finished (race/cts)\n"
+msgstr "^3voltas^7 Número de voltas concluídas (corrida/cts)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:329
+msgid "^3time^7                     Total time raced (race/cts)\n"
+msgstr "^3tempo^7 Tempo total de corrida (corrida/cts)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:330
+msgid "^3fastest^7                  Time of fastest lap (race/cts)\n"
+msgstr "^3mais rápida^7 Tempo da volta mais rápida (corrida/cts)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:331
+msgid "^3ticks^7                    Number of ticks (DOM)\n"
+msgstr "^3ticks^7 Número de ticks (DOM)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:332
+msgid "^3takes^7                    Number of domination points taken (DOM)\n"
+msgstr "^3tomados^7 Número de pontos de dominação tomados (DOM)\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:333
+msgid "^3bckills^7                  Number of ball carrier kills\n"
+msgstr "^3pblvítimas^7 Número de portadores de bolas mortos pelo jogador\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:334
+msgid ""
+"^3bctime^7                   Total amount of time holding the ball in "
+"Keepaway\n"
+msgstr "^3pbltempo^7 Tempo total segurando a bola em Keepaway\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:335
+msgid "^3score^7                    Total score\n"
+msgstr "^3pontuação^7 Pontuação total\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:338
+msgid ""
+"Before a field you can put a + or - sign, then a comma separated list\n"
+"of game types, then a slash, to make the field show up only in these\n"
+"or in all but these game types. You can also specify 'all' as a\n"
+"field to show all fields available for the current game mode.\n"
+"\n"
+msgstr ""
+"Antes dos campos de digitação, você pode inserir um sinal de + ou -, e usar "
+"uma lista de modos de jogo separada por vírgulas.\n"
+"Insira barras para fazer com que os campos sejam mostrados somente nesses "
+"modos de jogo ou em todos os modos exceto os especificados.\n"
+"Você também pode especificar a palavra 'all' como um campo para mostrar "
+"todos os campos disponíveis para o modo de jogo atual.\n"
+"\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:343
+msgid ""
+"The special game type names 'teams' and 'noteams' can be used to\n"
+"include/exclude ALL teams/noteams game modes.\n"
+"\n"
+msgstr ""
+"Os nomes especiais de modos de jogo 'teams' e 'noteams' podem ser usados\n"
+"para incluir/excluir TODOS os modos de jogo de equipe/sem equipe\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:346
+msgid "Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"
+msgstr ""
+"Exemplo: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:347
+msgid ""
+"will display name, ping and pl aligned to the left, and the fields\n"
+"right of the vertical bar aligned to the right.\n"
+msgstr ""
+"irá exibir nome, ping e pp alinhados à esquerda e os campos\n"
+"à direita da barra vertical alinhados à direita.\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:349
+msgid ""
+"'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+"other gamemodes except DM.\n"
+msgstr ""
+"'field3' só será exibido em CTF e 'field4' será exibido em todos\n"
+"os outros modos de jogo, exceto DM.\n"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:611
+#: qcsrc/client/hud/panel/scoreboard.qc:618
+#: qcsrc/client/hud/panel/scoreboard.qc:670
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:86
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:87
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:203
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:208
+msgid "N/A"
+msgstr "N/A"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1156
+#, c-format
+msgid "Accuracy stats (average %d%%)"
+msgstr "Estatísticas de precisão (média %d%%)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1295
+msgid "Map stats:"
+msgstr "Estatísticas do mapa:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1325
+msgid "Monsters killed:"
+msgstr "Monstros mortos:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1332
+msgid "Secrets found:"
+msgstr "Segredos encontrados:"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1354
+msgid "Capture time rankings"
+msgstr "Classificações de tempo de capturas"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1354
+msgid "Rankings"
+msgstr "Classificações"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1519
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
+msgid "Scoreboard"
+msgstr "Placar"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1584
+#, c-format
+msgid "Speed award: %d%s ^7(%s^7)"
+msgstr "Prêmio de velocidade: %d%s ^7(%s^7)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1588
+#, c-format
+msgid "All-time fastest: %d%s ^7(%s^7)"
+msgstr "O mais rápido de todos: %d%s ^7(%s^7)"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1604
+#, c-format
+msgid "Spectators"
+msgstr "Espectadores"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1619
+#, c-format
+msgid "playing ^3%s^7 on ^2%s^7"
+msgstr "jogando ^3%s^7 em ^2%s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1626
+#: qcsrc/client/hud/panel/scoreboard.qc:1631
+#, c-format
+msgid " for up to ^1%1.0f minutes^7"
+msgstr " por até ^1%1.0f minutos^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1635
+#: qcsrc/client/hud/panel/scoreboard.qc:1654
+msgid " or"
+msgstr " ou"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1638
+#: qcsrc/client/hud/panel/scoreboard.qc:1645
+#, c-format
+msgid " until ^3%s %s^7"
+msgstr " até ^3%s %s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1639
+#: qcsrc/client/hud/panel/scoreboard.qc:1646
+#: qcsrc/client/hud/panel/scoreboard.qc:1658
+#: qcsrc/client/hud/panel/scoreboard.qc:1665
+msgid "SCO^points"
+msgstr "pontos"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1640
+#: qcsrc/client/hud/panel/scoreboard.qc:1647
+#: qcsrc/client/hud/panel/scoreboard.qc:1659
+#: qcsrc/client/hud/panel/scoreboard.qc:1666
+msgid "SCO^is beaten"
+msgstr "foi espancado"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1657
+#: qcsrc/client/hud/panel/scoreboard.qc:1664
+#, c-format
+msgid " until a lead of ^3%s %s^7"
+msgstr " até uma vantagem de ^3%s %s^7"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1688
+#, c-format
+msgid "^1Respawning in ^3%s^1..."
+msgstr "^1Ressurgindo em ^3%s^1..."
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1698
+#, c-format
+msgid "You are dead, wait ^3%s^7 before respawning"
+msgstr "Você morreu. Espere ^3%s^7 antes de ressurgir"
+
+#: qcsrc/client/hud/panel/scoreboard.qc:1707
+#, c-format
+msgid "You are dead, press ^2%s^7 to respawn"
+msgstr "Você morreu. Aperte ^2%s^7 para ressurgir"
+
+#: qcsrc/client/hud/panel/vote.qc:24
+msgid "^1You must answer before entering hud configure mode\n"
+msgstr ""
+"^1Você tem que responder antes de entrar no modo de configuração do HUD\n"
+
+#: qcsrc/client/hud/panel/vote.qc:29
+msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
+msgstr "^2Nome ^7em vez de \"^1Jogador anônimo^7\" nas estatísticas"
+
+#: qcsrc/client/hud/panel/vote.qc:115
+msgid "A vote has been called for:"
+msgstr "Uma votação foi iniciada para:"
+
+#: qcsrc/client/hud/panel/vote.qc:117
+msgid "Allow servers to store and display your name?"
+msgstr "Permitir que servidores armazenem e mostrem o seu nome?"
+
+#: qcsrc/client/hud/panel/vote.qc:121
+msgid "^1Configure the HUD"
+msgstr "^1Configurar o HUD"
+
+#: qcsrc/client/hud/panel/vote.qc:125 qcsrc/menu/xonotic/dialog_firstrun.qc:82
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:18
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:18
+#: qcsrc/menu/xonotic/dialog_quit.qc:14
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:26
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:16
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:15
+msgid "Yes"
+msgstr "Sim"
+
+#: qcsrc/client/hud/panel/vote.qc:127 qcsrc/menu/xonotic/dialog_firstrun.qc:83
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:21
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:21
+#: qcsrc/menu/xonotic/dialog_quit.qc:16
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:29
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:17
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:17
+msgid "No"
+msgstr "Não"
+
+#: qcsrc/client/hud/panel/weapons.qc:530
+msgid "Out of ammo"
+msgstr "Sem munição"
+
+#: qcsrc/client/hud/panel/weapons.qc:534
+msgid "Don't have"
+msgstr "Não tem"
+
+#: qcsrc/client/hud/panel/weapons.qc:538
+msgid "Unavailable"
+msgstr "Indisponível"
+
+#: qcsrc/client/main.qc:1014
+msgid " qu/s"
+msgstr "qu/s"
+
+#: qcsrc/client/main.qc:1016
+msgid " m/s"
+msgstr "m/s"
+
+#: qcsrc/client/main.qc:1018
+msgid " km/h"
+msgstr "km/h"
+
+#: qcsrc/client/main.qc:1020
+msgid " mph"
+msgstr "mph"
+
+#: qcsrc/client/main.qc:1022
+msgid " knots"
+msgstr "nós"
+
+#: qcsrc/client/main.qc:1264
+#, c-format
+msgid "%s (not bound)"
+msgstr "%s (não tem atalho definido)"
+
+#: qcsrc/client/mapvoting.qc:49
+msgid " (1 vote)"
+msgstr "(1 voto)"
+
+#: qcsrc/client/mapvoting.qc:51
+#, c-format
+msgid " (%d votes)"
+msgstr "(%d votos)"
+
+#: qcsrc/client/mapvoting.qc:271
+msgid "Don't care"
+msgstr "Não importa"
+
+#: qcsrc/client/mapvoting.qc:365
+msgid "Decide the gametype"
+msgstr "Decidir o modo de jogo"
+
+#: qcsrc/client/mapvoting.qc:365
+msgid "Vote for a map"
+msgstr "Vote em um mapa"
+
+#: qcsrc/client/mapvoting.qc:382
+#, c-format
+msgid "%d seconds left"
+msgstr "Faltam %d segundos"
+
+#: qcsrc/client/mapvoting.qc:497
+msgid ""
+"mv_mapdownload: ^3You're not supposed to use this command on your own!\n"
+msgstr "mv_mapdownload: ^3Você não pode usar esse comando para si próprio!\n"
+
+#: qcsrc/client/mapvoting.qc:507
+msgid "^1Error:^7 Couldn't find pak index.\n"
+msgstr "^1Erro:^7 Não foi possível encontrar o índice do pak.\n"
+
+#: qcsrc/client/mapvoting.qc:516
+msgid "Requesting preview...\n"
+msgstr "Solicitando previsão...\n"
+
+#: qcsrc/client/miscfunctions.qc:109
+msgid "Trying to remove a team which is not in the teamlist!"
+msgstr ""
+"Você está tentando remover uma equipe que não está na lista de equipes!"
+
+#: qcsrc/client/view.qc:1380
+msgid "Nade timer"
+msgstr "Temporizador de granada"
+
+#: qcsrc/client/view.qc:1385
+msgid "Capture progress"
+msgstr "Progresso de captura"
+
+#: qcsrc/client/view.qc:1390
+msgid "Revival progress"
+msgstr "Progresso de renascimento"
+
+#: qcsrc/common/command/generic.qc:157
+msgid "error creating curl handle\n"
+msgstr "erro ao criar curl handle\n"
+
+#: qcsrc/common/command/generic.qc:403
+msgid "Notification restart command only works with cl_cmd and sv_cmd.\n"
+msgstr ""
+"Comando de reinício de notificação funciona apenas com cl_cmd e sv_cmd.\n"
+
+#: qcsrc/common/gamemodes/gamemode/nexball/weapon.qh:7
+msgid "Ball Stealer"
+msgstr "Ladrão de Bolas"
+
+#: qcsrc/common/items/item/armor.qh:111
+msgid "Big armor"
+msgstr "Armadura grande"
+
+#: qcsrc/common/items/item/armor.qh:147
+msgid "Mega armor"
+msgstr "Mega armadura"
+
+#: qcsrc/common/items/item/health.qh:111
+msgid "Big health"
+msgstr "Saúde grande"
+
+#: qcsrc/common/items/item/health.qh:147
+msgid "Mega health"
+msgstr "Mega saúde"
+
+#: qcsrc/common/items/item/jetpack.qh:35
+msgid "Jet Pack"
+msgstr "Mochila a Jato"
+
+#: qcsrc/common/items/item/jetpack.qh:82
+msgid "Fuel regen"
+msgstr "Regeneração de combustível"
+
+#: qcsrc/common/items/item/powerup.qh:44
+msgid "Strength"
+msgstr "Força"
+
+#: qcsrc/common/items/item/powerup.qh:76
+msgid "Shield"
+msgstr "Escudo"
+
+#: qcsrc/common/mapinfo.qc:639
+#, no-c-format
+msgid "@!#%'n Tuba Throwing"
+msgstr "@!#%'n Tuba Throwing"
+
+#: qcsrc/common/mapinfo.qh:99
+msgid "Deathmatch"
+msgstr "Mata-mata"
+
+#: qcsrc/common/mapinfo.qh:99
+msgid "Score as many frags as you can"
+msgstr "Consiga o máximo de execuções que puder"
+
+#: qcsrc/common/mapinfo.qh:111
+msgid "Last Man Standing"
+msgstr "Último Homem de Pé"
+
+#: qcsrc/common/mapinfo.qh:111
+msgid "Survive and kill until the enemies have no lives left"
+msgstr "Sobreviva e mate até que os inimigos não tenham vidas sobrando"
+
+#: qcsrc/common/mapinfo.qh:126
+msgid "Race"
+msgstr "Corrida"
+
+#: qcsrc/common/mapinfo.qh:126
+msgid "Race against other players to the finish line"
+msgstr "Corra contra outros jogadores até a linha de chegada"
+
+#: qcsrc/common/mapinfo.qh:160
+msgid "Race CTS"
+msgstr "Corrida CTS"
+
+#: qcsrc/common/mapinfo.qh:160
+msgid "Race for fastest time."
+msgstr "Corra pelo melhor tempo."
+
+#: qcsrc/common/mapinfo.qh:184
+msgid "Help your team score the most frags against the enemy team"
+msgstr "Ajude sua equipe a conseguir mais execuções do que a equipe inimiga"
+
+#: qcsrc/common/mapinfo.qh:184
+msgid "Team Deathmatch"
+msgstr "Mata-mata por Equipe"
+
+#: qcsrc/common/mapinfo.qh:220
+msgid "Capture the Flag"
+msgstr "Capture a Bandeira"
+
+#: qcsrc/common/mapinfo.qh:220
+msgid ""
+"Find and bring the enemy flag to your base to capture it, defend your base "
+"from the other team"
+msgstr ""
+"Encontre e retorne a bandeira inimiga à sua base para capturá-la e defenda "
+"sua base da equipe oponente"
+
+#: qcsrc/common/mapinfo.qh:249
+msgid "Clan Arena"
+msgstr "Clã Arena"
+
+#: qcsrc/common/mapinfo.qh:249
+msgid "Kill all enemy teammates to win the round"
+msgstr "Mate todos os inimigos para vencer a rodada"
+
+#: qcsrc/common/mapinfo.qh:287
+msgid "Capture and defend all the control points to win"
+msgstr "Capture e defenda todos os pontos de controle para vencer"
+
+#: qcsrc/common/mapinfo.qh:287
+msgid "Domination"
+msgstr "Dominação"
+
+#: qcsrc/common/mapinfo.qh:319
+msgid "Gather all the keys to win the round"
+msgstr "Colete todas as chaves para vencer a rodada"
+
+#: qcsrc/common/mapinfo.qh:319
+msgid "Key Hunt"
+msgstr "Caça a Chaves"
+
+#: qcsrc/common/mapinfo.qh:353
+msgid "Assault"
+msgstr "Assalto"
+
+#: qcsrc/common/mapinfo.qh:353
+msgid ""
+"Destroy obstacles to find and destroy the enemy power core before time runs "
+"out"
+msgstr ""
+"Destrua obstáculos para encontrar e destruir o núcleo de poder inimigo antes "
+"que o tempo acabe"
+
+#: qcsrc/common/mapinfo.qh:371
+msgid "Capture control points to reach and destroy the enemy generator"
+msgstr "Capture pontos de controle para alcançar e destruir o gerador inimigo"
+
+#: qcsrc/common/mapinfo.qh:371
+msgid "Onslaught"
+msgstr "Massacre"
+
+#: qcsrc/common/mapinfo.qh:387
+msgid "Nexball"
+msgstr "Bola Nex"
+
+#: qcsrc/common/mapinfo.qh:387
+msgid "Shoot and kick the ball into the enemies goal, keep your goal clean"
+msgstr "Atire e chute a bola no gol inimigo e mantenha seu gol limpo"
+
+#: qcsrc/common/mapinfo.qh:408
+msgid "Freeze Tag"
+msgstr "Congela"
+
+#: qcsrc/common/mapinfo.qh:408
+msgid ""
+"Kill enemies to freeze them, stand next to frozen teammates to revive them; "
+"freeze all enemies to win"
+msgstr ""
+"Mate inimigos para congelá-los. Fique perto de colegas para descongelá-los; "
+"congele todos os inimigos para vencer"
+
+#: qcsrc/common/mapinfo.qh:446
+msgid "Hold the ball to get points for kills"
+msgstr "Segure a bola para ganhar pontos por cada jogador aniquilado"
+
+#: qcsrc/common/mapinfo.qh:446
+msgid "Keepaway"
+msgstr "Keepaway"
+
+#: qcsrc/common/mapinfo.qh:461
+msgid "Invasion"
+msgstr "Invasão"
+
+#: qcsrc/common/mapinfo.qh:461
+msgid "Survive against waves of monsters"
+msgstr "Sobreviva contra ondas de monstros"
+
+#: qcsrc/common/minigames/cl_minigames.qc:383
+msgid "It's your turn"
+msgstr "É a sua vez"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:331
+#: qcsrc/menu/xonotic/dialog_quit.qh:6
+msgid "Quit"
+msgstr "Sair"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:336
+msgid "Invite"
+msgstr "Convidar"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:378
+msgid "Current Game"
+msgstr "Jogo Atual"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:403
+msgid "Exit Menu"
+msgstr "Sair do Menu"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:415
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:16
+msgid "Create"
+msgstr "Criar"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:418
+msgid "Join"
+msgstr "Entrar"
+
+#: qcsrc/common/minigames/cl_minigames_hud.qc:489
+msgid "Minigames"
+msgstr "Minijogos"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1168
+msgid "Better luck next time!"
+msgstr "Mais sorte da próxima vez!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1172
+msgid "Tubular! Press \"Next Level\" to continue!"
+msgstr "Tubular! Clique em \"Próximo Mapa\" para continuar!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1174
+msgid "Wicked! Press \"Next Level\" to continue!"
+msgstr "Enfeitiçado! Clique em \"Próximo Mapa\" para continuar!"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1177
+msgid "Press the space bar to change your currently selected tile"
+msgstr ""
+"Aperte a barra de espaço para alterar a sua imagem de equipe atualmente "
+"selecionada"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1180
+msgid "Push the boulders onto the targets"
+msgstr "Empurre os pedregulhos em direção aos alvos"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1404
+msgid "Next Level"
+msgstr "Próximo Mapa"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1405
+msgid "Restart"
+msgstr "Reiniciar"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1406
+msgid "Editor"
+msgstr "Editor"
+
+#: qcsrc/common/minigames/minigame/bd.qc:1407
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:37
+msgid "Save"
+msgstr "Salvar"
+
+#: qcsrc/common/minigames/minigame/c4.qc:373
+#: qcsrc/common/minigames/minigame/pp.qc:438
+#: qcsrc/common/minigames/minigame/ttt.qc:319
+msgid "Draw"
+msgstr "Empate"
+
+#: qcsrc/common/minigames/minigame/c4.qc:378
+#: qcsrc/common/minigames/minigame/nmm.qc:601
+msgid "You lost the game!"
+msgstr "Você perdeu o jogo!"
+
+#: qcsrc/common/minigames/minigame/c4.qc:379
+#: qcsrc/common/minigames/minigame/nmm.qc:602
+msgid "You win!"
+msgstr "Você venceu!"
+
+#: qcsrc/common/minigames/minigame/c4.qc:383
+#: qcsrc/common/minigames/minigame/nmm.qc:606
+#: qcsrc/common/minigames/minigame/pp.qc:455
+#: qcsrc/common/minigames/minigame/ttt.qc:336
+msgid "Wait for your opponent to make their move"
+msgstr "Espere o seu oponente terminar a vez dele"
+
+#: qcsrc/common/minigames/minigame/c4.qc:386
+#: qcsrc/common/minigames/minigame/nmm.qc:608
+#: qcsrc/common/minigames/minigame/pp.qc:458
+#: qcsrc/common/minigames/minigame/ttt.qc:339
+msgid "Click on the game board to place your piece"
+msgstr "Clique no tabuleiro de jogo para posicionar sua peça"
+
+#: qcsrc/common/minigames/minigame/nmm.qc:610
+msgid ""
+"You can select one of your pieces to move it in one of the surrounding places"
+msgstr ""
+"Você pode selecionar uma de suas peças para movê-la para um dos lugares ao "
+"redor"
+
+#: qcsrc/common/minigames/minigame/nmm.qc:612
+msgid "You can select one of your pieces to move it anywhere on the board"
+msgstr ""
+"Você pode selecionar uma de suas peças para movê-la para qualquer lugar no "
+"tabuleiro"
+
+#: qcsrc/common/minigames/minigame/nmm.qc:614
+msgid "You can take one of the opponent's pieces"
+msgstr "Você pode tomar uma das peças do seu oponente"
+
+#: qcsrc/common/minigames/minigame/pong.qc:570
+#: qcsrc/common/minigames/minigame/ttt.qc:299
+msgid "AI"
+msgstr "IA"
+
+#: qcsrc/common/minigames/minigame/pong.qc:587
+msgid "Press ^1Start Match^7 to start the match with the current players"
+msgstr ""
+"Aperte ^1Iniciar Partida^7 para iniciar a partida com os jogadores atuais"
+
+#: qcsrc/common/minigames/minigame/pong.qc:651
+msgid "Start Match"
+msgstr "Iniciar Partida"
+
+#: qcsrc/common/minigames/minigame/pong.qc:652
+msgid "Add AI player"
+msgstr "Adicionar bot"
+
+#: qcsrc/common/minigames/minigame/pong.qc:653
+msgid "Remove AI player"
+msgstr "Remover bot"
+
+#: qcsrc/common/minigames/minigame/pp.qc:443
+#: qcsrc/common/minigames/minigame/ttt.qc:324
+msgid ""
+"You lost the game!\n"
+"Select \"^1Next Match^7\" on the menu for a rematch!"
+msgstr ""
+"Você perdeu o jogo!\n"
+"Selecione \"^1Próxima Partida^7\" no menu para uma revanche!"
+
+#: qcsrc/common/minigames/minigame/pp.qc:444
+#: qcsrc/common/minigames/minigame/ttt.qc:325
+msgid ""
+"You win!\n"
+"Select \"^1Next Match^7\" on the menu to start a new match!"
+msgstr ""
+"Você venceu!\n"
+"Selecione \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
+
+#: qcsrc/common/minigames/minigame/pp.qc:450
+#: qcsrc/common/minigames/minigame/ttt.qc:331
+msgid "Select \"^1Next Match^7\" on the menu to start a new match!"
+msgstr ""
+"Selecione \"^1Próxima Partida^7\" no menu para iniciar uma nova partida!"
+
+#: qcsrc/common/minigames/minigame/pp.qc:451
+#: qcsrc/common/minigames/minigame/ttt.qc:332
+msgid "Wait for your opponent to confirm the rematch"
+msgstr "Espere o seu oponente confirmar a revanche"
+
+#: qcsrc/common/minigames/minigame/pp.qc:582
+#: qcsrc/common/minigames/minigame/ttt.qc:665
+msgid "Next Match"
+msgstr "Próxima Partida"
+
+#: qcsrc/common/minigames/minigame/ps.qc:478
+#, c-format
+msgid "Pieces left: %s"
+msgstr "Pedaços restantes: %s"
+
+#: qcsrc/common/minigames/minigame/ps.qc:488
+msgid "No more valid moves"
+msgstr "Não há mais movimentos válidos"
+
+#: qcsrc/common/minigames/minigame/ps.qc:491
+msgid "Well done, you win!"
+msgstr "Bom trabalho, você venceu!"
+
+#: qcsrc/common/minigames/minigame/ps.qc:494
+msgid "Jump a piece over another to capture it"
+msgstr "Faça uma peça saltar sobre outra para capturá-la"
+
+#: qcsrc/common/minigames/minigame/ttt.qc:666
+msgid "Single Player"
+msgstr "Um Jogador"
+
+#: qcsrc/common/monsters/monster/mage.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:18
+msgid "Mage"
+msgstr "Mago"
+
+#: qcsrc/common/monsters/monster/mage.qh:29
+msgid "Mage spike"
+msgstr "Prego de mago"
+
+#: qcsrc/common/monsters/monster/shambler.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:17
+msgid "Shambler"
+msgstr "Shambler"
+
+#: qcsrc/common/monsters/monster/spider.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:16
+msgid "Spider"
+msgstr "Aranha"
+
+#: qcsrc/common/monsters/monster/spider.qh:28
+msgid "Spider attack"
+msgstr "Ataque da Aranha"
+
+#: qcsrc/common/monsters/monster/wyvern.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:19
+msgid "Wyvern"
+msgstr "Wyvern"
+
+#: qcsrc/common/monsters/monster/wyvern.qh:28
+msgid "Wyvern attack"
+msgstr "Ataque do Wyvern"
+
+#: qcsrc/common/monsters/monster/zombie.qh:17
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:15
+msgid "Zombie"
+msgstr "Zumbi"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:15
+msgid "Ammo"
+msgstr "Munição"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:24
+msgid "Resistance"
+msgstr "Resistência"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:33
+#: qcsrc/common/mutators/mutator/instagib/items.qh:94
+msgid "Speed"
+msgstr "Velocidade"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:43
+msgid "Medic"
+msgstr "Médico"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:54
+msgid "Bash"
+msgstr "Pancada"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:62
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:85
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:177
+msgid "Vampire"
+msgstr "Vampiro"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:70
+msgid "Disability"
+msgstr "Incapacidade"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:78
+msgid "Vengeance"
+msgstr "Vingança"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:86
+msgid "Jump"
+msgstr "Saltar"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:95
+msgid "Invisible"
+msgstr "Invisível"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:104
+msgid "Inferno"
+msgstr "Inferno"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:112
+msgid "Swapper"
+msgstr "Trocador"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:120
+msgid "Magnet"
+msgstr "Ímã"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:128
+msgid "Luck"
+msgstr "Sorte"
+
+#: qcsrc/common/mutators/mutator/buffs/all.inc:136
+msgid "Flight"
+msgstr "Voo"
+
+#: qcsrc/common/mutators/mutator/buffs/buffs.qh:7
+msgid "Buff"
+msgstr "Bônus"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
+msgid "Damage text"
+msgstr "Texto de dano"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:18
+msgid "Draw damage numbers"
+msgstr "Exibir números de dano"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:20
+msgid "Font size minimum:"
+msgstr "Tamanho da fonte mínimo:"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:25
+msgid "Font size maximum:"
+msgstr "Tamanho da fonte máximo:"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:30
+msgid "Accumulate range:"
+msgstr "Alcance de acúmulo:"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:35
+msgid "Lifetime:"
+msgstr "Tempo de vida:"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:40
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:50
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:55
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:102
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:60
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:109
+#: qcsrc/menu/xonotic/util.qc:775
+msgid "Color:"
+msgstr "Cor:"
+
+#: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:47
+msgid "Draw damage numbers for friendly fire"
+msgstr "Exibir números de dano para fogo amigo"
+
+#: qcsrc/common/mutators/mutator/instagib/items.qh:56
+msgid "Extra life"
+msgstr "Vida extra"
+
+#: qcsrc/common/mutators/mutator/instagib/items.qh:75
+msgid "Invisibility"
+msgstr "Invisibilidade"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:18
+msgid "Napalm grenade"
+msgstr "Granada de napalm"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:26
+msgid "Ice grenade"
+msgstr "Granada de gelo"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:34
+msgid "Translocate grenade"
+msgstr "Granada de deslocamento"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:42
+msgid "Spawn grenade"
+msgstr "Granada de fragmentação"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:50
+msgid "Heal grenade"
+msgstr "Granada de cura"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:58
+msgid "Monster grenade"
+msgstr "Granada monstro"
+
+#: qcsrc/common/mutators/mutator/nades/nades.inc:66
+msgid "Entrap grenade"
+msgstr "Granada de armadilha"
+
+#: qcsrc/common/mutators/mutator/nades/nades.qh:32
+msgid "Grenade"
+msgstr "Granada"
+
+#: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
+msgid "Heavy Machine Gun"
+msgstr "Metralhadora Pesada"
+
+#: qcsrc/common/mutators/mutator/overkill/rpc.qh:17
+msgid "Rocket Propelled Chainsaw"
+msgstr "Rocket Propelled Chainsaw"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:3
+msgid "Waypoint"
+msgstr "Ponto de passagem"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:4
+msgid "Help me!"
+msgstr "Preciso de ajuda!"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:5
+msgid "Here"
+msgstr "Aqui"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:6
+msgid "DANGER"
+msgstr "PERIGO"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:8
+msgid "Frozen!"
+msgstr "Congelado!"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:10
+msgid "Item"
+msgstr "Item"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:12
+msgid "Checkpoint"
+msgstr "Ponto de checagem"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:13
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
+msgid "Finish"
+msgstr "Final"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:14
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:15
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
+msgid "Start"
+msgstr "Início"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:17
+msgid "Defend"
+msgstr "Defender"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:18
+msgid "Destroy"
+msgstr "Destruir"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:19
+msgid "Push"
+msgstr "Empurrar"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:21
+msgid "Flag carrier"
+msgstr "Portador de bandeiras"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:22
+msgid "Enemy carrier"
+msgstr "Portador inimigo"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:23
+msgid "Dropped flag"
+msgstr "Bandeira largada"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:24
+msgid "White base"
+msgstr "Base branca"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:25
+msgid "Red base"
+msgstr "Base vermelha"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:26
+msgid "Blue base"
+msgstr "Base azul"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:27
+msgid "Yellow base"
+msgstr "Base amarela"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:28
+msgid "Pink base"
+msgstr "Base rosa"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:29
+msgid "Return flag here"
+msgstr "Traga a bandeira para cá"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:31
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:32
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:33
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:34
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:35
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:51
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:52
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:53
+msgid "Control point"
+msgstr "Ponto de controle"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:37
+msgid "Dropped key"
+msgstr "Chave largada"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:38
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:40
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:41
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:42
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:43
+msgid "Key carrier"
+msgstr "Portador de chaves"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:39
+msgid "Run here"
+msgstr "Corra aqui"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:45
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:48
+msgid "Ball"
+msgstr "Bola"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:46
+msgid "Ball carrier"
+msgstr "Portador da bola"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:49
+msgid "Goal"
+msgstr "Gol"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:54
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:55
+msgid "Generator"
+msgstr "Gerador"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:57
+msgid "Weapon"
+msgstr "Arma"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:59
+msgid "Monster"
+msgstr "Monstro"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:61
+msgid "Vehicle"
+msgstr "Veículo"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:62
+msgid "Intruder!"
+msgstr "Intruso!"
+
+#: qcsrc/common/mutators/mutator/waypoints/all.inc:64
+msgid "Tagged"
+msgstr "Marcado"
+
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:651
+#: qcsrc/common/turrets/cl_turrets.qc:120
+msgid "Spam"
+msgstr "Spam"
+
+#: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:655
+#, c-format
+msgid "%s needing help!"
+msgstr "%s precisando de ajuda!"
+
+#: qcsrc/common/net_notice.qc:87
+msgid "^1Server notices:"
+msgstr "^1Avisos do servidor:"
+
+#: qcsrc/common/notifications/all.inc:239
+msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
+msgstr ""
+"^F4NOTA: ^BGMensagens no bate-papo de espectador não serão enviadas aos "
+"jogadores durante a partida"
+
+#: qcsrc/common/notifications/all.inc:241
+#, c-format
+msgid "^BG%s^BG captured the ^TC^TT^BG flag"
+msgstr "^BG%s^BG capturou a bandeira ^TC^TT^BG"
+
+#: qcsrc/common/notifications/all.inc:242
+#, c-format
+msgid ""
+"^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG"
+"%s^BG's previous record of ^F2%s^BG seconds"
+msgstr ""
+"^BG%s^BG capturou a bandeira ^TC^TT^BG em ^F1%s^BG segundos, quebrando o "
+"recorde anterior de ^BG%s^BG de ^F2%s^BG segundos"
+
+#: qcsrc/common/notifications/all.inc:243
+#, c-format
+msgid "^BG%s^BG captured the flag"
+msgstr "^BG%s^BG capturou a bandeira"
+
+#: qcsrc/common/notifications/all.inc:244
+#, c-format
+msgid "^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"
+msgstr "^BG%s^BG capturou a bandeira ^TC^TT^BG em ^F1%s^BG segundos"
+
+#: qcsrc/common/notifications/all.inc:245
+#, c-format
+msgid ""
+"^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break "
+"^BG%s^BG's previous record of ^F1%s^BG seconds"
+msgstr ""
+"^BG%s^BG capturou a bandeira ^TC^TT^BG em ^F2%s^BG segundos, não quebrando o "
+"record anterior de ^BG%s^BG de ^F1%s^BG segundos"
+
+#: qcsrc/common/notifications/all.inc:246
+msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
+msgstr "^BGA bandeira ^TC^TT^BG foi retornada à base pelo seu dono"
+
+#: qcsrc/common/notifications/all.inc:247
+msgid "^BGThe flag was returned by its owner"
+msgstr "^BGA bandeira ^TC^TT^BG foi retornada pelo seu dono"
+
+#: qcsrc/common/notifications/all.inc:248
+msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
+msgstr "^BGA bandeira ^TC^TT^BG foi destruída e retornada à base"
+
+#: qcsrc/common/notifications/all.inc:249
+msgid "^BGThe flag was destroyed and returned to base"
+msgstr "^BGA bandeira foi destruída e retornada à base"
+
+#: qcsrc/common/notifications/all.inc:250
+msgid "^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"
+msgstr "^BGA bandeira ^TC^TT^BG caiu na base e retornou sozinha"
+
+#: qcsrc/common/notifications/all.inc:251
+msgid "^BGThe flag was dropped in the base and returned itself"
+msgstr "^BGA bandeira caiu na base e retornou sozinha"
+
+#: qcsrc/common/notifications/all.inc:252
+msgid ""
+"^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to "
+"base"
+msgstr ""
+"^BGA bandeira ^TC^TT^BG caiu em algum lugar inacessível e retornou à base"
+
+#: qcsrc/common/notifications/all.inc:253
+msgid "^BGThe flag fell somewhere it couldn't be reached and returned to base"
+msgstr "^BGA bandeira caiu em algum lugar inacessível e retornou à base"
+
+#: qcsrc/common/notifications/all.inc:254
+#, c-format
+msgid ""
+"^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned "
+"itself"
+msgstr ""
+"^BGA bandeira ^TC^TT^BG ficou impaciente depois de ^F1%.2f^BG segundos e "
+"retornou sozinha"
+
+#: qcsrc/common/notifications/all.inc:255
+#, c-format
+msgid ""
+"^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"
+msgstr ""
+"^BGA bandeira ficou impaciente depois de ^F1%.2f^BG segundos e retornou "
+"sozinha"
+
+#: qcsrc/common/notifications/all.inc:256
+msgid "^BGThe ^TC^TT^BG flag has returned to the base"
+msgstr "^BGA bandeira ^TC^TT^BG retornou à base"
+
+#: qcsrc/common/notifications/all.inc:257
+msgid "^BGThe flag has returned to the base"
+msgstr "^BGA bandeira retornou à base"
+
+#: qcsrc/common/notifications/all.inc:258
+#, c-format
+msgid "^BG%s^BG lost the ^TC^TT^BG flag"
+msgstr "^BG%s^BG perdeu a bandeira ^TC^TT^BG"
+
+#: qcsrc/common/notifications/all.inc:259
+#, c-format
+msgid "^BG%s^BG lost the flag"
+msgstr "^BG%s^BG perdeu a bandeira"
+
+#: qcsrc/common/notifications/all.inc:260
+#, c-format
+msgid "^BG%s^BG got the ^TC^TT^BG flag"
+msgstr "^BG%s^BG pegou a bandeira ^TC^TT^BG"
+
+#: qcsrc/common/notifications/all.inc:261
+#, c-format
+msgid "^BG%s^BG got the flag"
+msgstr "^BG%s^BG pegou a bandeira"
+
+#: qcsrc/common/notifications/all.inc:262
+#: qcsrc/common/notifications/all.inc:263
+#, c-format
+msgid "^BG%s^BG returned the ^TC^TT^BG flag"
+msgstr "^BG%s^BG retornou a bandeira ^TC^TT^BG"
+
+#: qcsrc/common/notifications/all.inc:265
+#: qcsrc/common/notifications/all.inc:553
+#, c-format
+msgid "^F2Throwing coin... Result: %s^F2!"
+msgstr "^F2Atirando moeda... Resultado: %s^F2!"
+
+#: qcsrc/common/notifications/all.inc:267
+msgid "^BGYou don't have any fuel for the ^F1Jetpack"
+msgstr "^BGVocê está sem combustível para a ^F1Mochila a Jato"
+
+#: qcsrc/common/notifications/all.inc:269
+msgid "^F2You lack a UID, superspec options will not be saved/restored"
+msgstr ""
+"^F2Você não tem um UID, opções de sperspec não serão salvas/restauradas"
+
+#: qcsrc/common/notifications/all.inc:271
+msgid "^F1Round already started, you will join the game in the next round"
+msgstr "^F1A rodada já começou, você entrará no jogo na próxima rodada"
+
+#: qcsrc/common/notifications/all.inc:272
+msgid "^F2You will spectate in the next round"
+msgstr "^F2Você ficará de espectador na próxima rodada"
+
+#: qcsrc/common/notifications/all.inc:274
+#, c-format
+msgid "^BG%s%s^K1 was killed by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
+msgstr "^BG%s%s^K1 foi morto pelo bônus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:274
+#, c-format
+msgid "^BG%s%s^K1 was scored against by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 foi pontuado contra pelo bônus de ^BG%s^K1 de ^BG%s^K1 ^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:275
+#, c-format
+msgid "^BG%s%s^K1 was unfairly eliminated by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi morto injustamente por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:276
+#, c-format
+msgid "^BG%s%s^K1 was drowned by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi afogado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:277
+#, c-format
+msgid "^BG%s%s^K1 was grounded by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi castigado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:278
+#, c-format
+msgid "^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 se sentiu um pouco quente por causa do fogo de ^BG%s^K1^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:278
+#, c-format
+msgid "^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi cruelmente queimado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:279
+#, c-format
+msgid "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi cozinhado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:280
+#, c-format
+msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi empurrado em frente de um monstro por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:281
+#, c-format
+msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Nade%s%s"
+msgstr "^BG%s%s^K1 foi explodido pela Granada de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:282
+#, c-format
+msgid "^BG%s%s^K1 got too close to a napalm explosion%s%s"
+msgstr "^BG%s%s^K1 se aproximou demais de uma explosão de napalm%s%s"
+
+#: qcsrc/common/notifications/all.inc:282
+#, c-format
+msgid "^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"
+msgstr ""
+"^BG%s%s^K1 foi queimado até a morte pela Granada de Napalm de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:283
+#, c-format
+msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"
+msgstr "^BG%s%s^K1 foi explodido pela Granada de Gelo de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:284
+#, c-format
+msgid "^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"
+msgstr ""
+"^BG%s%s^K1 foi congelado até a morte pela Granada de Gelo de  ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:285
+#, c-format
+msgid "^BG%s%s^K1 has not been healed by ^BG%s^K1's Healing Nade%s%s"
+msgstr "^BG%s%s^K1 não foi curado pela Granada de Cura de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:286
+#, c-format
+msgid "^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi lançado para o espaço por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:287
+#, c-format
+msgid "^BG%s%s^K1 was slimed by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi dissolvido por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:288
+#, c-format
+msgid "^BG%s%s^K1 was preserved by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi preservado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:289
+#, c-format
+msgid "^BG%s%s^K1 tried to occupy ^BG%s^K1's teleport destination space%s%s"
+msgstr "^BG%s%s^K1 tentou ocupar o espaço do teletransporte de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:289
+#, c-format
+msgid "^BG%s%s^K1 was telefragged by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 levou um telefrag de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:290
+#, c-format
+msgid "^BG%s%s^K1 died in an accident with ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 morreu em um acidente com ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:291
+#, c-format
+msgid ""
+"^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Bumblebee exploded%s%s"
+msgstr "^BG%s%s^K1 foi pego pela explosão de Bumblebee de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:292
+#, c-format
+msgid "^BG%s%s^K1 saw the pretty lights of ^BG%s^K1's Bumblebee gun%s%s"
+msgstr "^BG%s%s^K1 viu as lindas luzes da arma do Bumblebee de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:293
+#, c-format
+msgid "^BG%s%s^K1 was crushed by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi esmagado por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:294
+#, c-format
+msgid "^BG%s%s^K1 was cluster bombed by ^BG%s^K1's Raptor%s%s"
+msgstr "^BG%s%s^K1 foi bombardeado pelo Raptor de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:295
+#, c-format
+msgid "^BG%s%s^K1 couldn't resist ^BG%s^K1's purple blobs%s%s"
+msgstr "^BG%s%s^K1 não resistiu às bolhas roxas de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:296
+#, c-format
+msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Raptor exploded%s%s"
+msgstr "^BG%s%s^K1 foi pego pela explosão do Raptor de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:297
+#, c-format
+msgid ""
+"^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Spiderbot exploded%s%s"
+msgstr "^BG%s%s^K1 foi pego pela explosão do Spiderbot de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:298
+#, c-format
+msgid "^BG%s%s^K1 got shredded by ^BG%s^K1's Spiderbot%s%s"
+msgstr "^BG%s%s^K1 foi picado pelo Spiderbot de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:299
+#, c-format
+msgid "^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s"
+msgstr "^BG%s%s^K1 foi explodido em pedacinhos pelo Spiderbot de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:300
+#, c-format
+msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"
+msgstr "^BG%s%s^K1 foi pego pela explosão do Racer de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:301
+#, c-format
+msgid "^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"
+msgstr "^BG%s%s^K1 foi aparafusado pelo Racer de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:302
+#, c-format
+msgid "^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"
+msgstr "^BG%s%s^K1 não conseguiu escapar do Racer de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:303
+#, c-format
+msgid "^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi jogado em mundo de dor por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:305
+#, c-format
+msgid "^BG%s^K1 was moved into the %s%s"
+msgstr "^BG%s^K1 foi movido para o %s%s"
+
+#: qcsrc/common/notifications/all.inc:306
+#, c-format
+msgid "^BG%s^K1 became enemies with the Lord of Teamplay%s%s"
+msgstr "^BG%s^K1 tornou-se inimigo do Senhor do Trabalho em Equipe%s%s"
+
+#: qcsrc/common/notifications/all.inc:307
+#, c-format
+msgid "^BG%s^K1 thought they found a nice camping ground%s%s"
+msgstr ""
+"^BG%s^K1 acharam que tinham encontrado um ótimo lugar para camperar%s%s"
+
+#: qcsrc/common/notifications/all.inc:308
+#, c-format
+msgid "^BG%s^K1 unfairly eliminated themself%s%s"
+msgstr "^BG%s^K1 se eliminou injustamente%s%s"
+
+#: qcsrc/common/notifications/all.inc:310
+#, c-format
+msgid "^BG%s^K1 couldn't catch their breath%s%s"
+msgstr "^BG%s^K1 ficou sem fôlego%s%s"
+
+#: qcsrc/common/notifications/all.inc:310
+#, c-format
+msgid "^BG%s^K1 was in the water for too long%s%s"
+msgstr "^BG%s^K1 ficou na água por muito tempo%s%s"
+
+#: qcsrc/common/notifications/all.inc:311
+#, c-format
+msgid "^BG%s^K1 hit the ground with a bit too much force%s%s"
+msgstr "^BG%s^K1 caiu no chão com muita força%s%s"
+
+#: qcsrc/common/notifications/all.inc:311
+#, c-format
+msgid "^BG%s^K1 hit the ground with a crunch%s%s"
+msgstr "^BG%s^K1 caiu no chão rigorosamente%s%s"
+
+#: qcsrc/common/notifications/all.inc:312
+#, c-format
+msgid "^BG%s^K1 became a bit too crispy%s%s"
+msgstr "^BG%s^K1 ficou um pouco crocante%s%s"
+
+#: qcsrc/common/notifications/all.inc:312
+#, c-format
+msgid "^BG%s^K1 felt a little hot%s%s"
+msgstr "^BG%s^K1 se sentiu um pouco quente%s%s"
+
+#: qcsrc/common/notifications/all.inc:313
+#, c-format
+msgid "^BG%s^K1 died%s%s"
+msgstr "^BG%s^K1 morreu%s%s"
+
+#: qcsrc/common/notifications/all.inc:314
+#, c-format
+msgid "^BG%s^K1 found a hot place%s%s"
+msgstr "^BG%s^K1 achou um lugar quente%s%s"
+
+#: qcsrc/common/notifications/all.inc:314
+#, c-format
+msgid "^BG%s^K1 turned into hot slag%s%s"
+msgstr "^BG%s^K1 tornou-se uma escória quente%s%s"
+
+#: qcsrc/common/notifications/all.inc:315
+#, c-format
+msgid "^BG%s^K1 was exploded by a Mage%s%s"
+msgstr "^BG%s^K1 foi explodido por um Mago%s%s"
+
+#: qcsrc/common/notifications/all.inc:316
+#, c-format
+msgid "^BG%s^K1's innards became outwards by a Shambler%s%s"
+msgstr ""
+"Os órgãos internos de ^BG%s^K1 se tornaram externos por causa de um Shambler "
+"%s%s"
+
+#: qcsrc/common/notifications/all.inc:317
+#, c-format
+msgid "^BG%s^K1 was smashed by a Shambler%s%s"
+msgstr "^BG%s^K1 foi esmagado por um Shambler%s%s"
+
+#: qcsrc/common/notifications/all.inc:318
+#, c-format
+msgid "^BG%s^K1 was zapped to death by a Shambler%s%s"
+msgstr "^BG%s^K1 foi eletrocutado até a morte por um Shambler%s%s"
+
+#: qcsrc/common/notifications/all.inc:319
+#, c-format
+msgid "^BG%s^K1 was bitten by a Spider%s%s"
+msgstr "^BG%s^K1 foi picado por uma Aranha%s%s"
+
+#: qcsrc/common/notifications/all.inc:320
+#, c-format
+msgid "^BG%s^K1 was fireballed by a Wyvern%s%s"
+msgstr "^BG%s^K1 foi morto pela fireball de um Wyvern%s%s"
+
+#: qcsrc/common/notifications/all.inc:321
+#, c-format
+msgid "^BG%s^K1 joins the Zombies%s%s"
+msgstr "^BG%s^K1 se juntou aos Zumbis%s%s"
+
+#: qcsrc/common/notifications/all.inc:322
+#, c-format
+msgid "^BG%s^K1 was given kung fu lessons by a Zombie%s%s"
+msgstr "^BG%s^K1 recebeu lições de kung fu de um Zumbi%s%s"
+
+#: qcsrc/common/notifications/all.inc:323
+#: qcsrc/common/notifications/all.inc:325
+#, c-format
+msgid "^BG%s^K1 mastered the art of self-nading%s%s"
+msgstr "^BG%s^K1 dominou a arte do suicídio com granadas%s%s"
+
+#: qcsrc/common/notifications/all.inc:324
+#, c-format
+msgid ""
+"^BG%s^K1 decided to take a look at the results of their napalm explosion%s%s"
+msgstr ""
+"^BG%s^K1 decidiu dar uma olhada nos resultados de sua explosão de napalm%s%s"
+
+#: qcsrc/common/notifications/all.inc:324
+#, c-format
+msgid "^BG%s^K1 was burned to death by their own Napalm Nade%s%s"
+msgstr ""
+"^BG%s^K1 foi queimado até a morte por sua própria Granada de Napalm%s%s"
+
+#: qcsrc/common/notifications/all.inc:326
+#, c-format
+msgid "^BG%s^K1 felt a little chilly%s%s"
+msgstr "^BG%s^K1 sentiu-se um pouco friolento%s%s"
+
+#: qcsrc/common/notifications/all.inc:326
+#, c-format
+msgid "^BG%s^K1 was frozen to death by their own Ice Nade%s%s"
+msgstr "^BG%s^K1 foi congelado até a morte por sua própria Granada de Gelo%s%s"
+
+#: qcsrc/common/notifications/all.inc:327
+#, c-format
+msgid "^BG%s^K1's Healing Nade didn't quite heal them%s%s"
+msgstr "A Granada de Cura de ^BG%s^K1 não lhe curou corretamente%s%s"
+
+#: qcsrc/common/notifications/all.inc:328
+#, c-format
+msgid "^BG%s^K1 died%s%s. What's the point of living without ammo?"
+msgstr "^BG%s^K1 morreu%s%s. Qual o sentido de viver sem munição?"
+
+#: qcsrc/common/notifications/all.inc:328
+#, c-format
+msgid "^BG%s^K1 ran out of ammo%s%s"
+msgstr "^BG%s^K1 ficou sem munição%s%s"
+
+#: qcsrc/common/notifications/all.inc:329
+#, c-format
+msgid "^BG%s^K1 rotted away%s%s"
+msgstr "^BG%s^K1 derreteu%s%s"
+
+#: qcsrc/common/notifications/all.inc:330
+#, c-format
+msgid "^BG%s^K1 became a shooting star%s%s"
+msgstr "^BG%s^K1 se tornou uma estrela cadente%s%s"
+
+#: qcsrc/common/notifications/all.inc:331
+#, c-format
+msgid "^BG%s^K1 was slimed%s%s"
+msgstr "^BG%s^K1 foi dissolvido%s%s"
+
+#: qcsrc/common/notifications/all.inc:332
+#, c-format
+msgid "^BG%s^K1 couldn't take it anymore%s%s"
+msgstr "^BG%s^K1 não aguentava mais%s%s"
+
+#: qcsrc/common/notifications/all.inc:333
+#, c-format
+msgid "^BG%s^K1 is now preserved for centuries to come%s%s"
+msgstr "^BG%s^K1 agora está preservado para os séculos que virão%s%s"
+
+#: qcsrc/common/notifications/all.inc:334
+#, c-format
+msgid "^BG%s^K1 switched to the %s%s"
+msgstr "^BG%s^K1 trocou para o %s%s"
+
+#: qcsrc/common/notifications/all.inc:335
+#, c-format
+msgid "^BG%s^K1 died in an accident%s%s"
+msgstr "^BG%s^K1 morreu em um acidente%s%s"
+
+#: qcsrc/common/notifications/all.inc:336
+#, c-format
+msgid "^BG%s^K1 ran into a turret%s%s"
+msgstr "^BG%s^K1 deu de cara com uma sentinela%s%s"
+
+#: qcsrc/common/notifications/all.inc:337
+#, c-format
+msgid "^BG%s^K1 was blasted away by an eWheel turret%s%s"
+msgstr "^BG%s^K1 foi explodido por uma sentinela eWheel%s%s"
+
+#: qcsrc/common/notifications/all.inc:338
+#, c-format
+msgid "^BG%s^K1 got caught up in the FLAC turret fire%s%s"
+msgstr "^BG%s^K1 se meteu no meio do tiroteio de uma sentinela FLAC%s%s"
+
+#: qcsrc/common/notifications/all.inc:339
+#, c-format
+msgid "^BG%s^K1 was blasted away by a Hellion turret%s%s"
+msgstr "^BG%s^K1 foi explodido por uma sentinela Hellion%s%s"
+
+#: qcsrc/common/notifications/all.inc:340
+#, c-format
+msgid "^BG%s^K1 could not hide from the Hunter turret%s%s"
+msgstr "^BG%s^K1 não conseguiu se esconder da sentinela Hunter%s%s"
+
+#: qcsrc/common/notifications/all.inc:341
+#, c-format
+msgid "^BG%s^K1 was riddled full of holes by a Machinegun turret%s%s"
+msgstr ""
+"^BG%s^K1 ficou cheio de buracos por causa de uma sentinela de Metralhadora%s"
+"%s"
+
+#: qcsrc/common/notifications/all.inc:342
+#, c-format
+msgid "^BG%s^K1 got turned into smoldering gibs by an MLRS turret%s%s"
+msgstr "^BG%s^K1 foi picado em pedacinhos latentes por uma sentinela MLRS%s%s"
+
+#: qcsrc/common/notifications/all.inc:343
+#, c-format
+msgid "^BG%s^K1 was phased out by a turret%s%s"
+msgstr "^BG%s^K1 foi eliminado por uma sentinela%s%s"
+
+#: qcsrc/common/notifications/all.inc:344
+#, c-format
+msgid "^BG%s^K1 got served some superheated plasma from a turret%s%s"
+msgstr "^BG%s^K1 levou um plasma superaquecido de uma sentinela%s%s"
+
+#: qcsrc/common/notifications/all.inc:345
+#, c-format
+msgid "^BG%s^K1 was electrocuted by a Tesla turret%s%s"
+msgstr "^BG%s^K1 foi eletrocutado por uma sentinela Tesla%s%s"
+
+#: qcsrc/common/notifications/all.inc:346
+#, c-format
+msgid "^BG%s^K1 got served a lead enrichment by a Walker turret%s%s"
+msgstr "^BG%s^K1 foi entupido de chumbo por uma sentinela Walker%s%s"
+
+#: qcsrc/common/notifications/all.inc:347
+#, c-format
+msgid "^BG%s^K1 was impaled by a Walker turret%s%s"
+msgstr "^BG%s^K1 foi empalado por uma sentinela Walker%s%s"
+
+#: qcsrc/common/notifications/all.inc:348
+#, c-format
+msgid "^BG%s^K1 was blasted away by a Walker turret%s%s"
+msgstr "^BG%s^K1 foi explodido por uma sentinela Walker%s%s"
+
+#: qcsrc/common/notifications/all.inc:349
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Bumblebee explosion%s%s"
+msgstr "^BG%s^K1 foi pego pelo raio de uma explosão de Bumblebee%s%s"
+
+#: qcsrc/common/notifications/all.inc:350
+#, c-format
+msgid "^BG%s^K1 was crushed by a vehicle%s%s"
+msgstr "^BG%s^K1 foi esmagado por um veículo%s%s"
+
+#: qcsrc/common/notifications/all.inc:351
+#, c-format
+msgid "^BG%s^K1 was caught in a Raptor cluster bomb%s%s"
+msgstr "^BG%s^K1 foi pego por uma bomba de Raptor%s%s"
+
+#: qcsrc/common/notifications/all.inc:352
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Raptor explosion%s%s"
+msgstr "^BG%s^K1 foi pego pela explosão de um Raptor%s%s"
+
+#: qcsrc/common/notifications/all.inc:353
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Spiderbot explosion%s%s"
+msgstr "^BG%s^K1 foi pego pela explosão de um Spiderbot%s%s"
+
+#: qcsrc/common/notifications/all.inc:354
+#, c-format
+msgid "^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s"
+msgstr "^BG%s^K1 foi explodido em pedacinhos por um foguete de Spiderbot%s%s"
+
+#: qcsrc/common/notifications/all.inc:355
+#, c-format
+msgid "^BG%s^K1 got caught in the blast of a Racer explosion%s%s"
+msgstr "^BG%s^K1 foi pego pela explosão de um Racer%s%s"
+
+#: qcsrc/common/notifications/all.inc:356
+#, c-format
+msgid "^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"
+msgstr "^BG%s^K1 não conseguiu escapar do foguete de um Racer%s%s"
+
+#: qcsrc/common/notifications/all.inc:359
+#, c-format
+msgid "^BG%s^K1 was betrayed by ^BG%s^K1%s%s"
+msgstr "^BG%s^K1 foi traído por ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:361
+#, c-format
+msgid "^BG%s^BG%s^BG (%s %s every %s seconds)"
+msgstr "^BG%s^BG%s^BG (%s %s a cada %s segundos)"
+
+#: qcsrc/common/notifications/all.inc:363
+#, c-format
+msgid "^BG%s^K1 was frozen by ^BG%s"
+msgstr "^BG%s^K1 foi congelado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:364
+#, c-format
+msgid "^BG%s^K3 was revived by ^BG%s"
+msgstr "^BG%s^K3 foi ressuscitado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:365
+#, c-format
+msgid "^BG%s^K3 was revived by falling"
+msgstr "^BG%s^K3 foi ressuscitado por cair"
+
+#: qcsrc/common/notifications/all.inc:366
+#, c-format
+msgid "^BG%s^K3 was revived by their Nade explosion"
+msgstr "^BG%s^K3 foi ressuscitado pela explosão da Granada deles"
+
+#: qcsrc/common/notifications/all.inc:367
+#, c-format
+msgid "^BG%s^K3 was automatically revived after %s second(s)"
+msgstr "^BG%s^K3 foi automaticamente ressuscitado depois de %s segundo(s)"
+
+#: qcsrc/common/notifications/all.inc:368
+#, c-format
+msgid "^BG%s^K1 froze themself"
+msgstr "^BG%s^K1 se congelou"
+
+#: qcsrc/common/notifications/all.inc:370
+#: qcsrc/common/notifications/all.inc:684
+msgid "^TC^TT^BG team wins the round"
+msgstr "A equipe ^TC^TT^BG venceu a rodada"
+
+#: qcsrc/common/notifications/all.inc:371
+#: qcsrc/common/notifications/all.inc:685
+#, c-format
+msgid "^BG%s^BG wins the round"
+msgstr "^BG%s^BG venceu a rodada"
+
+#: qcsrc/common/notifications/all.inc:372
+#: qcsrc/common/notifications/all.inc:548
+msgid "^BGRound tied"
+msgstr "^BGRodada empatada"
+
+#: qcsrc/common/notifications/all.inc:373
+#: qcsrc/common/notifications/all.inc:549
+msgid "^BGRound over, there's no winner"
+msgstr "^BGA rodada acabou sem vencedor"
+
+#: qcsrc/common/notifications/all.inc:375
+#, c-format
+msgid "^BGGodmode saved you %s units of damage, cheater!"
+msgstr "^BGModo Deus te protegeu de %s de dano, seu trapaçeiro!"
+
+#: qcsrc/common/notifications/all.inc:377
+#, c-format
+msgid "^BG%s^BG got the %s^BG buff!"
+msgstr "^BG%s^BG pegou o bônus de %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:378
+#, c-format
+msgid "^BG%s^BG lost the %s^BG buff!"
+msgstr "^BG%s^BG perdeu o bônus de %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:379
+#: qcsrc/common/notifications/all.inc:692
+#, c-format
+msgid "^BGYou dropped the %s^BG buff!"
+msgstr "^BGVocê largou o bônus de %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:380
+#: qcsrc/common/notifications/all.inc:693
+#, c-format
+msgid "^BGYou got the %s^BG buff!"
+msgstr "^BGVocê pegou o bônus de %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:382
+#: qcsrc/common/notifications/all.inc:696
+#, c-format
+msgid "^BGYou do not have the ^F1%s"
+msgstr "^BGVocê não tem a ^F1%s"
+
+#: qcsrc/common/notifications/all.inc:383
+#: qcsrc/common/notifications/all.inc:697
+#, c-format
+msgid "^BGYou dropped the ^F1%s^BG%s"
+msgstr "^BGVocê largou a ^F1%s^BG%s"
+
+#: qcsrc/common/notifications/all.inc:384
+#: qcsrc/common/notifications/all.inc:698
+#, c-format
+msgid "^BGYou got the ^F1%s"
+msgstr "^BGVocê pegou a ^F1%s"
+
+#: qcsrc/common/notifications/all.inc:385
+#: qcsrc/common/notifications/all.inc:699
+#, c-format
+msgid "^BGYou don't have enough ammo for the ^F1%s"
+msgstr "^BGVocê não tem munição suficiente para a ^F1%s"
+
+#: qcsrc/common/notifications/all.inc:386
+#: qcsrc/common/notifications/all.inc:700
+#, c-format
+msgid "^F1%s %s^BG is unable to fire, but its ^F1%s^BG can"
+msgstr "(%s) O ^F1modo %s^BG não pode atirar, mas o ^F1%s^BG pode"
+
+#: qcsrc/common/notifications/all.inc:387
+#: qcsrc/common/notifications/all.inc:701
+#, c-format
+msgid "^F1%s^BG is ^F4not available^BG on this map"
+msgstr "^F1%s^BG^F4 não está disponível^BG neste mapa"
+
+#: qcsrc/common/notifications/all.inc:389
+#, c-format
+msgid "^BG%s^BG is connecting..."
+msgstr "^BG%s^BG está conectando..."
+
+#: qcsrc/common/notifications/all.inc:390
+#, c-format
+msgid "^BG%s^F3 connected"
+msgstr "^BG%s^F3 conectou-se"
+
+#: qcsrc/common/notifications/all.inc:391
+#, c-format
+msgid "^BG%s^F3 connected and joined the ^TC^TT team"
+msgstr "^BG%s^F3 conectou-se e se uniu à equipe ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:392
+#, c-format
+msgid "^BG%s^F3 is now playing"
+msgstr "^BG%s^F3 está jogando agora"
+
+#: qcsrc/common/notifications/all.inc:393
+#, c-format
+msgid "^BG%s^F3 is now playing on the ^TC^TT team"
+msgstr "^BG%s^F3 está jogando agora na equipe ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:395
+#: qcsrc/common/notifications/all.inc:706
+#, c-format
+msgid "^BG%s^BG has dropped the ball!"
+msgstr "^BG%s^BG largou a bola!"
+
+#: qcsrc/common/notifications/all.inc:396
+#: qcsrc/common/notifications/all.inc:707
+#, c-format
+msgid "^BG%s^BG has picked up the ball!"
+msgstr "^BG%s^BG pegou a bola!"
+
+#: qcsrc/common/notifications/all.inc:398
+#, c-format
+msgid "^BG%s^BG captured the keys for the ^TC^TT team"
+msgstr "^BG%s^BG capturou as chaves para a equipe ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:399
+#, c-format
+msgid "^BG%s^BG dropped the ^TC^TT Key"
+msgstr "^BG%s^BG largou a Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:400
+#, c-format
+msgid "^BG%s^BG lost the ^TC^TT Key"
+msgstr "^BG%s^BG perdeu a Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:401
+#, c-format
+msgid "^BG%s^BG pushed %s^BG causing the ^TC^TT Key ^BGdestruction"
+msgstr "^BG%s^BG empurrou %s^BG causando a ^BGdestruição da Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:402
+#, c-format
+msgid "^BG%s^BG destroyed the ^TC^TT Key"
+msgstr "^BG%s^BG destruiu a Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:403
+#, c-format
+msgid "^BG%s^BG picked up the ^TC^TT Key"
+msgstr "^BG%s^BG pegou a Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:405
+#, c-format
+msgid "^BG%s^F3 forfeited"
+msgstr "^BG%s^F3 desistiu"
+
+#: qcsrc/common/notifications/all.inc:406
+#, c-format
+msgid "^BG%s^F3 has no more lives left"
+msgstr "^BG%s^F3 não tem mais vidas"
+
+#: qcsrc/common/notifications/all.inc:408
+msgid "^BGMonsters are currently disabled"
+msgstr "^BGMonstros estão atualmente desativados"
+
+#: qcsrc/common/notifications/all.inc:410
+msgid "^BGThe ^TC^TT^BG team held the ball for too long"
+msgstr "^BGA ^BGequipe ^TC^TT segurou a bola por muito tempo"
+
+#: qcsrc/common/notifications/all.inc:412
+#, c-format
+msgid "^BG%s^BG captured %s^BG control point"
+msgstr "^BG%s^BG capturou o ponto de controle %s^BG"
+
+#: qcsrc/common/notifications/all.inc:413
+#, c-format
+msgid "^TC^TT^BG team %s^BG control point has been destroyed by %s"
+msgstr "O ponto de controle %s^BG da equipe ^TC^TT^BG foi destruído por %s"
+
+#: qcsrc/common/notifications/all.inc:414
+msgid "^TC^TT^BG generator has been destroyed"
+msgstr "O gerador ^TC^TT^BG foi destruído"
+
+#: qcsrc/common/notifications/all.inc:415
+msgid "^TC^TT^BG generator spontaneously combusted due to overtime!"
+msgstr ""
+"O gerador da equipe ^TC^TT^BG entrou em combustão espontaneamente devido aos "
+"acréscimos!"
+
+#: qcsrc/common/notifications/all.inc:417
+#, c-format
+msgid "^BG%s^K1 picked up Invisibility"
+msgstr "^BG%s^K1 pegou Invisibilidade"
+
+#: qcsrc/common/notifications/all.inc:418
+#, c-format
+msgid "^BG%s^K1 picked up Shield"
+msgstr "^BG%s^K1 pegou Escudo"
+
+#: qcsrc/common/notifications/all.inc:419
+#, c-format
+msgid "^BG%s^K1 picked up Speed"
+msgstr "^BG%s^K1 pegou Velocidade"
+
+#: qcsrc/common/notifications/all.inc:420
+#, c-format
+msgid "^BG%s^K1 picked up Strength"
+msgstr "^BG%s^K1 pegou Força"
+
+#: qcsrc/common/notifications/all.inc:422
+#, c-format
+msgid "^BG%s^F3 disconnected"
+msgstr "^BG%s^F3 desconectou-se"
+
+#: qcsrc/common/notifications/all.inc:423
+#, c-format
+msgid "^BG%s^F3 was kicked for idling"
+msgstr "^BG%s^F3 foi expulso por inatividade"
+
+#: qcsrc/common/notifications/all.inc:424
+msgid ""
+"^F2You were kicked from the server because you are a spectator and "
+"spectators aren't allowed at the moment."
+msgstr ""
+"^F2Você foi expulso do servidor porque você é um espectador e espectadores "
+"não são permitidos no momento."
+
+#: qcsrc/common/notifications/all.inc:425
+#, c-format
+msgid "^BG%s^F3 is now spectating"
+msgstr "^BG%s^F3 está assistindo agora"
+
+#: qcsrc/common/notifications/all.inc:427
+#, c-format
+msgid "^BG%s^BG has abandoned the race"
+msgstr "^BG%s^BG abandonou a corrida"
+
+#: qcsrc/common/notifications/all.inc:428
+#, c-format
+msgid "^BG%s^BG couldn't break their %s%s^BG place record of %s%s %s"
+msgstr "^BG%s^BG não puderam quebrar o recorde de lugar %s%s^BG de %s%s %s"
+
+#: qcsrc/common/notifications/all.inc:429
+#, c-format
+msgid "^BG%s^BG couldn't break the %s%s^BG place record of %s%s %s"
+msgstr "^BG%s^BG não pode quebrar o recorde de lugar %s%s^BG de %s%s %s"
+
+#: qcsrc/common/notifications/all.inc:430
+#, c-format
+msgid "^BG%s^BG has finished the race"
+msgstr "^BG%s^BG acabou a corrida"
+
+#: qcsrc/common/notifications/all.inc:431
+#, c-format
+msgid "^BG%s^BG broke %s^BG's %s%s^BG place record with %s%s %s"
+msgstr ""
+"^BG%s^BG quebrou o recorde %s%s^BG de %s^BG e substituiu seu recorde com %s"
+"%s %s"
+
+#: qcsrc/common/notifications/all.inc:432
+#, c-format
+msgid "^BG%s^BG improved their %s%s^BG place record with %s%s %s"
+msgstr "^BG%s^BG melhoraram seus %s%s^BG com %s%s %s"
+
+#: qcsrc/common/notifications/all.inc:433
+#, c-format
+msgid ""
+"^BG%s^BG scored a new record with ^F2%s^BG, but unfortunately lacks a UID "
+"and will be lost."
+msgstr ""
+"^BG%s^BG atingiu um novo recorde com ^F2%s^BG, mas infelizmente, faltou uma "
+"identidade de usuário e sua pontuação será perdida."
+
+#: qcsrc/common/notifications/all.inc:434
+#, c-format
+msgid ""
+"^BG%s^BG scored a new record with ^F2%s^BG, but is anonymous and will be "
+"lost."
+msgstr ""
+"^BG%s^BG quebrou um novo recorde com ^F2%s^BG, mas é anônimo e, por isso, "
+"será perdido."
+
+#: qcsrc/common/notifications/all.inc:435
+#, c-format
+msgid "^BG%s^BG set the %s%s^BG place record with %s%s"
+msgstr "^BG%s^BG definiu o recorde do local %s%s^BG com a pontuação %s%s"
+
+#: qcsrc/common/notifications/all.inc:437
+#, c-format
+msgid ""
+"^F4You have been invited by ^BG%s^F4 to join their game of ^F2%s^F4 "
+"(^F1%s^F4)"
+msgstr ""
+"^F4Você foi convidado por ^BG%s^F4 para se juntar a eles na partida de "
+"^F2%s^F4 (^F1%s^F4)"
+
+#: qcsrc/common/notifications/all.inc:439
+msgid "^TC^TT ^BGteam scores!"
+msgstr "A equipe ^TC^TT ^BG pontuou!"
+
+#: qcsrc/common/notifications/all.inc:441
+#, c-format
+msgid ""
+"^F2You have to become a player within the next %s, otherwise you will be "
+"kicked, because spectating isn't allowed at this time!"
+msgstr ""
+"^F2Você precisa se tornar um jogador dentro de %s, caso contrário, você será "
+"expulso, pois espectadores não são permitidos no momento!"
+
+#: qcsrc/common/notifications/all.inc:443
+#, c-format
+msgid "^BG%s^K1 picked up a Superweapon"
+msgstr "^BG%s^K1 pegou uma Superarma"
+
+#: qcsrc/common/notifications/all.inc:445
+msgid "^BGYou cannot change to a larger team"
+msgstr "^BGVocê não pode trocar para uma equipe maior"
+
+#: qcsrc/common/notifications/all.inc:446
+msgid "^BGYou are not allowed to change teams"
+msgstr "^BGVocê não pode trocar de equipe"
+
+#: qcsrc/common/notifications/all.inc:448
+#, c-format
+msgid ""
+"^F4NOTE: ^BGThe server is running ^F1Xonotic %s (beta)^BG, you have "
+"^F2Xonotic %s"
+msgstr ""
+"^F4NOTA: ^BGO servidor está rodando ^F1Xonotic %s (beta)^BG, você tem o "
+"^F2Xonotic %s"
+
+#: qcsrc/common/notifications/all.inc:449
+#, c-format
+msgid ""
+"^F4NOTE: ^BGThe server is running ^F1Xonotic %s^BG, you have ^F2Xonotic %s"
+msgstr ""
+"^F4NOTA: ^BGO servidor está rodando ^F1Xonotic %s^BG, você tem o ^F2Xonotic "
+"%s"
+
+#: qcsrc/common/notifications/all.inc:450
+#, c-format
+msgid ""
+"^F4NOTE: ^F1Xonotic %s^BG is out, and you still have ^F2Xonotic %s^BG - get "
+"the update from ^F3http://www.xonotic.org/^BG!"
+msgstr ""
+"^F4NOTA: ^F1Xonotic %s^BG foi lançado e você ainda está com o ^F2Xonotic "
+"%s^BG - baixe a atualização pelo site ^F3http://www.xonotic.org/^BG!"
+
+#: qcsrc/common/notifications/all.inc:452
+#, c-format
+msgid "^F3SVQC Build information: ^F4%s"
+msgstr "^F3SVQC Informação da versão: ^F4%s"
+
+#: qcsrc/common/notifications/all.inc:454
+#, c-format
+msgid ""
+"^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Accordeon%s%s"
+msgstr ""
+"^BG%s%s^K1 morreu por causa da grande habilidade de ^BG%s^K1 com a @!#%%'n "
+"Accordeon%s%s"
+
+#: qcsrc/common/notifications/all.inc:455
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Accordeon%s%s"
+msgstr "^BG%s^K1 feriu seus próprios ouvidos com a @!#%%'n Accordeon%s%s"
+
+#: qcsrc/common/notifications/all.inc:456
+#, c-format
+msgid "^BG%s%s^K1 was electrocuted by ^BG%s^K1's Arc%s%s"
+msgstr "^BG%s%s^K1 foi eletrocutado pelo Arc de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:457
+#, c-format
+msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Arc bolts%s%s"
+msgstr "^BG%s%s^K1 foi explodido pelos raios do Arc de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:458
+#, c-format
+msgid "^BG%s%s^K1 was shot to death by ^BG%s^K1's Blaster%s%s"
+msgstr "^BG%s%s^K1 foi morto pelo Blaster de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:459
+#, c-format
+msgid "^BG%s^K1 shot themself to hell with their Blaster%s%s"
+msgstr "^BG%s^K1 atirou muito em si mesmo com seu Blaster%s%s"
+
+#: qcsrc/common/notifications/all.inc:460
+#, c-format
+msgid "^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s"
+msgstr "^BG%s%s^K1 sentiu o forte impulso da Crylink de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:461
+#, c-format
+msgid "^BG%s^K1 felt the strong pull of their Crylink%s%s"
+msgstr "^BG%s^K1 sentiu o forte impulso de sua Crylink%s%s"
+
+#: qcsrc/common/notifications/all.inc:462
+#, c-format
+msgid "^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s"
+msgstr "^BG%s%s^K1 comeu o foguete de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:463
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
+msgstr ""
+
+#: qcsrc/common/notifications/all.inc:464
+#, c-format
+msgid "^BG%s^K1 blew themself up with their Devastator%s%s"
+msgstr "^BG%s^K1 se explodiu com sua Devastator%s%s"
+
+#: qcsrc/common/notifications/all.inc:465
+#, c-format
+msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"
+msgstr "^BG%s%s^K1 foi pulverizado por raios de Electro de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:466
+#, c-format
+msgid "^BG%s%s^K1 felt the electrifying air of ^BG%s^K1's Electro combo%s%s"
+msgstr ""
+"^BG%s%s^K1 sentiu o ar eletrocutado do combo de Electro de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:467
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Electro orb%s%s"
+msgstr "^BG%s%s^K1 ficou muito perto da esfera de Electro de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:468
+#, c-format
+msgid "^BG%s^K1 played with Electro bolts%s%s"
+msgstr "^BG%s^K1 brincou com raios de Electro%s%s"
+
+#: qcsrc/common/notifications/all.inc:469
+#, c-format
+msgid "^BG%s^K1 could not remember where they put their Electro orb%s%s"
+msgstr ""
+"^BG%s^K1 não conseguiu se lembrar onde tinha colocado a sua esfera de Electro"
+"%s%s"
+
+#: qcsrc/common/notifications/all.inc:470
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's fireball%s%s"
+msgstr "^BG%s%s^K1 chegou muito perto da fireball de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:471
+#, c-format
+msgid "^BG%s%s^K1 got burnt by ^BG%s^K1's firemine%s%s"
+msgstr "^BG%s%s^K1 foi queimado pela mina de fogo de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:472
+#, c-format
+msgid "^BG%s^K1 should have used a smaller gun%s%s"
+msgstr "^BG%s^K1 deveria ter usado uma arma menor%s%s"
+
+#: qcsrc/common/notifications/all.inc:473
+#, c-format
+msgid "^BG%s^K1 forgot about their firemine%s%s"
+msgstr "^BG%s^K1 se esqueceu da sua mina de fogo%s%s"
+
+#: qcsrc/common/notifications/all.inc:474
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets%s%s"
+msgstr ""
+"^BG%s%s^K1 foi atingido por uma rajada de foguetes do Hagar de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:475
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s"
+msgstr "^BG%s%s^K1 foi atingido pelos foguetes do Hagar de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:476
+#, c-format
+msgid "^BG%s^K1 played with tiny Hagar rockets%s%s"
+msgstr "^BG%s^K1 brincou com minúsculos foguetes de Hagar%s%s"
+
+#: qcsrc/common/notifications/all.inc:477
+#, c-format
+msgid "^BG%s%s^K1 was cut down with ^BG%s^K1's HLAC%s%s"
+msgstr "^BG%s%s^K1 foi rasgado pelo HLAC de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:478
+#, c-format
+msgid "^BG%s^K1 got a little jumpy with their HLAC%s%s"
+msgstr "^BG%s^K1 ficou um pouco agitado com o seu HLAC%s%s"
+
+#: qcsrc/common/notifications/all.inc:479
+#, c-format
+msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Heavy Machine Gun%s%s"
+msgstr "^BG%s%s^K1 foi atingido pela Metralhadora Pesada de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:480
+#, c-format
+msgid "^BG%s%s^K1 was torn to bits by ^BG%s^K1's Heavy Machine Gun%s%s"
+msgstr "^BG%s%s^K1 foi despedaçado pela Metralhadora Pesada de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:481
+#, c-format
+msgid "^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s"
+msgstr "^BG%s%s^K1 foi pego pela bomba de gravidade do Gancho de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:482
+#, c-format
+msgid ""
+"^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s"
+msgstr ""
+"^BG%s%s^K1 morreu por causa da grande habilidade de ^BG%s^K1 com a @!#%%'n "
+"Klein Bottle%s%s"
+
+#: qcsrc/common/notifications/all.inc:483
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s"
+msgstr ""
+"^BG%s^K1 machucaram seus próprios ouvidos com a @!#%%'n Klein Bottle%s%s"
+
+#: qcsrc/common/notifications/all.inc:484
+#, c-format
+msgid "^BG%s%s^K1 was sniped by ^BG%s^K1's Machine Gun%s%s"
+msgstr "^BG%s%s^K1 foi atingido pela Metralhadora de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:485
+#, c-format
+msgid "^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Machine Gun%s%s"
+msgstr ""
+"^BG%s%s^K1 ficou cheio de buracos por causa da Metralhadora de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:486
+#: qcsrc/common/notifications/all.inc:790
+#, c-format
+msgid "^BGYou cannot place more than ^F2%s^BG mines at a time"
+msgstr "^BGVocê não pode pôr mais do que ^F2%s^BG minas por vez"
+
+#: qcsrc/common/notifications/all.inc:487
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's mine%s%s"
+msgstr "^BG%s%s^K1 ficou muito perto da mina de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:488
+#, c-format
+msgid "^BG%s^K1 forgot about their mine%s%s"
+msgstr "^BG%s^K1 se esqueceu de sua mina%s%s"
+
+#: qcsrc/common/notifications/all.inc:489
+#, c-format
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"
+msgstr "^BG%s%s^K1 ficou muito perto da granada de Mortar de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:490
+#, c-format
+msgid "^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"
+msgstr "^BG%s%s^K1 comeu a granada de Mortar de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:491
+#, c-format
+msgid "^BG%s^K1 didn't see their own Mortar grenade%s%s"
+msgstr "^BG%s^K1 não viu a sua própria granada de Mortar%s%s"
+
+#: qcsrc/common/notifications/all.inc:492
+#, c-format
+msgid "^BG%s^K1 blew themself up with their own Mortar%s%s"
+msgstr "^BG%s^K1 se explodiu com o seu próprio Mortar%s%s"
+
+#: qcsrc/common/notifications/all.inc:493
+#, c-format
+msgid "^BG%s%s^K1 was sniped with a Rifle by ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 foi atingido pelo Rifle de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:494
+#, c-format
+msgid "^BG%s%s^K1 died in ^BG%s^K1's Rifle bullet hail%s%s"
+msgstr "^BG%s%s^K1 morreu pela bala do Rifle de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:495
+#, c-format
+msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail%s%s"
+msgstr "^BG%s%s^K1 falhou em se esconder da bala do Rifle de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:496
+#, c-format
+msgid "^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle%s%s"
+msgstr "^BG%s%s^K1 falhou em se esconder do Rifle de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:497
+#, c-format
+msgid "^BG%s%s^K1 was sawn in half by ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
+msgstr "^BG%s%s^K1 foi serrado ao meio pelo RPC de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:498
+#, c-format
+msgid "^BG%s%s^K1 almost dodged ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
+msgstr "^BG%s%s^K1 quase desviou do RPC de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:499
+#, c-format
+msgid "^BG%s^K1 was sawn in half by their own Rocket Propelled Chainsaw%s%s"
+msgstr "^BG%s^K1 foi serrado ao meio pelo seu próprio RPC%s%s"
+
+#: qcsrc/common/notifications/all.inc:500
+#, c-format
+msgid "^BG%s^K1 blew themself up with their Rocket Propelled Chainsaw%s%s"
+msgstr "^BG%s^K1 se explodiu com seu próprio RPC%s%s"
+
+#: qcsrc/common/notifications/all.inc:501
+#, c-format
+msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Seeker rockets%s%s"
+msgstr "^BG%s%s^K1 foi surrado pelos foguetes do Seeker de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:502
+#, c-format
+msgid "^BG%s%s^K1 was tagged by ^BG%s^K1's Seeker%s%s"
+msgstr "^BG%s%s^K1 foi marcado pelo Seeker de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:503
+#, c-format
+msgid "^BG%s^K1 played with tiny Seeker rockets%s%s"
+msgstr "^BG%s^K1 brincou com minúsculos foguetes de Seeker%s%s"
+
+#: qcsrc/common/notifications/all.inc:504
+#, c-format
+msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shockwave%s%s"
+msgstr "^BG%s%s^K1 foi morto pela Shockwave de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:505
+#, c-format
+msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shockwave%s%s"
+msgstr "^BG%s%s^K1 deu uns tapas em ^BG%s^K1 com uma grande Shockwave%s%s"
+
+#: qcsrc/common/notifications/all.inc:506
+#, c-format
+msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s"
+msgstr "^BG%s%s^K1 foi baleado pela Shotgun de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:507
+#, c-format
+msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shotgun%s%s"
+msgstr "^BG%s%s^K1 deu uns tapas em ^BG%s^K1 com uma grande Shotgun%s%s"
+
+#: qcsrc/common/notifications/all.inc:508
+#, c-format
+msgid "^BG%s^K1 is now thinking with portals%s%s"
+msgstr "^BG%s^K1 agora está pensando com portais%s%s"
+
+#: qcsrc/common/notifications/all.inc:509
+#, c-format
+msgid "^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Tuba%s%s"
+msgstr ""
+"^BG%s%s^K1 morreu por causa da grande habilidade de ^BG%s^K1 com a @!#%%'n "
+"Tuba%s%s"
+
+#: qcsrc/common/notifications/all.inc:510
+#, c-format
+msgid "^BG%s^K1 hurt their own ears with the @!#%%'n Tuba%s%s"
+msgstr "^BG%s^K1 feriu seus próprios ouvidos com a @!#%%'n Tuba%s%s"
+
+#: qcsrc/common/notifications/all.inc:511
+#, c-format
+msgid "^BG%s%s^K1 has been sublimated by ^BG%s^K1's Vaporizer%s%s"
+msgstr "^BG%s%s^K1 foi sublimado pela Vaporizer de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:512
+#, c-format
+msgid "^BG%s%s^K1 has been vaporized by ^BG%s^K1's Vortex%s%s"
+msgstr "^BG%s%s^K1 foi vaporizado pela Vortex de ^BG%s^K1%s%s"
+
+#: qcsrc/common/notifications/all.inc:537
+msgid "^F4You are now alone!"
+msgstr "^F4Você está sozinho agora!"
+
+#: qcsrc/common/notifications/all.inc:539
+msgid "^BGYou are attacking!"
+msgstr "^BGVocê está atacando!"
+
+#: qcsrc/common/notifications/all.inc:540
+msgid "^BGYou are defending!"
+msgstr "^BGVocê está defendendo!"
+
+#: qcsrc/common/notifications/all.inc:541
+#, c-format
+msgid "^BGObjective destroyed in ^F4%s^BG!"
+msgstr "^BGObjetivo destruído em ^F4%s^BG!"
+
+#: qcsrc/common/notifications/all.inc:543
+msgid "^F4Begin!"
+msgstr "^F4Começou!"
+
+#: qcsrc/common/notifications/all.inc:544
+msgid "^F4Game starts in ^COUNT"
+msgstr "^F4A partida iniciará em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:545
+msgid "^F4Round starts in ^COUNT"
+msgstr "^F4A rodada iniciará em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:546
+msgid "^F4Round cannot start"
+msgstr "^F4A rodada não pode iniciar"
+
+#: qcsrc/common/notifications/all.inc:551
+msgid "^F2Don't camp!"
+msgstr "^F2Não campere!"
+
+#: qcsrc/common/notifications/all.inc:555
+msgid ""
+"^BGYou are now free.\n"
+"^BGFeel free to ^F2try to capture^BG the flag again\n"
+"^BGif you think you will succeed."
+msgstr ""
+"^BGVocê está livre agora.\n"
+"^BGSinta-se à vontade para ^F2tentar capturar^BG a bandeira de novo\n"
+"^BGse você acha que irá conseguir."
+
+#: qcsrc/common/notifications/all.inc:556
+msgid "^BGThis flag is currently inactive"
+msgstr "^BGEsta bandeira está atualmente inativa"
+
+#: qcsrc/common/notifications/all.inc:557
+msgid ""
+"^BGYou are now ^F1shielded^BG from the flag(s)\n"
+"^BGfor ^F2too many unsuccessful attempts^BG to capture.\n"
+"^BGMake some defensive scores before trying again."
+msgstr ""
+"^BGVocê agora está ^F1impedido^BG de carregar a(s) bandeira(s)\n"
+"^BGapós ^F2várias tentativas de captura sem êxito^BG.\n"
+"^BGFaça alguns pontos defensivos antes de tentar novamente."
+
+#: qcsrc/common/notifications/all.inc:558
+msgid "^BGYou captured the ^TC^TT^BG flag!"
+msgstr "^BGVocê capturou a bandeira ^TC^TT^BG!"
+
+#: qcsrc/common/notifications/all.inc:559
+msgid "^BGYou captured the flag!"
+msgstr "^BGVocê capturou a bandeira!"
+
+#: qcsrc/common/notifications/all.inc:560
+#, c-format
+msgid "^BGToo many flag throws! Throwing disabled for %s."
+msgstr ""
+"^BGNão largue a bandeira várias vezes! Agora você não pode largar por %s."
+
+#: qcsrc/common/notifications/all.inc:561
+#, c-format
+msgid "^BG%s^BG passed the ^TC^TT^BG flag to %s"
+msgstr "^BG%s^BG passou a bandeira ^TC^TT^BG para %s"
+
+#: qcsrc/common/notifications/all.inc:562
+#, c-format
+msgid "^BG%s^BG passed the flag to %s"
+msgstr "^BG%s^BG passou a bandeira para %s"
+
+#: qcsrc/common/notifications/all.inc:563
+#, c-format
+msgid "^BGYou received the ^TC^TT^BG flag from %s"
+msgstr "^BGVocê recebeu a bandeira ^TC^TT^BG de %s"
+
+#: qcsrc/common/notifications/all.inc:564
+#, c-format
+msgid "^BGYou received the flag from %s"
+msgstr "^BGVocê recebeu a bandeira de %s"
+
+#: qcsrc/common/notifications/all.inc:565
+#, c-format
+msgid "^BGPress ^F2%s^BG to receive the flag from %s^BG"
+msgstr "^BGAperte ^F2%s^BG para receber a bandeira de %s^BG"
+
+#: qcsrc/common/notifications/all.inc:566
+#, c-format
+msgid "^BGRequesting %s^BG to pass you the flag"
+msgstr "^BGPedindo à %s^BG para que te passe a bandeira"
+
+#: qcsrc/common/notifications/all.inc:567
+#, c-format
+msgid "^BGYou passed the ^TC^TT^BG flag to %s"
+msgstr "^BGVocê passou a bandeira ^TC^TT^BG para %s"
+
+#: qcsrc/common/notifications/all.inc:568
+#, c-format
+msgid "^BGYou passed the flag to %s"
+msgstr "^BGVocê passou a bandeira para %s"
+
+#: qcsrc/common/notifications/all.inc:569
+msgid "^BGYou got the ^TC^TT^BG flag!"
+msgstr "^BGVocê pegou a bandeira ^TC^TT^BG!"
+
+#: qcsrc/common/notifications/all.inc:570
+msgid "^BGYou got the flag!"
+msgstr "^BGVocê pegou a bandeira!"
+
+#: qcsrc/common/notifications/all.inc:571
+#, c-format
+msgid "^BGYou got your %steam^BG's flag, return it!"
+msgstr "^BGVocê pegou a bandeira da sua %sequipe^BG, retorne-a!"
+
+#: qcsrc/common/notifications/all.inc:572
+#, c-format
+msgid "^BGYou got the %senemy^BG's flag, return it!"
+msgstr "^BGVocê pegou a bandeira da %sequipe inimiga^BG, retorne-a!"
+
+#: qcsrc/common/notifications/all.inc:573
+#, c-format
+msgid "^BGThe %senemy^BG got your flag! Retrieve it!"
+msgstr "^BGO %sinimigo^BG pegou a sua bandeira! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:574
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a sua bandeira! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:575
+#, c-format
+msgid "^BGThe %senemy^BG got the flag! Retrieve it!"
+msgstr "^BGO %sinimigo^BG pegou a bandeira! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:576
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:577
+#, c-format
+msgid "^BGThe %senemy^BG got their flag! Retrieve it!"
+msgstr "^BGO %sinimigo^BG pegou a bandeira deles! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:578
+#, c-format
+msgid "^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira deles! Recupere-a!"
+
+#: qcsrc/common/notifications/all.inc:579
+#, c-format
+msgid "^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"
+msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira ^TC^TT^BG! Proteja-o!"
+
+#: qcsrc/common/notifications/all.inc:580
+#, c-format
+msgid "^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"
+msgstr ""
+"^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira ^TC^TT^BG! Proteja-"
+"o!"
+
+#: qcsrc/common/notifications/all.inc:581
+#, c-format
+msgid "^BGYour %steam mate^BG got the flag! Protect them!"
+msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira! Proteja-o!"
+
+#: qcsrc/common/notifications/all.inc:582
+#, c-format
+msgid "^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"
+msgstr "^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira! Proteja-o!"
+
+#: qcsrc/common/notifications/all.inc:583
+msgid "^BGEnemies can now see you on radar!"
+msgstr "^BGAgora os inimigos podem te ver no radar!"
+
+#: qcsrc/common/notifications/all.inc:584
+msgid "^BGYou returned the ^TC^TT^BG flag!"
+msgstr "^BGVocê retornou a bandeira ^TC^TT^BG!"
+
+#: qcsrc/common/notifications/all.inc:585
+msgid "^BGStalemate! Enemies can now see you on radar!"
+msgstr "^BGCuidado! Agora os inimigos podem te ver no radar!"
+
+#: qcsrc/common/notifications/all.inc:586
+msgid "^BGStalemate! Flag carriers can now be seen by enemies on radar!"
+msgstr ""
+"^BGCuidado! Agora portadores da bandeira podem ser vistos pelos inimigos no "
+"radar!"
+
+#: qcsrc/common/notifications/all.inc:590
+#, c-format
+msgid "^K3%sYou fragged ^BG%s"
+msgstr "^K3%sVocê executou ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:591
+#: qcsrc/common/notifications/all.inc:600
+#: qcsrc/common/notifications/all.inc:609
+#, c-format
+msgid "^K3%sYou scored against ^BG%s"
+msgstr "^K3%sVocê pontuou contra ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:592
+#, c-format
+msgid "^K1%sYou were fragged by ^BG%s"
+msgstr "^K1%sVocê foi executado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:593
+#: qcsrc/common/notifications/all.inc:602
+#: qcsrc/common/notifications/all.inc:611
+#, c-format
+msgid "^K1%sYou were scored against by ^BG%s"
+msgstr "^K1%sVocê foi pontuado contra por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:599
+#, c-format
+msgid "^K3%sYou burned ^BG%s"
+msgstr "^K3%sVocê queimou ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:601
+#, c-format
+msgid "^K1%sYou were burned by ^BG%s"
+msgstr "^K1%sVocê foi queimado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:608
+#, c-format
+msgid "^K3%sYou froze ^BG%s"
+msgstr "^K3%sVocê congelou ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:610
+#, c-format
+msgid "^K1%sYou were frozen by ^BG%s"
+msgstr "^K1%sVocê foi congelado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:617
+#, c-format
+msgid "^K1%sYou typefragged ^BG%s"
+msgstr "^K1%sVocê executou ^BG%s enquanto digitava"
+
+#: qcsrc/common/notifications/all.inc:618
+#, c-format
+msgid "^K1%sYou scored against ^BG%s^K1 while they were typing"
+msgstr "^K1%sVocê pontuou contra ^BG%s^K1 enquanto estavam digitando"
+
+#: qcsrc/common/notifications/all.inc:619
+#, c-format
+msgid "^K1%sYou were typefragged by ^BG%s"
+msgstr "^K1%sVocê foi executado enquanto digitava por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:620
+#, c-format
+msgid "^K1%sYou were scored against by ^BG%s^K1 while typing"
+msgstr "^K1%sVocê foi pontuado contra enquanto digitava por ^BG%s^K1"
+
+#: qcsrc/common/notifications/all.inc:626
+#, c-format
+msgid "^BGPress ^F2%s^BG again to toss the nade!"
+msgstr "^BGAperte ^F2%s^BG de novo para lançar a granada!"
+
+#: qcsrc/common/notifications/all.inc:627
+msgid "^F2You got a ^K1BONUS GRENADE^F2!"
+msgstr "^F2Você pegou uma ^K1GRANADA BÔNUS^F2!"
+
+#: qcsrc/common/notifications/all.inc:629
+#, c-format
+msgid ""
+"^BGYou have been moved into a different team\n"
+"You are now on: %s"
+msgstr ""
+"^BGVocê foi movido para uma equipe diferente\n"
+"Agora você está na equipe: %s"
+
+#: qcsrc/common/notifications/all.inc:630
+msgid "^K1Don't go against your team mates!"
+msgstr "^K1Não vá contra seus colegas de equipe!"
+
+#: qcsrc/common/notifications/all.inc:630
+msgid "^K1Don't shoot your team mates!"
+msgstr "^K1Não atire nos seus colegas de equipe!"
+
+#: qcsrc/common/notifications/all.inc:631
+msgid "^K1Die camper!"
+msgstr "^K1Morra, camper!"
+
+#: qcsrc/common/notifications/all.inc:631
+msgid "^K1Reconsider your tactics, camper!"
+msgstr "^K1Reconsidere suas táticas, camper!"
+
+#: qcsrc/common/notifications/all.inc:632
+msgid "^K1You unfairly eliminated yourself!"
+msgstr "^K1Você se matou injustamente!"
+
+#: qcsrc/common/notifications/all.inc:633
+#, c-format
+msgid "^K1You were %s"
+msgstr "^K1Você foi %s"
+
+#: qcsrc/common/notifications/all.inc:634
+msgid "^K1You couldn't catch your breath!"
+msgstr "^K1Você não recuperou seu fôlego!"
+
+#: qcsrc/common/notifications/all.inc:635
+msgid "^K1You hit the ground with a crunch!"
+msgstr "^K1Você caiu no chão rigorosamente!"
+
+#: qcsrc/common/notifications/all.inc:636
+msgid "^K1You felt a little too hot!"
+msgstr "^K1Você se sentiu um pouco quente!"
+
+#: qcsrc/common/notifications/all.inc:636
+msgid "^K1You got a little bit too crispy!"
+msgstr "^K1Você ficou um pouco crocante demais!"
+
+#: qcsrc/common/notifications/all.inc:637
+msgid "^K1You killed your own dumb self!"
+msgstr "^K1Você se matou, seu burro!"
+
+#: qcsrc/common/notifications/all.inc:637
+msgid "^K1You need to be more careful!"
+msgstr "^K1Você precisa ter mais cuidado!"
+
+#: qcsrc/common/notifications/all.inc:638
+msgid "^K1You couldn't stand the heat!"
+msgstr "^K1Você não suportou o calor!"
+
+#: qcsrc/common/notifications/all.inc:639
+msgid "^K1You need to watch out for monsters!"
+msgstr "^K1Você tem que se cuidar dos monstros!"
+
+#: qcsrc/common/notifications/all.inc:639
+msgid "^K1You were killed by a monster!"
+msgstr "^K1Você foi morto por um monstro!"
+
+#: qcsrc/common/notifications/all.inc:640
+msgid "^K1Tastes like chicken!"
+msgstr "^K1Tem gosto de frango!"
+
+#: qcsrc/common/notifications/all.inc:640
+msgid "^K1You forgot to put the pin back in!"
+msgstr "^K1Você se esqueceu de pôr o pino de volta!"
+
+#: qcsrc/common/notifications/all.inc:641
+msgid "^K1Hanging around a napalm explosion is bad!"
+msgstr "^K1Brincar no meio de uma explosão de napalm é errado!"
+
+#: qcsrc/common/notifications/all.inc:642
+msgid "^K1You felt a little chilly!"
+msgstr "^K1Você sentiu um pouco de frio!"
+
+#: qcsrc/common/notifications/all.inc:642
+msgid "^K1You got a little bit too cold!"
+msgstr "^K1Você ficou um pouco gelado demais!"
+
+#: qcsrc/common/notifications/all.inc:643
+msgid "^K1Your Healing Nade is a bit defective"
+msgstr "^K1Sua Granada de Cura está um pouco defeituosa"
+
+#: qcsrc/common/notifications/all.inc:644
+msgid "^K1You are respawning for running out of ammo..."
+msgstr "^K1Você está ressurgindo por ficar sem munição..."
+
+#: qcsrc/common/notifications/all.inc:644
+msgid "^K1You were killed for running out of ammo..."
+msgstr "^K1Você foi morto por ficar sem munição..."
+
+#: qcsrc/common/notifications/all.inc:645
+msgid "^K1You grew too old without taking your medicine"
+msgstr "^K1Você ficou muito velho sem tomar o seu medicamento"
+
+#: qcsrc/common/notifications/all.inc:645
+msgid "^K1You need to preserve your health"
+msgstr "^K1Você precisa conservar sua saúde"
+
+#: qcsrc/common/notifications/all.inc:646
+msgid "^K1You became a shooting star!"
+msgstr "^K1Você virou uma estrela cadente!"
+
+#: qcsrc/common/notifications/all.inc:647
+msgid "^K1You melted away in slime!"
+msgstr "^K1Você derreteu na lama!"
+
+#: qcsrc/common/notifications/all.inc:648
+msgid "^K1You committed suicide!"
+msgstr "^K1Você cometeu suicídio!"
+
+#: qcsrc/common/notifications/all.inc:648
+msgid "^K1You ended it all!"
+msgstr "^K1Você acabou com tudo!"
+
+#: qcsrc/common/notifications/all.inc:649
+msgid "^K1You got stuck in a swamp!"
+msgstr "^K1Você ficou preso em um pântano!"
+
+#: qcsrc/common/notifications/all.inc:650
+#, c-format
+msgid "^BGYou are now on: %s"
+msgstr "^BGVocê está agora em: %s"
+
+#: qcsrc/common/notifications/all.inc:651
+msgid "^K1You died in an accident!"
+msgstr "^K1Você morreu em um acidente!"
+
+#: qcsrc/common/notifications/all.inc:652
+msgid "^K1You had an unfortunate run in with a turret!"
+msgstr "^K1Você teve um encontro lamentável com uma sentinela!"
+
+#: qcsrc/common/notifications/all.inc:652
+msgid "^K1You were fragged by a turret!"
+msgstr "^K1Você foi executado por uma sentinela!"
+
+#: qcsrc/common/notifications/all.inc:653
+msgid "^K1You had an unfortunate run in with an eWheel turret!"
+msgstr "^K1Você teve um encontro lamentável com uma sentinela eWheel!"
+
+#: qcsrc/common/notifications/all.inc:653
+msgid "^K1You were fragged by an eWheel turret!"
+msgstr "^K1Você foi executado por uma sentinela eWheel!"
+
+#: qcsrc/common/notifications/all.inc:654
+msgid "^K1You had an unfortunate run in with a Walker turret!"
+msgstr "^K1Você teve um encontro lamentável com uma sentinela Walker!"
+
+#: qcsrc/common/notifications/all.inc:654
+msgid "^K1You were fragged by a Walker turret!"
+msgstr "^K1Você foi executado por uma sentinela Walker!"
+
+#: qcsrc/common/notifications/all.inc:655
+msgid "^K1You got caught in the blast of a Bumblebee explosion!"
+msgstr "^K1Você foi pego pelo raio de uma explosão de Bumblebee!"
+
+#: qcsrc/common/notifications/all.inc:656
+msgid "^K1You were crushed by a vehicle!"
+msgstr "^K1Você foi esmagado por um veículo!"
+
+#: qcsrc/common/notifications/all.inc:657
+msgid "^K1You were caught in a Raptor cluster bomb!"
+msgstr "^K1Você foi pego por uma bomba Raptor!"
+
+#: qcsrc/common/notifications/all.inc:658
+msgid "^K1You got caught in the blast of a Raptor explosion!"
+msgstr "^K1Você foi pego no raio de uma explosão de Raptor!"
+
+#: qcsrc/common/notifications/all.inc:659
+msgid "^K1You got caught in the blast of a Spiderbot explosion!"
+msgstr "^K1Você foi pego no raio de uma explosão de Spiderbot!"
+
+#: qcsrc/common/notifications/all.inc:660
+msgid "^K1You were blasted to bits by a Spiderbot rocket!"
+msgstr "^K1Você foi despedaçado por um foguete de Spiderbot!"
+
+#: qcsrc/common/notifications/all.inc:661
+msgid "^K1You got caught in the blast of a Racer explosion!"
+msgstr "^K1Você foi pego no raio de uma explosão de Racer!"
+
+#: qcsrc/common/notifications/all.inc:662
+msgid "^K1You couldn't find shelter from a Racer rocket!"
+msgstr "^K1Você não conseguiu escapar do foguete de um Racer!"
+
+#: qcsrc/common/notifications/all.inc:663
+msgid "^K1Watch your step!"
+msgstr "^K1Cuidado onde pisa!"
+
+#: qcsrc/common/notifications/all.inc:665
+#, c-format
+msgid "^K1Moron! You fragged ^BG%s^K1, a team mate!"
+msgstr "^K1Idiota! Você executou ^BG%s^K1, um colega de equipe!"
+
+#: qcsrc/common/notifications/all.inc:665
+#, c-format
+msgid "^K1Moron! You went against ^BG%s^K1, a team mate!"
+msgstr "^K1Idiota! Você foi contra ^BG%s^K1, um colega de equipe!"
+
+#: qcsrc/common/notifications/all.inc:666
+#, c-format
+msgid "^K1You were fragged by ^BG%s^K1, a team mate"
+msgstr "^K1Você foi executado por ^BG%s^K1, um colega de equipe"
+
+#: qcsrc/common/notifications/all.inc:666
+#, c-format
+msgid "^K1You were scored against by ^BG%s^K1, a team mate"
+msgstr "^K1Você foi pontuado contra por ^BG%s^K1, um colega de equipe"
+
+#: qcsrc/common/notifications/all.inc:668
+msgid ""
+"^K1Stop idling!\n"
+"^BGDisconnecting in ^COUNT..."
+msgstr ""
+"^K1Pare de ficar AFK!\n"
+"^BGDesconectando em ^COUNT..."
+
+#: qcsrc/common/notifications/all.inc:670
+#, c-format
+msgid "^BGYou need %s^BG!"
+msgstr "^BGVocê precisa %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:671
+#, c-format
+msgid "^BGYou also need %s^BG!"
+msgstr "^BGVocê também precisa %s^BG!"
+
+#: qcsrc/common/notifications/all.inc:672
+msgid "^BGDoor unlocked!"
+msgstr "^BGPorta destrancada!"
+
+#: qcsrc/common/notifications/all.inc:674
+msgid "^F2You picked up some extra lives"
+msgstr "^F2Você pegou algumas vidas extras"
+
+#: qcsrc/common/notifications/all.inc:676
+#, c-format
+msgid "^K3You revived ^BG%s"
+msgstr "^K3Você ressuscitou ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:677
+msgid "^K3You revived yourself"
+msgstr "^K3Você se ressuscitou"
+
+#: qcsrc/common/notifications/all.inc:678
+#, c-format
+msgid "^K3You were revived by ^BG%s"
+msgstr "^K3Você foi ressuscitado por ^BG%s"
+
+#: qcsrc/common/notifications/all.inc:679
+#, c-format
+msgid "^K3You were automatically revived after %s second(s)"
+msgstr "^K3Você foi automaticamente ressuscitado após %s segundo(s)"
+
+#: qcsrc/common/notifications/all.inc:681
+msgid "^BGThe generator is under attack!"
+msgstr "^BGO gerador está sobre ataque!"
+
+#: qcsrc/common/notifications/all.inc:683
+msgid "^TC^TT^BG team loses the round"
+msgstr "A equipe ^TC^TT^BG perdeu a rodada"
+
+#: qcsrc/common/notifications/all.inc:687
+msgid "^K1You froze yourself"
+msgstr "^K1Você se congelou"
+
+#: qcsrc/common/notifications/all.inc:688
+msgid "^K1Round already started, you spawn as frozen"
+msgstr "^K1A rodada já começou, você surgiu congelado"
+
+#: qcsrc/common/notifications/all.inc:690
+#, c-format
+msgid "^K1A %s has arrived!"
+msgstr "^K1Um %s chegou!"
+
+#: qcsrc/common/notifications/all.inc:694
+msgid "^BGYou got the ^F1Fuel regenerator"
+msgstr "^BGVocê pegou o ^F1Regenerador de combustível"
+
+#: qcsrc/common/notifications/all.inc:695
+msgid "^BGYou got the ^F1Jet pack"
+msgstr "^BGVocê pegou a ^F1Mochila a Jato"
+
+#: qcsrc/common/notifications/all.inc:703
+msgid ""
+"^K1No spawnpoints available!\n"
+"Hope your team can fix it..."
+msgstr ""
+"^K1Não há pontos de surgimento disponíveis!\n"
+"Tomara que sua equipe consiga consertar isso..."
+
+#: qcsrc/common/notifications/all.inc:704
+msgid ""
+"^K1You may not join the game at this time.\n"
+"The player limit reached maximum capacity."
+msgstr ""
+"^K1Você não pode entrar no jogo neste momento.\n"
+"A capacidade máxima de jogadores foi alcançada."
+
+#: qcsrc/common/notifications/all.inc:708
+msgid "^BGYou picked up the ball"
+msgstr "^BGVocê pegou a bola"
+
+#: qcsrc/common/notifications/all.inc:709
+msgid "^BGKilling people while you don't have the ball gives no points!"
+msgstr "^BGMatar os outros enquanto você não tiver a bola não lhe dará pontos!"
+
+#: qcsrc/common/notifications/all.inc:711
+msgid ""
+"^BGAll keys are in your team's hands!\n"
+"Help the key carriers to meet!"
+msgstr ""
+"^BGTodas as chaves estão com a sua equipe!\n"
+"Ajude os portadores das chaves a se encontrarem!"
+
+#: qcsrc/common/notifications/all.inc:712
+msgid ""
+"^BGAll keys are in ^TC^TT team^BG's hands!\n"
+"Interfere ^F4NOW^BG!"
+msgstr ""
+"^BGTodas as chaves estão com a equipe ^TC^TT^BG!\n"
+"Interfira ^F4AGORA^BG!"
+
+#: qcsrc/common/notifications/all.inc:713
+msgid ""
+"^BGAll keys are in your team's hands!\n"
+"Meet the other key carriers ^F4NOW^BG!"
+msgstr ""
+"^BGTodas as chaves estão com a sua equipe!\n"
+"Encontre-se com os outros portadores das chaves ^F4AGORA^BG!"
+
+#: qcsrc/common/notifications/all.inc:714
+msgid "^F4Round will start in ^COUNT"
+msgstr "^F4A rodada iniciará em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:715
+msgid "^BGScanning frequency range..."
+msgstr "^BGEscaneando alcance de frequência..."
+
+#: qcsrc/common/notifications/all.inc:716
+msgid "^BGYou are starting with the ^TC^TT Key"
+msgstr "^BGVocê está começando com a Chave ^TC^TT"
+
+#: qcsrc/common/notifications/all.inc:718
+msgid "^BGYou have no lives left, you must wait until the next match"
+msgstr ""
+"^BGVocê não tem vidas sobrando, você terá que aguardar até a próxima partida"
+
+#: qcsrc/common/notifications/all.inc:720
+#, c-format
+msgid ""
+"^BGWaiting for players to join...\n"
+"Need active players for: %s"
+msgstr ""
+"^BGEsperando jogadores entrarem...\n"
+"Precisa-se de jogadores ativos para: %s"
+
+#: qcsrc/common/notifications/all.inc:721
+#, c-format
+msgid "^BGWaiting for %s player(s) to join..."
+msgstr "^BGEsperando %s jogador(es) entrar(em)..."
+
+#: qcsrc/common/notifications/all.inc:723
+msgid "^BGYour weapon has been downgraded until you find some ammo!"
+msgstr "^BGA sua arma foi rebaixada até que você encontre alguma munição!"
+
+#: qcsrc/common/notifications/all.inc:724
+msgid "^F4^COUNT^BG left to find some ammo!"
+msgstr "^F4^COUNT^BG restante(s) para encontrar alguma munição!"
+
+#: qcsrc/common/notifications/all.inc:725
+msgid "^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"
+msgstr "^BGEncontre alguma munição ou você morrerá em ^F4^COUNT^BG!"
+
+#: qcsrc/common/notifications/all.inc:725
+msgid "^BGGet some ammo! ^F4^COUNT^BG left!"
+msgstr "^BGEncontre alguma munição! Falta ^F4^COUNT^BG!"
+
+#: qcsrc/common/notifications/all.inc:726
+#, c-format
+msgid "^F2Extra lives remaining: ^K1%s"
+msgstr "^F2Vidas extras restantes: ^K1%s"
+
+#: qcsrc/common/notifications/all.inc:730
+#, c-format
+msgid ""
+"^F2^COUNT^BG until weapon change...\n"
+"Next weapon: ^F1%s"
+msgstr ""
+"^F2^CONTAGEM^BG até a mudança de arma...\n"
+"Próxima arma: ^F1%s"
+
+#: qcsrc/common/notifications/all.inc:731
+#, c-format
+msgid "^F2Active weapon: ^F1%s"
+msgstr "^F2Arma ativa: ^F1%s"
+
+#: qcsrc/common/notifications/all.inc:733
+#, c-format
+msgid "^BGYou captured %s^BG control point"
+msgstr "^BGVocê capturou o ponto de controle %s^BG"
+
+#: qcsrc/common/notifications/all.inc:734
+#, c-format
+msgid "^TC^TT^BG team captured %s^BG control point"
+msgstr "A equipe ^TC^TT^BG capturou o ponto de controle %s^BG"
+
+#: qcsrc/common/notifications/all.inc:735
+msgid "^BGThis control point currently cannot be captured"
+msgstr "^BGEste ponto de controle atualmente não pode ser capturado"
+
+#: qcsrc/common/notifications/all.inc:736
+msgid ""
+"^BGThe enemy generator cannot be destroyed yet\n"
+"^F2Capture some control points to unshield it"
+msgstr ""
+"^BGO gerador inimigo ainda não pode ser destruído\n"
+"^F2Capture alguns pontos de controle para desprotegê-lo"
+
+#: qcsrc/common/notifications/all.inc:737
+msgid "^BGThe ^TCenemy^BG generator is no longer shielded!"
+msgstr "^BGO gerador ^TCinimigo^BG não está mais protegido!"
+
+#: qcsrc/common/notifications/all.inc:738
+msgid ""
+"^K1Your generator is NOT shielded!\n"
+"^BGRe-capture control points to shield it!"
+msgstr ""
+"^K1O seu gerador NÃO está blindado!\n"
+"^BGRecapture pontos de controle para blindá-lo!"
+
+#: qcsrc/common/notifications/all.inc:739
+#, c-format
+msgid "^BGPress ^F2%s^BG to teleport"
+msgstr "^BGAperte ^F2%s^BG para se teletransportar"
+
+#: qcsrc/common/notifications/all.inc:740
+#, c-format
+msgid "^BGTeleporting disabled for %s"
+msgstr "^BGTeletransporte desabilitado para %s"
+
+#: qcsrc/common/notifications/all.inc:742
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"Keep fragging until we have a winner!"
+msgstr ""
+"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continue executando até que tenhamos um vencedor!"
+
+#: qcsrc/common/notifications/all.inc:742
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"Keep scoring until we have a winner!"
+msgstr ""
+"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continue pontuando até que tenhamos um vencedor!"
+
+#: qcsrc/common/notifications/all.inc:743
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"\n"
+"Generators are now decaying.\n"
+"The more control points your team holds,\n"
+"the faster the enemy generator decays"
+msgstr ""
+"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
+"\n"
+"Os geradores estão enfraquecendo agora.\n"
+"Quanto mais pontos de controle a sua equipe tiver,\n"
+"mais rápido o gerador inimigo enfraquecerá"
+
+#: qcsrc/common/notifications/all.inc:744
+#, c-format
+msgid ""
+"^F2Now playing ^F4OVERTIME^F2!\n"
+"^BGAdded ^F4%s^BG to the game!"
+msgstr ""
+"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
+"^BGAdicionado ^F4%s^BG à partida!"
+
+#: qcsrc/common/notifications/all.inc:746
+msgid "^K1In^BG-portal created"
+msgstr "^K1^BGPortal de entrada criado"
+
+#: qcsrc/common/notifications/all.inc:747
+msgid "^F3Out^BG-portal created"
+msgstr "^F3^BGPortal de saída criado"
+
+#: qcsrc/common/notifications/all.inc:748
+msgid "^F1Portal creation failed"
+msgstr "^F1Falha ao criar portal"
+
+#: qcsrc/common/notifications/all.inc:750
+msgid "^F2Strength infuses your weapons with devastating power"
+msgstr "^F2A Força deixou suas armas com um poder devastador"
+
+#: qcsrc/common/notifications/all.inc:751
+msgid "^F2Strength has worn off"
+msgstr "^F2A Força se esgotou"
+
+#: qcsrc/common/notifications/all.inc:753
+msgid "^F2Shield surrounds you"
+msgstr "^F2O Escudo te cerca"
+
+#: qcsrc/common/notifications/all.inc:754
+msgid "^F2Shield has worn off"
+msgstr "^F2O Escudo se esgotou"
+
+#: qcsrc/common/notifications/all.inc:756
+msgid "^F2You are on speed"
+msgstr "^F2Você tem a velocidade"
+
+#: qcsrc/common/notifications/all.inc:757
+msgid "^F2Speed has worn off"
+msgstr "^F2A Velocidade se esgotou"
+
+#: qcsrc/common/notifications/all.inc:759
+msgid "^F2You are invisible"
+msgstr "^F2Você está invisível"
+
+#: qcsrc/common/notifications/all.inc:760
+msgid "^F2Invisibility has worn off"
+msgstr "^F2A Invisibilidade se esgotou"
+
+#: qcsrc/common/notifications/all.inc:762
+msgid "^F2The race is over, finish your lap!"
+msgstr "^F2A corrida acabou, termine sua volta!"
+
+#: qcsrc/common/notifications/all.inc:764
+msgid "^BGSecondary fire inflicts no damage!"
+msgstr "^BGModo de disparo secundário não causa dano!"
+
+#: qcsrc/common/notifications/all.inc:766
+msgid "^BGSequence completed!"
+msgstr "^BGSequência completada!"
+
+#: qcsrc/common/notifications/all.inc:767
+msgid "^BGThere are more to go..."
+msgstr "^BGAinda tem mais..."
+
+#: qcsrc/common/notifications/all.inc:768
+#, c-format
+msgid "^BGOnly %s^BG more to go..."
+msgstr "^BGSó falta(m) %s^BG..."
+
+#: qcsrc/common/notifications/all.inc:770
+msgid "^F2Superweapons have broken down"
+msgstr "^F2As Superarmas quebraram"
+
+#: qcsrc/common/notifications/all.inc:771
+msgid "^F2Superweapons have been lost"
+msgstr "^F2As Superarmas foram perdidas"
+
+#: qcsrc/common/notifications/all.inc:772
+msgid "^F2You now have a superweapon"
+msgstr "^F2Agora você tem uma Superarma"
+
+#: qcsrc/common/notifications/all.inc:774
+msgid "^K1Changing to ^TC^TT^K1 in ^COUNT"
+msgstr "^K1Trocando para ^TC^TT^K1 em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:775
+msgid "^K1Changing team in ^COUNT"
+msgstr "^K1Trocando de equipe em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:776
+msgid "^K1Spectating in ^COUNT"
+msgstr "^K1Trocando para espectador em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:777
+msgid "^K1Suicide in ^COUNT"
+msgstr "^K1Cometendo suicídio em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:779
+msgid "^F4Timeout begins in ^COUNT"
+msgstr "^F4Pausa iniciará em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:780
+msgid "^F4Timeout ends in ^COUNT"
+msgstr "^F4Pausa acabará em ^COUNT"
+
+#: qcsrc/common/notifications/all.inc:782
+msgid "^K1Cannot join given minigame session!"
+msgstr "^K1Não foi possível entrar na sessão de mini jogo fornecida!"
+
+#: qcsrc/common/notifications/all.inc:784
+#, c-format
+msgid "^BGPress ^F2%s^BG to enter/exit the vehicle"
+msgstr "^BGAperte ^F2%s^BG para entrar/sair do veículo"
+
+#: qcsrc/common/notifications/all.inc:785
+#, c-format
+msgid "^BGPress ^F2%s^BG to enter the vehicle gunner"
+msgstr "^BGAperte ^F2%s^BG para usar a arma do veículo"
+
+#: qcsrc/common/notifications/all.inc:786
+#, c-format
+msgid "^BGPress ^F2%s^BG to steal this vehicle"
+msgstr "^BGAperte ^F2%s^BG para roubar este veículo"
+
+#: qcsrc/common/notifications/all.inc:787
+msgid ""
+"^F2The enemy is stealing one of your vehicles!\n"
+"^F4Stop them!"
+msgstr ""
+"^F2O inimigo está roubando um de seus veículos!\n"
+"^F4Impeça-os!"
+
+#: qcsrc/common/notifications/all.inc:788
+msgid "^F2Intruder detected, disabling shields!"
+msgstr "^F2Intruso detectado, desativando escudos!"
+
+#: qcsrc/common/notifications/all.qh:188
+msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
+msgstr ""
+"Comando de despejo de notificação funciona apenas com cl_cmd e sv_cmd.\n"
+
+#: qcsrc/common/notifications/all.qh:399 qcsrc/common/notifications/all.qh:400
+#, c-format
+msgid " (near %s)"
+msgstr " (próximo de %s)"
+
+#: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
+msgid "primary"
+msgstr "primário"
+
+#: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
+msgid "secondary"
+msgstr "secundário"
+
+#: qcsrc/common/notifications/all.qh:410
+msgid "point"
+msgstr "ponto"
+
+#: qcsrc/common/notifications/all.qh:410
+msgid "points"
+msgstr "pontos"
+
+#: qcsrc/common/notifications/all.qh:419
+msgid "drop flag"
+msgstr "largar bandeira"
+
+#: qcsrc/common/notifications/all.qh:420
+msgid "throw nade"
+msgstr "arremessar granada"
+
+#: qcsrc/common/notifications/all.qh:431
+#, c-format
+msgid " with %s"
+msgstr " com %s"
+
+#: qcsrc/common/notifications/all.qh:444
+#, c-format
+msgid "%s^K1 made a TRIPLE FRAG! %s^BG"
+msgstr "%s^K1 fez uma EXECUÇÃO TRIPLA! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:444
+#, c-format
+msgid "%s^K1 made a TRIPLE SCORE! %s^BG"
+msgstr "%s^K1 fez uma PONTUAÇÃO TRIPLA! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:444
+msgid "TRIPLE FRAG! "
+msgstr "EXECUÇÃO TRIPLA! "
+
+#: qcsrc/common/notifications/all.qh:445
+#, c-format
+msgid "%s^K1 made FIVE SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez CINCO PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:445
+#, c-format
+msgid "%s^K1 unlocked RAGE! %s^BG"
+msgstr "%s^K1 desbloqueou a FÚRIA! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:445
+msgid "RAGE! "
+msgstr "FÚRIA! "
+
+#: qcsrc/common/notifications/all.qh:446
+#, c-format
+msgid "%s^K1 made TEN SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez DEZ PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:446
+#, c-format
+msgid "%s^K1 started a MASSACRE! %s^BG"
+msgstr "%s^K1 começou um MASSACRE! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:446
+msgid "MASSACRE! "
+msgstr "MASSACRE! "
+
+#: qcsrc/common/notifications/all.qh:447
+#, c-format
+msgid "%s^K1 executed MAYHEM! %s^BG"
+msgstr "%s^K1 executou uma MUTILAÇÃO! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:447
+#, c-format
+msgid "%s^K1 made FIFTEEN SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez QUINZE PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:447
+msgid "MAYHEM! "
+msgstr "MUTILAÇÃO! "
+
+#: qcsrc/common/notifications/all.qh:448
+#, c-format
+msgid "%s^K1 is a BERSERKER! %s^BG"
+msgstr "%s^K1 está FURIOSO! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:448
+#, c-format
+msgid "%s^K1 made TWENTY SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez VINTE PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:448
+msgid "BERSERKER! "
+msgstr "FURIOSO!"
+
+#: qcsrc/common/notifications/all.qh:449
+#, c-format
+msgid "%s^K1 inflicts CARNAGE! %s^BG"
+msgstr "%s^K1 está infligindo CARNIFICINA! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:449
+#, c-format
+msgid "%s^K1 made TWENTY FIVE SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez VINTE E CINCO PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:449
+msgid "CARNAGE! "
+msgstr "CARNIFICINA!"
+
+#: qcsrc/common/notifications/all.qh:450
+#, c-format
+msgid "%s^K1 made THIRTY SCORES IN A ROW! %s^BG"
+msgstr "%s^K1 fez TRINTA PONTUAÇÕES SEGUIDAS! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:450
+#, c-format
+msgid "%s^K1 unleashes ARMAGEDDON! %s^BG"
+msgstr "%s^K1 desencadeou o ARMAGEDOM! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:450
+msgid "ARMAGEDDON! "
+msgstr "ARMAGEDDON! "
+
+#: qcsrc/common/notifications/all.qh:457
+#, c-format
+msgid "%s(^F1Bot^BG)"
+msgstr "%s(^F1Bot^BG)"
+
+#: qcsrc/common/notifications/all.qh:459
+#, c-format
+msgid "%s(Ping ^F1%d^BG)"
+msgstr "%s(Ping ^F1%d^BG)"
+
+#: qcsrc/common/notifications/all.qh:466
+#, c-format
+msgid ""
+"\n"
+"(Health ^1%d^BG / Armor ^2%d^BG)%s"
+msgstr ""
+"\n"
+"(Saúde ^1%d^BG / Armadura ^2%d^BG)%s"
+
+#: qcsrc/common/notifications/all.qh:468
+#, c-format
+msgid ""
+"\n"
+"(^F4Dead^BG)%s"
+msgstr ""
+"\n"
+"(^F4Morto^BG)%s"
+
+#: qcsrc/common/notifications/all.qh:489 qcsrc/common/notifications/all.qh:502
+#, c-format
+msgid "%d score spree! "
+msgstr "%d pontuações seguidas!"
+
+#: qcsrc/common/notifications/all.qh:501
+#, c-format
+msgid "%d frag spree! "
+msgstr "%d execuções seguidas!"
+
+#: qcsrc/common/notifications/all.qh:514
+msgid "First blood! "
+msgstr "Primeira morte! "
+
+#: qcsrc/common/notifications/all.qh:514
+msgid "First score! "
+msgstr "Primeiro ponto!"
+
+#: qcsrc/common/notifications/all.qh:518
+msgid "First casualty! "
+msgstr "Primeira baixa!"
+
+#: qcsrc/common/notifications/all.qh:518
+msgid "First victim! "
+msgstr "Primeira vítima!"
+
+#: qcsrc/common/notifications/all.qh:559
+#, c-format
+msgid "%s^K1 has %d frags in a row! %s^BG"
+msgstr "%s^K1 tem %d execuções seguidas! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:560
+#, c-format
+msgid "%s^K1 made %d scores in a row! %s^BG"
+msgstr "%s^K1 fez %d pontos seguidos! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:578
+#, c-format
+msgid "%s^K1 drew first blood! %s^BG"
+msgstr "%s^K1 foi o primeiro a matar alguém! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:579
+#, c-format
+msgid "%s^K1 got the first score! %s^BG"
+msgstr "%s^K1 foi o primeiro a pontuar! %s^BG"
+
+#: qcsrc/common/notifications/all.qh:595
+#, c-format
+msgid ", ending their %d frag spree"
+msgstr ", finalizando sua cadeia de %d execuções"
+
+#: qcsrc/common/notifications/all.qh:596
+#, c-format
+msgid ", ending their %d score spree"
+msgstr ", finalizando sua cadeia de %d pontuações"
+
+#: qcsrc/common/notifications/all.qh:610
+#, c-format
+msgid ", losing their %d frag spree"
+msgstr ", perdendo sua cadeia de %d execuções"
+
+#: qcsrc/common/notifications/all.qh:611
+#, c-format
+msgid ", losing their %d score spree"
+msgstr ", perdendo sua cadeia de %d pontuações"
+
+#: qcsrc/common/teams.qh:29
+msgid "TEAM^Red"
+msgstr "Vermelha"
+
+#: qcsrc/common/teams.qh:30
+msgid "TEAM^Blue"
+msgstr "Azul"
+
+#: qcsrc/common/teams.qh:31
+msgid "TEAM^Yellow"
+msgstr "Amarela"
+
+#: qcsrc/common/teams.qh:32
+msgid "TEAM^Pink"
+msgstr "Rosa"
+
+#: qcsrc/common/teams.qh:33
+msgid "Team"
+msgstr "Equipe"
+
+#: qcsrc/common/teams.qh:34
+msgid "Neutral"
+msgstr "Neutro"
+
+#: qcsrc/common/teams.qh:37
+msgid "KEY^Red"
+msgstr "Vermelha"
+
+#: qcsrc/common/teams.qh:38
+msgid "KEY^Blue"
+msgstr "Azul"
+
+#: qcsrc/common/teams.qh:39
+msgid "KEY^Yellow"
+msgstr "Amarela"
+
+#: qcsrc/common/teams.qh:40
+msgid "KEY^Pink"
+msgstr "Rosa"
+
+#: qcsrc/common/teams.qh:41
+msgid "FLAG^Red"
+msgstr "Vermelha"
+
+#: qcsrc/common/teams.qh:42
+msgid "FLAG^Blue"
+msgstr "Azul"
+
+#: qcsrc/common/teams.qh:43
+msgid "FLAG^Yellow"
+msgstr "Amarela"
+
+#: qcsrc/common/teams.qh:44
+msgid "FLAG^Pink"
+msgstr "Rosa"
+
+#: qcsrc/common/teams.qh:45
+msgid "GENERATOR^Red"
+msgstr "Vermelho"
+
+#: qcsrc/common/teams.qh:46
+msgid "GENERATOR^Blue"
+msgstr "Azul"
+
+#: qcsrc/common/teams.qh:47
+msgid "GENERATOR^Yellow"
+msgstr "Amarelo"
+
+#: qcsrc/common/teams.qh:48
+msgid "GENERATOR^Pink"
+msgstr "Rosa"
+
+#: qcsrc/common/turrets/all.qh:51
+msgid "Turrets dump command only works with sv_cmd.\n"
+msgstr "O comando de despejo de sentinelas funciona apenas com sv_cmd.\n"
+
+#: qcsrc/common/turrets/cl_turrets.qc:129
+#, c-format
+msgid "%s under attack!"
+msgstr "%s está sob ataque!"
+
+#: qcsrc/common/turrets/turret.qh:11
+msgid "Turret"
+msgstr "Sentinela"
+
+#: qcsrc/common/turrets/turret/ewheel.qh:15
+msgid "eWheel Turret"
+msgstr "Sentinela eWheel"
+
+#: qcsrc/common/turrets/turret/ewheel_weapon.qh:7
+msgid "eWheel"
+msgstr "eWheel"
+
+#: qcsrc/common/turrets/turret/flac.qh:13
+msgid "FLAC Cannon"
+msgstr "Canhão FLAC"
+
+#: qcsrc/common/turrets/turret/flac_weapon.qh:7
+msgid "FLAC"
+msgstr "FLAC"
+
+#: qcsrc/common/turrets/turret/fusionreactor.qh:11
+msgid "Fusion Reactor"
+msgstr "Reator de Fusão"
+
+#: qcsrc/common/turrets/turret/hellion.qh:13
+msgid "Hellion Missile Turret"
+msgstr "Sentinela de Míssil Hellion"
+
+#: qcsrc/common/turrets/turret/hellion_weapon.qh:7
+msgid "Hellion"
+msgstr "Hellion"
+
+#: qcsrc/common/turrets/turret/hk.qh:15
+msgid "Hunter-Killer Turret"
+msgstr "Sentinela Hunter-Killer"
+
+#: qcsrc/common/turrets/turret/hk_weapon.qh:7
+msgid "Hunter-Killer"
+msgstr "Hunter-Killer"
+
+#: qcsrc/common/turrets/turret/machinegun.qh:13
+msgid "Machinegun Turret"
+msgstr "Sentinela de Metralhadora"
+
+#: qcsrc/common/turrets/turret/machinegun_weapon.qh:7
+msgid "Machinegun"
+msgstr "Metralhadora"
+
+#: qcsrc/common/turrets/turret/mlrs.qh:13
+msgid "MLRS Turret"
+msgstr "Sentinela MLRS"
+
+#: qcsrc/common/turrets/turret/mlrs_weapon.qh:7
+msgid "MLRS"
+msgstr "MLRS"
+
+#: qcsrc/common/turrets/turret/phaser.qh:13
+msgid "Phaser Cannon"
+msgstr "Canhão Phaser"
+
+#: qcsrc/common/turrets/turret/phaser_weapon.qh:7
+msgid "Phaser"
+msgstr "Phaser"
+
+#: qcsrc/common/turrets/turret/plasma.qh:13
+msgid "Plasma Cannon"
+msgstr "Canhão de Plasma"
+
+#: qcsrc/common/turrets/turret/plasma_dual.qh:7
+msgid "Dual plasma"
+msgstr "Plasma duplo"
+
+#: qcsrc/common/turrets/turret/plasma_dual.qh:19
+msgid "Dual Plasma Cannon"
+msgstr "Canhão de Plasma Duplo"
+
+#: qcsrc/common/turrets/turret/plasma_weapon.qh:7
+msgid "Plasma"
+msgstr "Plasma"
+
+#: qcsrc/common/turrets/turret/tesla.qh:13
+#: qcsrc/common/turrets/turret/tesla_weapon.qh:7
+msgid "Tesla Coil"
+msgstr "Bobina de Tesla"
+
+#: qcsrc/common/turrets/turret/walker.qh:15
+msgid "Walker Turret"
+msgstr "Sentinela Walker"
+
+#: qcsrc/common/turrets/turret/walker_weapon.qh:7
+msgid "Walker"
+msgstr "Walker"
+
+#: qcsrc/common/vehicles/cl_vehicles.qc:192
+#, c-format
+msgid "Press %s"
+msgstr "Aperte %s"
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
+msgid "No right gunner!"
+msgstr "Sem artilheiro na direita!"
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
+msgid "No left gunner!"
+msgstr "Sem artilheiro na esquerda!"
+
+#: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
+msgid "Bumblebee"
+msgstr "Bumblebee"
+
+#: qcsrc/common/vehicles/vehicle/racer.qh:19
+msgid "Racer"
+msgstr "Racer"
+
+#: qcsrc/common/vehicles/vehicle/racer_weapon.qh:9
+msgid "Racer cannon"
+msgstr "Canhão Racer"
+
+#: qcsrc/common/vehicles/vehicle/raptor.qh:19
+msgid "Raptor"
+msgstr "Raptor"
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:9
+msgid "Raptor cannon"
+msgstr "Canhão de Raptor"
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:17
+msgid "Raptor bomb"
+msgstr "Bomba de Raptor"
+
+#: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:25
+msgid "Raptor flare"
+msgstr "Chama de Raptor"
+
+#: qcsrc/common/vehicles/vehicle/spiderbot.qh:19
+msgid "Spiderbot"
+msgstr "Spiderbot"
+
+#: qcsrc/common/weapons/all.qh:78
+msgid "Weapons dump command only works with sv_cmd.\n"
+msgstr "O comando de despejo de armas funciona apenas com sv_cmd.\n"
+
+#: qcsrc/common/weapons/weapon/arc.qc:17
+msgid "Arc"
+msgstr "Arc"
+
+#: qcsrc/common/weapons/weapon/blaster.qc:17
+msgid "Blaster"
+msgstr "Blaster"
+
+#: qcsrc/common/weapons/weapon/crylink.qc:17
+msgid "Crylink"
+msgstr "Crylink"
+
+#: qcsrc/common/weapons/weapon/devastator.qc:17
+msgid "Devastator"
+msgstr "Devastator"
+
+#: qcsrc/common/weapons/weapon/electro.qc:17
+msgid "Electro"
+msgstr "Electro"
+
+#: qcsrc/common/weapons/weapon/fireball.qc:17
+msgid "Fireball"
+msgstr "Fireball"
+
+#: qcsrc/common/weapons/weapon/hagar.qc:17
+msgid "Hagar"
+msgstr "Hagar"
+
+#: qcsrc/common/weapons/weapon/hlac.qc:17
+msgid "Heavy Laser Assault Cannon"
+msgstr "Heavy Laser Assault Cannon"
+
+#: qcsrc/common/weapons/weapon/hook.qc:17
+msgid "Grappling Hook"
+msgstr "Gancho (grappling hook)"
+
+#: qcsrc/common/weapons/weapon/machinegun.qc:17
+msgid "MachineGun"
+msgstr "Metralhadora"
+
+#: qcsrc/common/weapons/weapon/minelayer.qc:17
+msgid "Mine Layer"
+msgstr "Mine Layer"
+
+#: qcsrc/common/weapons/weapon/mortar.qc:17
+msgid "Mortar"
+msgstr "Mortar"
+
+#: qcsrc/common/weapons/weapon/porto.qc:17
+msgid "Port-O-Launch"
+msgstr "Port-O-Launch"
+
+#: qcsrc/common/weapons/weapon/rifle.qc:18
+msgid "Rifle"
+msgstr "Rifle"
+
+#: qcsrc/common/weapons/weapon/seeker.qc:17
+msgid "T.A.G. Seeker"
+msgstr "T.A.G. Seeker"
+
+#: qcsrc/common/weapons/weapon/shockwave.qc:17
+msgid "Shockwave"
+msgstr "Shockwave"
+
+#: qcsrc/common/weapons/weapon/shotgun.qc:17
+msgid "Shotgun"
+msgstr "Shotgun"
+
+#: qcsrc/common/weapons/weapon/tuba.qc:17
+#, no-c-format
+msgid "@!#%'n Tuba"
+msgstr "@!#%'n Tuba"
+
+#: qcsrc/common/weapons/weapon/vaporizer.qc:18
+msgid "Vaporizer"
+msgstr "Vaporizer"
+
+#: qcsrc/common/weapons/weapon/vortex.qc:18
+msgid "Vortex"
+msgstr "Vortex"
+
+#: qcsrc/lib/counting.qh:9
+#, c-format
+msgid "CI_DEC^%s years"
+msgstr "%s anos"
+
+#: qcsrc/lib/counting.qh:12
+#, c-format
+msgid "CI_ZER^%d years"
+msgstr "%d anos"
+
+#: qcsrc/lib/counting.qh:13
+#, c-format
+msgid "CI_FIR^%d year"
+msgstr "^%d ano"
+
+#: qcsrc/lib/counting.qh:14
+#, c-format
+msgid "CI_SEC^%d years"
+msgstr "%d anos"
+
+#: qcsrc/lib/counting.qh:15
+#, c-format
+msgid "CI_THI^%d years"
+msgstr "%d anos"
+
+#: qcsrc/lib/counting.qh:16
+#, c-format
+msgid "CI_MUL^%d years"
+msgstr "^%d anos"
+
+#: qcsrc/lib/counting.qh:18
+#, c-format
+msgid "CI_DEC^%s weeks"
+msgstr "^%s semanas"
+
+#: qcsrc/lib/counting.qh:21
+#, c-format
+msgid "CI_ZER^%d weeks"
+msgstr "^%d semanas"
+
+#: qcsrc/lib/counting.qh:22
+#, c-format
+msgid "CI_FIR^%d week"
+msgstr "^%d semana"
+
+#: qcsrc/lib/counting.qh:23
+#, c-format
+msgid "CI_SEC^%d weeks"
+msgstr "^%d semanas"
+
+#: qcsrc/lib/counting.qh:24
+#, c-format
+msgid "CI_THI^%d weeks"
+msgstr "^%d semanas"
+
+#: qcsrc/lib/counting.qh:25
+#, c-format
+msgid "CI_MUL^%d weeks"
+msgstr "^%d semanas"
+
+#: qcsrc/lib/counting.qh:27
+#, c-format
+msgid "CI_DEC^%s days"
+msgstr "^%s dias"
+
+#: qcsrc/lib/counting.qh:30
+#, c-format
+msgid "CI_ZER^%d days"
+msgstr "^%d dias"
+
+#: qcsrc/lib/counting.qh:31
+#, c-format
+msgid "CI_FIR^%d day"
+msgstr "^%d dia"
+
+#: qcsrc/lib/counting.qh:32
+#, c-format
+msgid "CI_SEC^%d days"
+msgstr "^%d dias"
+
+#: qcsrc/lib/counting.qh:33
+#, c-format
+msgid "CI_THI^%d days"
+msgstr "^%d dias"
+
+#: qcsrc/lib/counting.qh:34
+#, c-format
+msgid "CI_MUL^%d days"
+msgstr "^%d dias"
+
+#: qcsrc/lib/counting.qh:36
+#, c-format
+msgid "CI_DEC^%s hours"
+msgstr "^%s horas"
+
+#: qcsrc/lib/counting.qh:39
+#, c-format
+msgid "CI_ZER^%d hours"
+msgstr "^%d horas"
+
+#: qcsrc/lib/counting.qh:40
+#, c-format
+msgid "CI_FIR^%d hour"
+msgstr "^%d hora"
+
+#: qcsrc/lib/counting.qh:41
+#, c-format
+msgid "CI_SEC^%d hours"
+msgstr "^%d horas"
+
+#: qcsrc/lib/counting.qh:42
+#, c-format
+msgid "CI_THI^%d hours"
+msgstr "^%d horas"
+
+#: qcsrc/lib/counting.qh:43
+#, c-format
+msgid "CI_MUL^%d hours"
+msgstr "^%d horas"
+
+#: qcsrc/lib/counting.qh:46
+#, c-format
+msgid "CI_DEC^%s minutes"
+msgstr "^%s minutos"
+
+#: qcsrc/lib/counting.qh:49
+#, c-format
+msgid "CI_ZER^%d minutes"
+msgstr "^%d minutos"
+
+#: qcsrc/lib/counting.qh:50
+#, c-format
+msgid "CI_FIR^%d minute"
+msgstr "^%d minuto"
+
+#: qcsrc/lib/counting.qh:51
+#, c-format
+msgid "CI_SEC^%d minutes"
+msgstr "^%d minutos"
+
+#: qcsrc/lib/counting.qh:52
+#, c-format
+msgid "CI_THI^%d minutes"
+msgstr "^%d minutos"
+
+#: qcsrc/lib/counting.qh:53
+#, c-format
+msgid "CI_MUL^%d minutes"
+msgstr "^%d minutos"
+
+#: qcsrc/lib/counting.qh:55
+#, c-format
+msgid "CI_DEC^%s seconds"
+msgstr "^%s segundos"
+
+#: qcsrc/lib/counting.qh:58
+#, c-format
+msgid "CI_ZER^%d seconds"
+msgstr "^%d segundos"
+
+#: qcsrc/lib/counting.qh:59
+#, c-format
+msgid "CI_FIR^%d second"
+msgstr "^%d segundo"
+
+#: qcsrc/lib/counting.qh:60
+#, c-format
+msgid "CI_SEC^%d seconds"
+msgstr "^%d segundos"
+
+#: qcsrc/lib/counting.qh:61
+#, c-format
+msgid "CI_THI^%d seconds"
+msgstr "^%d segundos"
+
+#: qcsrc/lib/counting.qh:62
+#, c-format
+msgid "CI_MUL^%d seconds"
+msgstr "^%d segundos"
+
+#: qcsrc/lib/counting.qh:79
+#, c-format
+msgid "%dst"
+msgstr "%dst"
+
+#: qcsrc/lib/counting.qh:80
+#, c-format
+msgid "%dnd"
+msgstr "%dnd"
+
+#: qcsrc/lib/counting.qh:81
+#, c-format
+msgid "%drd"
+msgstr "%drd"
+
+#: qcsrc/lib/counting.qh:82 qcsrc/lib/counting.qh:85
+#, c-format
+msgid "%dth"
+msgstr "%dth"
+
+#: qcsrc/lib/oo.qh:298
+msgid "No description"
+msgstr "Sem descrição"
+
+#: qcsrc/lib/spawnfunc.qh:65
+#, c-format
+msgid ""
+"Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, "
+"please file an issue."
+msgstr ""
+"Campo de entidade %s.%s (%s) não está na lista branca. Se você acredita que "
+"isso é um erro, por favor, reporte-o."
+
+#: qcsrc/lib/string.qh:48
+#, c-format
+msgid "%d days, %02d:%02d:%02d"
+msgstr "%d dias, %02d:%02d:%02d"
+
+#: qcsrc/lib/string.qh:49
+#, c-format
+msgid "%02d:%02d:%02d"
+msgstr "%02d:%02d:%02d"
+
+#: qcsrc/menu/command/menu_cmd.qc:48
+msgid "Usage: menu_cmd command..., where possible commands are:\n"
+msgstr "Uso: comando menu_cmd..., onde os possíveis comandos são:\n"
+
+#: qcsrc/menu/command/menu_cmd.qc:49
+msgid "  sync - reloads all cvars on the current menu page\n"
+msgstr " sync - recarrega todas as cvars no menu atual\n"
+
+#: qcsrc/menu/command/menu_cmd.qc:50
+msgid "  directmenu ITEM - select a menu item as main item\n"
+msgstr " directmenu ITEM - seleciona um item do menu como principal\n"
+
+#: qcsrc/menu/command/menu_cmd.qc:79
+msgid "Available options:\n"
+msgstr "Opções disponíveis:\n"
+
+#: qcsrc/menu/command/menu_cmd.qc:128
+msgid "Invalid command. For a list of supported commands, try menu_cmd help.\n"
+msgstr ""
+"Comando inválido. Para uma lista de comandos suportados, digite menu_cmd "
+"help.\n"
+
+#: qcsrc/menu/item/listbox.qc:415
+#, c-format
+msgid "Item %d"
+msgstr "Item %d"
+
+#: qcsrc/menu/item/textslider.qc:11 qcsrc/menu/item/textslider.qc:12
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:37
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:68
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:115
+msgid "Custom"
+msgstr "Personalizado"
+
+#: qcsrc/menu/xonotic/campaign.qc:241
+#, c-format
+msgid "Level %d: %s"
+msgstr "Nível %d: %s"
+
+#: qcsrc/menu/xonotic/credits.qc:4
+msgid "Core Team"
+msgstr "Equipe Principal"
+
+#: qcsrc/menu/xonotic/credits.qc:16
+msgid "Extended Team"
+msgstr "Equipe Estendida"
+
+#: qcsrc/menu/xonotic/credits.qc:48
+msgid "Website"
+msgstr "Site"
+
+#: qcsrc/menu/xonotic/credits.qc:53
+msgid "Stats"
+msgstr "Estatísticas"
+
+#: qcsrc/menu/xonotic/credits.qc:57
+msgid "Art"
+msgstr "Arte"
+
+#: qcsrc/menu/xonotic/credits.qc:65
+msgid "Animation"
+msgstr "Animação"
+
+#: qcsrc/menu/xonotic/credits.qc:69
+msgid "Level Design"
+msgstr "Design de Mapas"
+
+#: qcsrc/menu/xonotic/credits.qc:92
+msgid "Music / Sound FX"
+msgstr "Música / Efeitos de Som"
+
+#: qcsrc/menu/xonotic/credits.qc:108
+msgid "Game Code"
+msgstr "Codificação de Jogo"
+
+#: qcsrc/menu/xonotic/credits.qc:116
+msgid "Marketing / PR"
+msgstr "Marketing / Relações Públicas"
+
+#: qcsrc/menu/xonotic/credits.qc:122
+msgid "Legal"
+msgstr "Assuntos Legais"
+
+#: qcsrc/menu/xonotic/credits.qc:127
+msgid "Game Engine"
+msgstr "Motor de Jogo"
+
+#: qcsrc/menu/xonotic/credits.qc:131
+msgid "Engine Additions"
+msgstr "Adições ao Motor"
+
+#: qcsrc/menu/xonotic/credits.qc:136
+msgid "Compiler"
+msgstr "Compilador"
+
+#: qcsrc/menu/xonotic/credits.qc:142
+msgid "Other Active Contributors"
+msgstr "Outros Contribuidores Ativos"
+
+#: qcsrc/menu/xonotic/credits.qc:149
+msgid "Translators"
+msgstr "Tradutores"
+
+#: qcsrc/menu/xonotic/credits.qc:151
+msgid "Asturian"
+msgstr "Asturiano"
+
+#: qcsrc/menu/xonotic/credits.qc:156
+msgid "Belarusian"
+msgstr "Bielorrusso"
+
+#: qcsrc/menu/xonotic/credits.qc:159
+msgid "Bulgarian"
+msgstr "Búlgaro"
+
+#: qcsrc/menu/xonotic/credits.qc:166
+msgid "Chinese (China)"
+msgstr "Chinês (China)"
+
+#: qcsrc/menu/xonotic/credits.qc:172
+msgid "Chinese (Taiwan)"
+msgstr "Chinês (Taiwan)"
+
+#: qcsrc/menu/xonotic/credits.qc:177
+msgid "Cornish"
+msgstr "Córnico"
+
+#: qcsrc/menu/xonotic/credits.qc:180
+msgid "Czech"
+msgstr "Tcheco"
+
+#: qcsrc/menu/xonotic/credits.qc:185
+msgid "Dutch"
+msgstr "Holandês"
+
+#: qcsrc/menu/xonotic/credits.qc:192
+msgid "English (Australia)"
+msgstr "Inglês (Austrália)"
+
+#: qcsrc/menu/xonotic/credits.qc:197
+msgid "Finnish"
+msgstr "Finlandês"
+
+#: qcsrc/menu/xonotic/credits.qc:202
+msgid "French"
+msgstr "Francês"
+
+#: qcsrc/menu/xonotic/credits.qc:210
+msgid "German"
+msgstr "Alemão"
+
+#: qcsrc/menu/xonotic/credits.qc:221
+msgid "Greek"
+msgstr "Grego"
+
+#: qcsrc/menu/xonotic/credits.qc:227
+msgid "Hungarian"
+msgstr "Húngaro"
+
+#: qcsrc/menu/xonotic/credits.qc:231
+msgid "Irish"
+msgstr "Irlandês"
+
+#: qcsrc/menu/xonotic/credits.qc:234
+msgid "Italian"
+msgstr "Italiano"
+
+#: qcsrc/menu/xonotic/credits.qc:240
+msgid "Kazakh"
+msgstr "Cazaque"
+
+#: qcsrc/menu/xonotic/credits.qc:243
+msgid "Korean"
+msgstr "Coreano"
+
+#: qcsrc/menu/xonotic/credits.qc:247
+msgid "Polish"
+msgstr "Polônes"
+
+#: qcsrc/menu/xonotic/credits.qc:255
+msgid "Portuguese"
+msgstr "Português"
+
+#: qcsrc/menu/xonotic/credits.qc:261
+msgid "Romanian"
+msgstr "Romeno"
+
+#: qcsrc/menu/xonotic/credits.qc:268
+msgid "Russian"
+msgstr "Russo"
+
+#: qcsrc/menu/xonotic/credits.qc:279
+msgid "Scottish Gaelic"
+msgstr "Gaélico Escocês"
+
+#: qcsrc/menu/xonotic/credits.qc:282
+msgid "Serbian"
+msgstr "Sérvio"
+
+#: qcsrc/menu/xonotic/credits.qc:288
+msgid "Spanish"
+msgstr "Espanhol"
+
+#: qcsrc/menu/xonotic/credits.qc:299
+msgid "Swedish"
+msgstr "Sueco"
+
+#: qcsrc/menu/xonotic/credits.qc:303
+msgid "Ukrainian"
+msgstr "Ucraniano"
+
+#: qcsrc/menu/xonotic/credits.qc:310
+msgid "Past Contributors"
+msgstr "Colaboradores Passados"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:73
+msgid "forced to be saved to config.cfg"
+msgstr "forçado a ser salvo em config.cfg"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:79 qcsrc/menu/xonotic/cvarlist.qc:89
+msgid "will not be saved"
+msgstr "não será salvo"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:84
+msgid "will be saved to config.cfg"
+msgstr "será salvo em config.cfg"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:93
+msgid "private"
+msgstr "privado"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:95
+msgid "engine setting"
+msgstr "configuração do motor"
+
+#: qcsrc/menu/xonotic/cvarlist.qc:97
+msgid "read only"
+msgstr "somente leitura"
+
+#: qcsrc/menu/xonotic/dialog_credits.qc:13
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:38
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:287
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:85
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:75
+#: qcsrc/menu/xonotic/dialog_singleplayer_winner.qc:14
+msgid "OK"
+msgstr "OK"
+
+#: qcsrc/menu/xonotic/dialog_credits.qh:7
+msgid "Credits"
+msgstr "Créditos"
+
+#: qcsrc/menu/xonotic/dialog_credits.qh:8
+msgid "The Xonotic credits"
+msgstr "Créditos - Xonotic"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:39
+msgid ""
+"Welcome to Xonotic, please select your language preference and enter your "
+"player name to get started.  You can change these options later through the "
+"menu system."
+msgstr ""
+"Bem-vindo(a) ao Xonotic! Escolha o seu idioma de preferência e insira o seu "
+"apelido para começar. Você pode alterar essas configurações mais tarde pelo "
+"menu."
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:45
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:28
+msgid "Name:"
+msgstr "Nome:"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:53
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
+msgid "Name under which you will appear in the game"
+msgstr "Seu nome que aparecerá no jogo"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:69
+msgid "Text language:"
+msgstr "Idioma do texto:"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:78
+msgid "Allow player statistics to use your nickname at stats.xonotic.org?"
+msgstr ""
+"Permitir que as estatísticas de jogador usem o seu apelido em stats.xonotic."
+"org?"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:84
+msgid "Undecided"
+msgstr "Não decidido"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qc:88
+msgid "Save settings"
+msgstr "Salvar configurações"
+
+#: qcsrc/menu/xonotic/dialog_firstrun.qh:6
+msgid "Welcome"
+msgstr "Bem-vindo(a)"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
+msgid "Ammunition display:"
+msgstr "Exibir munições:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:19
+msgid "Show only current ammo type"
+msgstr "Exibir apenas o tipo de munição atual"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:22
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:44
+msgid "Noncurrent alpha:"
+msgstr "Alfa não circulante:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:26
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:48
+msgid "Noncurrent scale:"
+msgstr "Escala não circulante:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:30
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:24
+msgid "Align icon:"
+msgstr "Alinhar ícone:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:31
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:30
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:23
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:35
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:21
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:33
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:18
+msgid "Left"
+msgstr "Esquerda"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:36
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:26
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:23
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:34
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:20
+msgid "Right"
+msgstr "Direita"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qh:6
+msgid "Ammo Panel"
+msgstr "Painel de Munições"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:17
+msgid "Message duration:"
+msgstr "Duração de mensagem:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:21
+msgid "Fade time:"
+msgstr "Tempo de desaparecimento:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:25
+msgid "Flip messages order"
+msgstr "Trocar ordem de mensagens"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:15
+msgid "Text alignment:"
+msgstr "Alinhamento do texto:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:31
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:19
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:71
+msgid "Center"
+msgstr "Centro"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:35
+msgid "Font scale:"
+msgstr "Tamanho da fonte:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh:6
+msgid "Centerprint Panel"
+msgstr "Painel Central"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
+msgid "Chat entries:"
+msgstr "Entradas do bate-papo:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
+msgid "Chat size:"
+msgstr "Tamanho do bate-papo:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
+msgid "Chat lifetime:"
+msgstr "Tempo de vida do bate-papo:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
+msgid "Chat beep sound"
+msgstr "Som de aviso do bate-papo"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
+msgid "Chat Panel"
+msgstr "Painel do Bate-papo"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
+msgid "Engine info:"
+msgstr "Informações do Motor:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:17
+msgid "Use an averaging algorithm for fps"
+msgstr "Usar um algoritmo médio para o fps"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qh:6
+msgid "Engine Info Panel"
+msgstr "Painel de Informações do Motor"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
+msgid "Combine health and armor"
+msgstr "Combinar saúde e armadura"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:15
+msgid "Enable status bar"
+msgstr "Habilitar barra de status"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:19
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:17
+msgid "Status bar alignment:"
+msgstr "Alinhamento da barra de status:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:37
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:25
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:35
+msgid "Inward"
+msgstr "Para dentro"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:29
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:38
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:27
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:36
+msgid "Outward"
+msgstr "Para fora"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:32
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:30
+msgid "Icon alignment:"
+msgstr "Alinhamento de ícones:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:40
+msgid "Flip health and armor positions"
+msgstr "Trocar as posições da saúde e armadura"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh:6
+msgid "Health/Armor Panel"
+msgstr "Painel de Saúde/Armadura"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
+msgid "Info messages:"
+msgstr "Mensagens de informação:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:17
+msgid "Flip align"
+msgstr "Trocar alinhamento"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qh:6
+msgid "Info Messages Panel"
+msgstr "Painel de Mensagens de Informação"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:16
+msgid "PNL^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:17
+msgid "PNL^Enabled spectating"
+msgstr "Espectadores habilitados"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:18
+msgid "PNL^Enabled even playing in warmup"
+msgstr "Habilitado mesmo jogando em aquecimento"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:29
+msgid "Reduced"
+msgstr "Reduzido"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:32
+msgid "Text/icon ratio:"
+msgstr "Proporção para textos e ícones:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:35
+msgid "Hide spawned items"
+msgstr "Ocultar itens disponíveis"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:37
+msgid "Hide big armor and health"
+msgstr "Ocultar armadura grande e saúde grande"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:39
+msgid "Dynamic size"
+msgstr "Tamanho dinâmico"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qh:6
+msgid "Items Time Panel"
+msgstr "Painel de Tempo dos Itens "
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_modicons.qh:6
+msgid "Mod Icons Panel"
+msgstr "Painel de Ícones de Mod"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:15
+msgid "Notifications:"
+msgstr "Notificações:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:18
+msgid "Also print notifications to the console"
+msgstr "Mostrar notificações no console também"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:21
+msgid "Flip notify order"
+msgstr "Trocar ordem de notificações"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:24
+msgid "Entry lifetime:"
+msgstr "Tempo de vida de cada entrada:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qc:28
+msgid "Entry fadetime:"
+msgstr "Desaparecimento de cada entrada:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
+msgid "Notification Panel"
+msgstr "Painel de Notificações"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:15
+msgid "Panel disabled"
+msgstr "Painel desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:16
+msgid "Panel enabled"
+msgstr "Painel habilitado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
+msgid "Panel enabled even observing"
+msgstr "Painel habilitado enquanto estiver observando"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:18
+msgid "Panel enabled only in Race/CTS"
+msgstr "Painel habilitado apenas em Corrida/CTS"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
+msgid "Status bar"
+msgstr "Barra de status"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:26
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:68
+msgid "Left align"
+msgstr "Alinhamento à esquerda"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:27
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:74
+msgid "Right align"
+msgstr "Alinhamento à direita"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:28
+msgid "Inward align"
+msgstr "Alinhamento para dentro"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:29
+msgid "Outward align"
+msgstr "Alinhamento para fora"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:33
+msgid "Flip speed/acceleration positions"
+msgstr "Trocar posição da velocidade e da aceleração"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:37
+msgid "Speed:"
+msgstr "Velocidade:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:38
+msgid "Include vertical speed"
+msgstr "Incluir velocidade vertical"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:49
+msgid "Speed unit:"
+msgstr "Unidade de velocidade:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:51
+msgid "qu/s"
+msgstr "qu/s"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:52
+msgid "m/s"
+msgstr "m/s"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:53
+msgid "km/h"
+msgstr "km/h"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:54
+msgid "mph"
+msgstr "mph"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:55
+msgid "knots"
+msgstr "nós"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:57
+msgid "Show"
+msgstr "Exibir"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:60
+msgid "Top speed"
+msgstr "Velocidade máxima"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:66
+msgid "Acceleration:"
+msgstr "Aceleração:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:67
+msgid "Include vertical acceleration"
+msgstr "Incluir aceleração vertical"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qh:6
+msgid "Physics Panel"
+msgstr "Painel de Física"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qh:6
+msgid "Powerups Panel"
+msgstr "Painel de Potencializadores"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:15
+msgid "Panel enabled when spectating"
+msgstr "Painel habilitado enquanto estiver de espectador"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:16
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:17
+msgid "Panel always enabled"
+msgstr "Painel sempre habilitado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:23
+msgid "Forced aspect:"
+msgstr "Forçar aspecto:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qh:6
+msgid "Pressed Keys Panel"
+msgstr "Painel de Teclas Pressionadas"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qh:6
+msgid "Quick Menu Panel"
+msgstr "Painel de Menu Instantâneo"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_racetimer.qh:6
+msgid "Race Timer Panel"
+msgstr "Painel do Cronômetro de Corrida"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
+msgid "Panel enabled in teamgames"
+msgstr "Painel habilitado em jogos de equipe"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
+msgid "Radar:"
+msgstr "Radar:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:26
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:68
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:107
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:54
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:87
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:103
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:45
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:67
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:118
+#: qcsrc/menu/xonotic/util.qc:792
+msgid "Alpha:"
+msgstr "Alfa:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:30
+msgid "Rotation:"
+msgstr "Rotação:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:32
+msgid "Forward"
+msgstr "Para a frente"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:33
+msgid "West"
+msgstr "Para o oeste"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:34
+msgid "South"
+msgstr "Para o sul"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:35
+msgid "East"
+msgstr "Para o leste"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:36
+msgid "North"
+msgstr "Para o norte"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:40
+msgid "Scale:"
+msgstr "Escala:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:44
+msgid "Zoom mode:"
+msgstr "Modo de zoom:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:46
+msgid "Zoomed in"
+msgstr "Ampliado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:47
+msgid "Zoomed out"
+msgstr "Afastado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:48
+msgid "Always zoomed"
+msgstr "Sempre ampliado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:49
+msgid "Never zoomed"
+msgstr "Nunca ampliado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qh:6
+msgid "Radar Panel"
+msgstr "Painel do Radar"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:15
+msgid "Score:"
+msgstr "Pontuação:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:18
+msgid "Rankings:"
+msgstr "Classificações:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:19
+msgid "Off"
+msgstr "Desligado"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:20
+msgid "And me"
+msgstr "E eu"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:21
+msgid "Pure"
+msgstr "Puro"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_score.qh:6
+msgid "Score Panel"
+msgstr "Painel da Pontuação"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:14
+msgid "Timer:"
+msgstr "Cronômetro:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qc:17
+msgid "Show elapsed time"
+msgstr "Exibir tempo decorrido"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_timer.qh:6
+msgid "Timer Panel"
+msgstr "Painel do Cronômetro"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_vote.qc:15
+msgid "Alpha after voting:"
+msgstr "Alfa após votação:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_vote.qh:6
+msgid "Vote Panel"
+msgstr "Painel de Votação"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:20
+msgid "Fade out after:"
+msgstr "Desaparecer após:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:22
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:167
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:139
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:55
+msgid "Never"
+msgstr "Nunca"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:24
+#, c-format
+msgid "%ds"
+msgstr "%ds"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:28
+msgid "Fade effect:"
+msgstr "Efeito de desaparecimento:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:31
+msgid "EF^None"
+msgstr "Nenhum"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:32
+msgid "Alpha"
+msgstr "Alfa"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:33
+msgid "Slide"
+msgstr "Deslizar"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:34
+msgid "EF^Both"
+msgstr "Ambos"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:38
+msgid "Weapon icons:"
+msgstr "Ícones das armas:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:41
+msgid "Show only owned weapons"
+msgstr "Exibir apenas armas obtidas"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:52
+msgid "Show weapon ID as:"
+msgstr "Exibir o ID da arma como:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:53
+msgid "SHOWAS^None"
+msgstr "Nenhum"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:54
+msgid "Number"
+msgstr "Número"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:55
+msgid "Bind"
+msgstr "Atalho"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:58
+msgid "Weapon ID scale:"
+msgstr "Escala do ID da arma:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:64
+msgid "Show Accuracy"
+msgstr "Exibir precisão"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:65
+msgid "Show Ammo"
+msgstr "Exibir munições"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:68
+msgid "Ammo bar alpha:"
+msgstr "Transparência da barra de munições:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:74
+msgid "Ammo bar color:"
+msgstr "Cor da barra de munições:"
+
+#: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qh:6
+msgid "Weapons Panel"
+msgstr "Painel das Armas"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:19
+msgid "HUD skins"
+msgstr "Visuais de HUD"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:22
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:196
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:31
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:42
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:25
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:35
+msgid "Filter:"
+msgstr "Filtrar:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:30
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:49
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:44
+msgid "Refresh"
+msgstr "Atualizar"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:33
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:30
+msgid "Set skin"
+msgstr "Definir visual"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:37
+msgid "Save current skin"
+msgstr "Salvar visual atual"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:46
+msgid "Panel background defaults:"
+msgstr "Padrões de fundo do painel:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:48
+#: qcsrc/menu/xonotic/util.qc:767
+msgid "Background:"
+msgstr "Fundo:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:50
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:62
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:77
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:116
+#: qcsrc/menu/xonotic/util.qc:770 qcsrc/menu/xonotic/util.qc:786
+#: qcsrc/menu/xonotic/util.qc:803
+msgid "Disable"
+msgstr "Desabilitar"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:60
+#: qcsrc/menu/xonotic/util.qc:783
+msgid "Border size:"
+msgstr "Tamanho das bordas:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:75
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:114
+msgid "Team color:"
+msgstr "Cor de equipe:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:83
+#: qcsrc/menu/xonotic/util.qc:809
+msgid "Test team color in configure mode"
+msgstr "Testar cor de equipe no modo de configuração"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:86
+#: qcsrc/menu/xonotic/util.qc:812
+msgid "Padding:"
+msgstr "Preenchimento:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:93
+msgid "HUD Dock:"
+msgstr "Camada do HUD:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:95
+msgid "DOCK^Disabled"
+msgstr "Desabilitada"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:96
+msgid "DOCK^Small"
+msgstr "Pequena"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:97
+msgid "DOCK^Medium"
+msgstr "Média"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:98
+msgid "DOCK^Large"
+msgstr "Grande"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:121
+msgid "Grid settings:"
+msgstr "Configurações da rede:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:124
+msgid "Snap panels to grid"
+msgstr "Fixar painéis à grade"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:127
+msgid "Grid size:"
+msgstr "Tamanho da rede:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:129
+msgid "X:"
+msgstr "X:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:136
+msgid "Y:"
+msgstr "Y:"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:145
+msgid "Exit setup"
+msgstr "Sair da configuração"
+
+#: qcsrc/menu/xonotic/dialog_hudsetup_exit.qh:6
+msgid "Panel HUD Setup"
+msgstr "Painel de Configuração do HUD"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:13
+msgid "Monster:"
+msgstr "Monstro:"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:22
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:20
+msgid "Spawn"
+msgstr "Surgir"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:23
+#: qcsrc/menu/xonotic/serverlist.qc:268
+msgid "Remove"
+msgstr "Remover"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:25
+msgid "Move target:"
+msgstr "Mover alvo:"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:26
+msgid "Follow"
+msgstr "Seguir"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:27
+msgid "Wander"
+msgstr "Vaguear"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:28
+msgid "Spawnpoint"
+msgstr "Ponto de surgimento"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:29
+msgid "No moving"
+msgstr "Sem movimento"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:31
+msgid "Colors:"
+msgstr "Cores:"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qc:33
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:39
+msgid "Set skin:"
+msgstr "Definir visual:"
+
+#: qcsrc/menu/xonotic/dialog_monstertools.qh:6
+msgid "Monster Tools"
+msgstr "Ferramentas de Monstros"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:14
+msgid "Servers"
+msgstr "Servidores"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:15
+msgid "Find servers to play on"
+msgstr "Encontre servidores para jogar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:17
+msgid "Host your own game"
+msgstr "Crie a sua própria partida"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:18
+msgid "Media"
+msgstr "Mídia"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qc:19
+msgid "Profile"
+msgstr "Perfil"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qh:6
+msgid "Multiplayer"
+msgstr "Multijogador"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer.qh:7
+msgid ""
+"Play online, against your friends in LAN, view demos or change player "
+"settings"
+msgstr ""
+"Jogue online, jogue contra seus amigos em rede local, assista a demos ou "
+"altere as configurações de jogador."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:46
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:134
+#: qcsrc/menu/xonotic/skinlist.qc:88 qcsrc/menu/xonotic/util.qc:769
+#: qcsrc/menu/xonotic/util.qc:785 qcsrc/menu/xonotic/util.qc:794
+#: qcsrc/menu/xonotic/util.qc:802 qcsrc/menu/xonotic/util.qc:814
+msgid "Default"
+msgstr "Padrão"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:48
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:64
+msgid "Unlimited"
+msgstr "Ilimitado"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:66
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:78
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:128
+msgid "Frag limit:"
+msgstr "Limite de execuções:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:66
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:78
+msgid "The amount of frags needed before the match will end"
+msgstr "A quantidade de execuções necessária para acabar a partida"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
+msgid "Capture limit:"
+msgstr "Limite de capturas:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
+msgid "The amount of captures needed before the match will end"
+msgstr "A quantidade de capturas necessária para acabar a partida"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:68
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:73
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:74
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:75
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:76
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:77
+msgid "Point limit:"
+msgstr "Limite de pontos:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:68
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:77
+msgid "The amount of points needed before the match will end"
+msgstr "A quantidade de pontos necessária para acabar a partida"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:70
+msgid "Lives:"
+msgstr "Vidas:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:71
+msgid "Laps:"
+msgstr "Voltas:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
+msgid "Goals:"
+msgstr "Gols:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
+msgid "The amount of goals needed before the match will end"
+msgstr "A quantidade de gols necessária para acabar a partida"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:97
+msgid "Gametype"
+msgstr "Modo de jogo"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:102
+msgid "Time limit:"
+msgstr "Tempo limite:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:104
+msgid "Timelimit in minutes that when hit, will end the match"
+msgstr ""
+"Limite de tempo em minutos que, ao ser atingido, irá encerrar a partida."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:105
+#, c-format
+msgid "%d minutes"
+msgstr "%d minutos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:106
+msgid "TIMLIM^Default"
+msgstr "Padrão"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:107
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:159
+msgid "1 minute"
+msgstr "1 minuto"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:124
+msgid "TIMLIM^Infinite"
+msgstr "Infinito"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:132
+msgid "Teams:"
+msgstr "Equipes:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:135
+msgid "2 teams"
+msgstr "2 equipes"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:136
+msgid "3 teams"
+msgstr "3 equipes"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:137
+msgid "4 teams"
+msgstr "4 equipes"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:140
+msgid "Player slots:"
+msgstr "Vagas para jogadores:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:142
+msgid ""
+"The maximum amount of players or bots that can be connected to your server "
+"at once"
+msgstr ""
+"O número máximo de jogadores ou bots que podem estar conectados ao seu "
+"servidor simultaneamente."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:144
+msgid "Number of bots:"
+msgstr "Número de bots:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:146
+msgid "Amount of bots on your server"
+msgstr "Quantidade de bots no seu servidor"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:148
+msgid "Bot skill:"
+msgstr "Habilidade dos bots:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:151
+msgid "Specify how experienced the bots will be"
+msgstr "Especifique a experiência dos bots"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:152
+msgid "Botlike"
+msgstr "Perdido"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:153
+msgid "Beginner"
+msgstr "Iniciante"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:154
+msgid "You will win"
+msgstr "Você vai ganhar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:155
+msgid "You can win"
+msgstr "Você pode ganhar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:156
+msgid "You might win"
+msgstr "Você talvez ganhe"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:157
+msgid "Advanced"
+msgstr "Avançado"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:158
+msgid "Expert"
+msgstr "Experiente"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:159
+msgid "Pro"
+msgstr "Profissional"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:160
+msgid "Assassin"
+msgstr "Assassino"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:161
+msgid "Unhuman"
+msgstr "Desumano"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:162
+msgid "Godlike"
+msgstr "Divino"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:178
+msgid "Mutators..."
+msgstr "Modificadores..."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:179
+msgid "Mutators and weapon arenas"
+msgstr "Modificadores e arenas de armas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:188
+msgid "Maplist"
+msgstr "Lista de mapas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:198
+msgid ""
+"Click here or Ctrl-F to provide a keyword to narrow down the map list. Ctrl-"
+"Delete to clear; Enter when done."
+msgstr ""
+"Clique aqui ou aperte Ctrl+F para digitar uma palavra chave e buscar o mapa "
+"desejado. Você pode apertar Ctrl+Delete para apagar e Enter para confirmar."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:207
+msgid "Add shown"
+msgstr "Adicionar exibidos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:208
+msgid "Add the maps shown in the list to your selection"
+msgstr "Adiciona os mapas exibidos na lista para a sua seleção"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:211
+msgid "Remove shown"
+msgstr "Remover exibidos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:212
+msgid "Remove the maps shown in the list from your selection"
+msgstr "Remove os mapas exibidos na lista da sua seleção"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:217
+msgid "Add all"
+msgstr "Adicionar todos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:218
+msgid "Add every available map to your selection"
+msgstr "Adiciona todos os mapas disponíveis para a sua seleção"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:221
+msgid "Remove all"
+msgstr "Remover todos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:222
+msgid "Remove all the maps from your selection"
+msgstr "Remove todos os mapas da sua seleção"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:229
+msgid "Start Multiplayer!"
+msgstr "Iniciar Multijogador!"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:58
+msgid "Title:"
+msgstr "Título:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:64
+msgid "Author:"
+msgstr "Autor:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:70
+msgid "Game types:"
+msgstr "Modos de jogo:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:93
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:296
+msgid "Close"
+msgstr "Fechar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:96
+msgid "MAP^Play"
+msgstr "Jogar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qh:7
+msgid "Map Information"
+msgstr "Informações do Mapa"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:28
+msgid "All Weapons Arena"
+msgstr "Arena com Todas as Armas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:30
+msgid "Most Weapons Arena"
+msgstr "Arena com Maior Parte das Armas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:49
+#, c-format
+msgid "%s Arena"
+msgstr "%s Arena"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:61
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:159
+msgid "Dodging"
+msgstr "Esquiva"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:63
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:267
+msgid "InstaGib"
+msgstr "InstaGib"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:65
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:216
+msgid "New Toys"
+msgstr "Novos Brinquedos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:67
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:272
+msgid "NIX"
+msgstr "NIX"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:69
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:220
+msgid "Rocket Flying"
+msgstr "Voar com Foguetes"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:71
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:212
+msgid "Invincible Projectiles"
+msgstr "Projéteis Invencíveis"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:75
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:282
+msgid "No start weapons"
+msgstr "Sem armas iniciais"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:77
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:195
+msgid "Low gravity"
+msgstr "Pouca gravidade"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:79
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:166
+msgid "Cloaked"
+msgstr "Oculto"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:81
+msgid "Hook"
+msgstr "Gancho"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:83
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:173
+msgid "Midair"
+msgstr "No ar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:87
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:224
+msgid "Piñata"
+msgstr "Piñata"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:89
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:229
+msgid "Weapons stay"
+msgstr "Armas permanescentes"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:91
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:184
+msgid "Blood loss"
+msgstr "Perda de sangue"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:93
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:208
+msgid "Jet pack"
+msgstr "Mochila a Jato"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:95
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:170
+msgid "Buffs"
+msgstr "Bônus (buffs)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:97
+msgid "Overkill"
+msgstr "Exagero"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:99
+msgid "No powerups"
+msgstr "Sem potencializadores"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:101
+msgid "Powerups"
+msgstr "Potencializadores"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:103
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:163
+msgid "Touch explode"
+msgstr "Toque explosivo"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:105
+msgid "MUT^None"
+msgstr "Nenhum"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:156
+msgid "Gameplay mutators:"
+msgstr "Modificadores de jogabilidade:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:160
+msgid "Enable dodging"
+msgstr "Habilitar esquiva"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:167
+msgid "All players are almost invisible"
+msgstr "Todos jogadores ficarão quase invisíveis"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:174
+msgid "Only possible to inflict damage on your enemy while he's airborne"
+msgstr ""
+"Só é possível causar dano aos seus inimigos enquanto eles estiverem no ar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:178
+msgid "Damage done to your enemy gets added to your own health"
+msgstr "O dano causado aos seus inimigos será adicionado à sua saúde"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:183
+msgid ""
+"Amount of health below which your player gets stunned because of blood loss"
+msgstr ""
+"Quantidade de saúde abaixo a qual o seu jogador permanecerá atordoado devido "
+"à perda de sangue"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:192
+msgid "Make things fall to the ground slower, lower value means lower gravity"
+msgstr ""
+"Faz com que as coisas caiam no chão mais devagar. Valores mais baixos "
+"significam gravidade mais baixa"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:201
+msgid "Weapon & item mutators:"
+msgstr "Modificadores de armas e itens:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:204
+msgid "Grappling hook"
+msgstr "Gancho de escalada"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:205
+msgid "Players spawn with the grappling hook"
+msgstr "Jogadores surgem com o gancho"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:209
+msgid "Players spawn with the jetpack"
+msgstr "Jogadores surgem com a mochila a jato"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:225
+msgid "Players will drop all weapons they possessed when they are killed"
+msgstr ""
+"Ao morrerem, jogadores irão deixar cair no chão todas as armas que tinham"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
+msgid "Weapons stay after they are picked up"
+msgstr "Armas permanecem no chão após serem coletadas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
+msgid "Regular (no arena)"
+msgstr "Normal (sem arena)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:237
+msgid "Weapon arenas:"
+msgstr "Arenas de armas:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:238
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:256
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:261
+msgid ""
+"Selecting a weapon arena will give all players that weapon at spawn as well "
+"as unlimited ammo, and disable all other weapon pickups."
+msgstr ""
+"Selecionar uma arena de armas concederá a todos os jogadores a arma "
+"selecionada ao surgirem bem como munição ilimitada. Todas as outras armas "
+"ficarão indisponíveis no mapa."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
+msgid "Most weapons"
+msgstr "Maior parte das armas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:260
+msgid "All weapons"
+msgstr "Todas as armas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:264
+msgid "Special arenas:"
+msgstr "Arenas especiais:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:268
+msgid ""
+"Players will be given only one weapon, which can instantly kill the opponent "
+"with a single shot. If the player runs out of ammo, he will have 10 seconds "
+"to find some or if he fails to do so, face death. The secondary fire mode "
+"does not inflict any damage but is good for doing trickjumps."
+msgstr ""
+"Os jogadores terão uma arma, a qual pode instantaneamente matar o oponente "
+"com um único disparo. Se o jogador ficar sem munição, ele terá 10 segundos "
+"para encontrar alguma e se não conseguir fazer isso, irá morrer. O modo de "
+"disparo secundário não causa nenhum dano, mas é útil para executar truques "
+"de movimento."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
+msgid ""
+"No items Xonotic - instead of pickup items, everyone plays with the same "
+"weapon. After some time, a countdown will start, after which everyone will "
+"switch to another weapon."
+msgstr ""
+"Sem itens Xonotic - em vez de pegar itens espalhados pelo mapa, todo mundo "
+"joga com a mesma arma. Depois de um certo tempo, uma contagem regressiva irá "
+"iniciar, e depois disso todos irão trocar para uma outra arma."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:277
+msgid "with blaster"
+msgstr "com blaster"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:278
+msgid "Always carry the blaster as an additional weapon in Nix"
+msgstr "Sempre carregue a blaster como uma arma adicional em Nix"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qh:9
+msgid "Mutators"
+msgstr "Modificadores"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:38
+msgid "SRVS^Categories"
+msgstr "Categorias"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:41
+msgid "SRVS^Empty"
+msgstr "Vazio"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:42
+msgid "Show empty servers"
+msgstr "Exibir servidores vazios"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:46
+msgid "SRVS^Full"
+msgstr "Cheio"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:47
+msgid "Show full servers that have no slots available"
+msgstr "Exibir servidores cheios que não contêm vagas disponíveis"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:51
+msgid "Pause"
+msgstr "Pausar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:52
+msgid ""
+"Pause updating the server list to prevent servers from \"jumping around\""
+msgstr ""
+"Pausa a atualização da lista de servidores para evitar que os servidores "
+"fiquem saindo do lugar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
+msgid "Reload the server list"
+msgstr "Atualizar a lista de servidores"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:67
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:223
+msgid "Address:"
+msgstr "Endereço:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:78
+msgid "Info..."
+msgstr "Informações..."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:79
+msgid "Show more information about the currently highlighted server"
+msgstr "Exibir mais informações sobre o servidor atualmente destacado"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:84
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:303
+msgid "Join!"
+msgstr "Conectar!"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:154
+#: qcsrc/menu/xonotic/serverlist.qc:1061
+msgid "MOD^Default"
+msgstr "Padrão"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+#, c-format
+msgid "%d modified"
+msgstr "%d modificadas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
+msgid "Official"
+msgstr "Oficial"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
+msgid "N/A (auth library missing, can't connect)"
+msgstr ""
+"N/A (biblioteca de autenticação não encontrada, não foi possível se conectar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:171
+msgid "N/A (auth library missing)"
+msgstr "N/A (biblioteca de autenticação não encontrada)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:177
+msgid "Not supported (can't connect)"
+msgstr "Não suportado (não foi possível se conectar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
+msgid "Not supported (won't encrypt)"
+msgstr "Não suportado (não encriptará)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:183
+msgid "Supported (will encrypt)"
+msgstr "Suportado (irá encriptar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:185
+msgid "Supported (won't encrypt)"
+msgstr "Suportado (não encriptará)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:189
+msgid "Requested (will encrypt)"
+msgstr "Solicitado (irá encriptar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:191
+msgid "Requested (won't encrypt)"
+msgstr "Solicitado (não encriptará)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:195
+msgid "Required (can't connect)"
+msgstr "Necessário (não foi possível se conectar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:197
+msgid "Required (will encrypt)"
+msgstr "Necessário (irá encriptar)"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:217
+msgid "Hostname:"
+msgstr "Servidor:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:231
+msgid "Gametype:"
+msgstr "Modo de jogo:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:236
+msgid "Map:"
+msgstr "Mapa:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:241
+msgid "Mod:"
+msgstr "Mod:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:246
+msgid "Version:"
+msgstr "Versão:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:251
+msgid "Settings:"
+msgstr "Configurações:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:258
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:290
+msgid "Players:"
+msgstr "Jogadores:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:263
+msgid "Bots:"
+msgstr "Bots:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:268
+msgid "Free slots:"
+msgstr "Vagas livres:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:274
+msgid "Encryption:"
+msgstr "Encriptação:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:279
+msgid "ID:"
+msgstr "ID:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:284
+msgid "Key:"
+msgstr "Chave:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh:7
+msgid "Server Information"
+msgstr "Informações do Servidor"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:25
+msgid "Demos"
+msgstr "Demos"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:26
+msgid "Screenshots"
+msgstr "Capturas de tela"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:27
+msgid "Music Player"
+msgstr "Reprodutor de Músicas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:48
+msgid "Auto record demos"
+msgstr "Gravar demos automaticamente"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:57
+msgid "Timedemo"
+msgstr "Executar benchmark"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:58
+msgid "Benchmark how fast your computer can run the highlighted demo"
+msgstr ""
+"Executa um teste de desempenho para saber quão rápido seu computador pode "
+"rodar a demo destacada"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:62
+msgid "DEMO^Play"
+msgstr "Reproduzir"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:13
+msgid "Playing a demo will disconnect you from the current match."
+msgstr "Reproduzir uma demo irá desconectar você da partida atual."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:15
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:15
+msgid "Do you really wish to disconnect now?"
+msgstr "Você realmente deseja desconectar agora?"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh:6
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qh:6
+msgid "Disconnect"
+msgstr "Desconectar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:13
+msgid "Timing a demo will disconnect you from the current match."
+msgstr "Executar benchmark em uma demo irá desconectá-lo da partida atual."
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:37
+msgid "MUSICPL^Add"
+msgstr "Adicionar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:40
+msgid "MUSICPL^Add all"
+msgstr "Adicionar todas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:44
+msgid "Set as menu track"
+msgstr "Definir como música do menu"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:48
+msgid "Reset default menu track"
+msgstr "Redefinir música padrão do menu"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:54
+msgid "Playlist:"
+msgstr "Lista de reprodução:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:55
+msgid "Random order"
+msgstr "Ordem aleatória"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:60
+msgid "MUSICPL^Stop"
+msgstr "Parar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:63
+msgid "MUSICPL^Play"
+msgstr "Tocar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:66
+msgid "MUSICPL^Pause"
+msgstr "Pausar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:69
+msgid "MUSICPL^Prev"
+msgstr "Anterior"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:72
+msgid "MUSICPL^Next"
+msgstr "Seguinte"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:76
+msgid "MUSICPL^Remove"
+msgstr "Remover"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:79
+msgid "MUSICPL^Remove all"
+msgstr "Remover todas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
+msgid "Auto screenshot scoreboard"
+msgstr "Tirar capturas de tela automaticamente do placar"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:63
+msgid "Open in the viewer"
+msgstr "Abrir no visualizador"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:139
+msgid "Reset"
+msgstr "Redefinir"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:144
+msgid "Previous"
+msgstr "Anterior"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:147
+msgid "Next"
+msgstr "Seguinte"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:152
+msgid "Slide show"
+msgstr "Apresentação de slides"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:34
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:21
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:37
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:25
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:20
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:21
+msgid "Apply immediately"
+msgstr "Aplicar imediatamente"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
+msgid "Name"
+msgstr "Nome"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:77
+msgid "Model"
+msgstr "Modelo"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:96
+msgid "Glowing color"
+msgstr "Cor brilhante"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:106
+msgid "Detail color"
+msgstr "Cor do detalhe"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:121
+msgid "Statistics"
+msgstr "Estatísticas"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:125
+msgid "Allow player statistics to track your client"
+msgstr "Permitir que as estatísticas de jogadores rastreiem o seu cliente"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:129
+msgid "Allow player statistics to use your nickname"
+msgstr "Permitir que as estatísticas de jogadores usem o seu apelido"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
+msgid "Country"
+msgstr "Idioma"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
+msgid "Gender:"
+msgstr "Gênero:"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:161
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:174
+msgid "Undisclosed"
+msgstr "Não revelado"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:162
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:172
+msgid "Female"
+msgstr "Feminino"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:163
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:173
+msgid "Male"
+msgstr "Masculino"
+
+#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:166
+msgid "Gender"
+msgstr "Gênero"
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:11
+msgid "Are you sure you want to quit?"
+msgstr "Tem certeza de que deseja sair?"
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:15
+msgid "Back to work..."
+msgstr "De volta ao trabalho..."
+
+#: qcsrc/menu/xonotic/dialog_quit.qc:17
+msgid "I got some more fragging to do!"
+msgstr "Está na hora das execuções!"
+
+#: qcsrc/menu/xonotic/dialog_quit.qh:7
+msgid "Quit the game"
+msgstr "Sair do jogo"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:15
+msgid "Model:"
+msgstr "Modelo:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:21
+msgid "Remove *"
+msgstr "Remover *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:23
+msgid "Copy *"
+msgstr "Copiar *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:24
+msgid "Paste"
+msgstr "Colar"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:26
+msgid "Bone:"
+msgstr "Osso:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:31
+msgid "Set * as child"
+msgstr "Definir * como criança"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:32
+msgid "Attach to *"
+msgstr "Anexar à *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:34
+msgid "Detach from *"
+msgstr "Separar de *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:37
+msgid "Visual object properties for *:"
+msgstr "Propriedades de objeto visual para *:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:41
+msgid "Set alpha:"
+msgstr "Definir alfa:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:44
+msgid "Set color main:"
+msgstr "Definir cor principal:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:46
+msgid "Set color glow:"
+msgstr "Definir cor do brilho:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:50
+msgid "Set frame:"
+msgstr "Definir frame:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:54
+msgid "Physical object properties for *:"
+msgstr "Propriedades de objeto físico para *:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:56
+msgid "Set material:"
+msgstr "Definir material:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:62
+msgid "Set solidity:"
+msgstr "Definir solidez:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:63
+msgid "Non-solid"
+msgstr "Não sólido"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:64
+msgid "Solid"
+msgstr "Sólido"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:65
+msgid "Set physics:"
+msgstr "Definir física:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:66
+msgid "Static"
+msgstr "Estática"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:67
+msgid "Movable"
+msgstr "Movível"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:68
+msgid "Physical"
+msgstr "Físico"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:70
+msgid "Set scale:"
+msgstr "Definir escala:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:72
+msgid "Set force:"
+msgstr "Definir força:"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:76
+msgid "Claim *"
+msgstr "Resgatar *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:78
+msgid "* object info"
+msgstr "Informações de objeto *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:79
+msgid "* mesh info"
+msgstr "Informações de malha *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:80
+msgid "* attachment info"
+msgstr "Informações de extras *"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:81
+msgid "Show help"
+msgstr "Exibir ajuda"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:82
+msgid "* is the object you are facing"
+msgstr "* é o objeto para o qual você está virado"
+
+#: qcsrc/menu/xonotic/dialog_sandboxtools.qh:6
+msgid "Sandbox Tools"
+msgstr "Ferramentas Sandbox"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:18
+msgid "Video"
+msgstr "Vídeo"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:19
+msgid "Effects"
+msgstr "Efeitos"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:20
+msgid "Audio"
+msgstr "Áudio"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:22
+msgid "Game"
+msgstr "Jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:23
+msgid "Input"
+msgstr "Entrada"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:24
+msgid "User"
+msgstr "Usuário"
+
+#: qcsrc/menu/xonotic/dialog_settings.qc:25
+#: qcsrc/menu/xonotic/keybinder.qc:105
+msgid "Misc"
+msgstr "Diversos"
+
+#: qcsrc/menu/xonotic/dialog_settings.qh:6
+msgid "Settings"
+msgstr "Configurações"
+
+#: qcsrc/menu/xonotic/dialog_settings.qh:7
+msgid "Change the game settings"
+msgstr "Altere as configurações do jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
+msgid "Master:"
+msgstr "Principal:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:35
+msgid "Music:"
+msgstr "Música:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:43
+msgid "VOL^Ambient:"
+msgstr "Ambiente:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:50
+msgid "Info:"
+msgstr "Informação:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:57
+msgid "Items:"
+msgstr "Itens:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:64
+msgid "Pain:"
+msgstr "Dor:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:71
+msgid "Player:"
+msgstr "Jogador:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:78
+msgid "Shots:"
+msgstr "Disparos:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:85
+msgid "Voice:"
+msgstr "Voz:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:93
+msgid "Weapons:"
+msgstr "Armas:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:99
+msgid "New style sound attenuation"
+msgstr "Novo estilo de atenuação de som"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:102
+msgid "Mute sounds when not active"
+msgstr "Desabilita o som enquanto estiver em segundo plano"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:105
+msgid "Frequency:"
+msgstr "Frequência:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:107
+msgid "Sound output frequency"
+msgstr "Frequência da saída de som"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:108
+msgid "8 kHz"
+msgstr "8 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:109
+msgid "11.025 kHz"
+msgstr "11.025 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:110
+msgid "16 kHz"
+msgstr "16 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:111
+msgid "22.05 kHz"
+msgstr "22.05 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:112
+msgid "24 kHz"
+msgstr "24 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:113
+msgid "32 kHz"
+msgstr "32 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:114
+msgid "44.1 kHz"
+msgstr "44.1 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:115
+msgid "48 kHz"
+msgstr "48 kHz"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:119
+msgid "Channels:"
+msgstr "Canais:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:121
+msgid "Number of channels for the sound output"
+msgstr "Número de canais para a saída de som"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:122
+msgid "Mono"
+msgstr "Mono"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:123
+msgid "Stereo"
+msgstr "Estéreo"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:124
+msgid "2.1"
+msgstr "2.1"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:125
+msgid "4"
+msgstr "4"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:126
+msgid "5"
+msgstr "5"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:127
+msgid "5.1"
+msgstr "5.1"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:128
+msgid "6.1"
+msgstr "6.1"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:129
+msgid "7.1"
+msgstr "7.1"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:134
+msgid "Swap stereo output channels"
+msgstr "Trocar canais de saída estéreo de lugar"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:135
+msgid "Swap left/right channels"
+msgstr "Troca de lugar os canais esquerdo e direito"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:138
+msgid "Headphone friendly mode"
+msgstr "Modo de fones de ouvido"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:139
+msgid ""
+"Enable spatialization (blend the right and left channel slightly to decrease "
+"stereo separation a bit for headphones)"
+msgstr ""
+"Habilita espacialização (combina levemente os canais esquerdo e direito para "
+"diminuir um pouco a separação de estéreo para fones de ouvido)"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:143
+msgid "Hit indication sound"
+msgstr "Som indicador de disparo acertado"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:144
+msgid "Play a hit indicator sound when your shot hits an enemy"
+msgstr "Reproduz um som indicando que você acertou um inimigo"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:147
+msgid "Chat message sound"
+msgstr "Som de mensagem do bate-papo"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:149
+msgid "Menu sounds"
+msgstr "Sons do menu"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:150
+msgid "Play sounds when clicking menu items"
+msgstr "Reproduz sons quando você clica nas opções do menu"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:151
+msgid "Focus sounds"
+msgstr "Sons de foco"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:152
+msgid "Play sounds when hovering over menu items too"
+msgstr "Reproduz sons quando você passa o mouse sobre as opções do menu também"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:156
+msgid "Time announcer:"
+msgstr "Aviso de tempo:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:158
+msgid "WRN^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:160
+msgid "5 minutes"
+msgstr "5 minutos"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:161
+msgid "WRN^Both"
+msgstr "Ambos"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:164
+msgid "Automatic taunts:"
+msgstr "Provocações automáticas:"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:166
+msgid "Automatically taunt enemies after fragging them"
+msgstr "Provocar inimigos automaticamente depois de executá-los"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
+msgid "Sometimes"
+msgstr "Às vezes"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:169
+msgid "Often"
+msgstr "Frequentemente"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:170
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:141
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:57
+msgid "Always"
+msgstr "Sempre"
+
+#: qcsrc/menu/xonotic/dialog_settings_audio.qc:176
+msgid "Debug info about sounds"
+msgstr "Depurar informações sobre sons"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:41
+msgid "Quality preset:"
+msgstr "Predefinição de qualidade:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:45
+msgid "PRE^OMG!"
+msgstr "MEU DEUS!"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:48
+msgid "PRE^Low"
+msgstr "Baixa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:50
+msgid "PRE^Medium"
+msgstr "Média"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:52
+msgid "PRE^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:54
+msgid "PRE^High"
+msgstr "Alta"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:56
+msgid "PRE^Ultra"
+msgstr "Ultra"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:60
+msgid "PRE^Ultimate"
+msgstr "Máxima"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:65
+msgid "Geometry detail:"
+msgstr "Detalhes da geometria:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:67
+msgid "Change the smoothness of the curves on the map (default: normal)"
+msgstr "Altera a suavização das curvas no mapa (padrão: normal)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:68
+msgid "DET^Lowest"
+msgstr "Mínimo"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:69
+msgid "DET^Low"
+msgstr "Baixo"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:70
+msgid "DET^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:71
+msgid "DET^Good"
+msgstr "Bom"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:72
+msgid "DET^Best"
+msgstr "Melhor"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:73
+msgid "DET^Insane"
+msgstr "Insano"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:77
+msgid "Player detail:"
+msgstr "Detalhes do jogador:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:79
+msgid "PDET^Low"
+msgstr "Baixo"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:80
+msgid "PDET^Medium"
+msgstr "Médio"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:81
+msgid "PDET^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:82
+msgid "PDET^Good"
+msgstr "Bom"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:83
+msgid "PDET^Best"
+msgstr "Melhor"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:87
+msgid "Texture resolution:"
+msgstr "Resolução das texturas:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:91
+msgid "RES^Leet"
+msgstr "Elite"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:92
+msgid "RES^Lowest"
+msgstr "Mínima"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:93
+msgid "RES^Very low"
+msgstr "Muito baixa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:94
+msgid "RES^Low"
+msgstr "Baixa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:95
+msgid "RES^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:96
+msgid "RES^Good"
+msgstr "Boa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:97
+msgid "RES^Best"
+msgstr "Melhor"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:110
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:115
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:120
+msgid "Avoid lossy texture compression"
+msgstr "Evitar compressão de texturas com perdas"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:131
+msgid "Show surfaces"
+msgstr "Exibir superfícies"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:132
+msgid ""
+"Disable textures completely for very slow hardware. This gives a huge "
+"performance boost, but looks very ugly. (default: disabled)"
+msgstr ""
+"Desabilita completamente as texturas para PCs de baixo desempenho. Isso "
+"garante uma alto ganho de desempenho, mas deixa o jogo muito feio. (padrão: "
+"desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:135
+msgid "Use lightmaps"
+msgstr "Usar lightmaps"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:136
+msgid ""
+"Use high resolution lightmaps, which will look pretty but use up some extra "
+"video memory (default: enabled)"
+msgstr ""
+"Usa lightmaps de alta resolução, os quais ficarão elegantes, mas irão usar "
+"um pouco mais de memória (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:138
+msgid "Deluxe mapping"
+msgstr "Mapeamento deluxe"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:139
+msgid "Use per-pixel lighting effects (default: enabled)"
+msgstr "Usa efeitos de iluminação por pixel (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:141
+msgid "Gloss"
+msgstr "Lustro"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:142
+msgid ""
+"Enable the use of glossmaps on textures supporting it (default: enabled)"
+msgstr ""
+"Habilita o uso de glossmaps em texturas que suportam esse recurso (padrão: "
+"habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:145
+msgid "Offset mapping"
+msgstr "Mapeamento por paralaxe"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:146
+msgid ""
+"Offset mapping effect that will make textures with bumpmaps appear like they "
+"\"pop out\" of the flat 2D surface (default: disabled)"
+msgstr ""
+"Efeito de mapeamento por paralaxe que fará as texturas com bumpmaps "
+"parecerem que estão \"saindo\" da superfície plana em 2D (padrão: "
+"desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:148
+msgid "Relief mapping"
+msgstr "Mapeamento de relevo"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:149
+msgid ""
+"Higher quality offset mapping, which also has a huge impact on performance "
+"(default: disabled)"
+msgstr ""
+"Mapeamento por paralaxe de maior qualidade, o qual também causa um grande "
+"impacto no desempenho (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:152
+msgid "Reflections:"
+msgstr "Reflexos:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:153
+msgid ""
+"Reflection and refraction quality, has a huge impact on performance on maps "
+"with reflecting surfaces (default: disabled)"
+msgstr ""
+"Qualidade de reflexos e refrações. Causa um grande impacto no desempenho em "
+"mapas que contenham superfícies com reflexos (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:156
+msgid "Resolution of reflections/refractions (default: good)"
+msgstr "Resolução dos reflexos e refrações (padrão: boa)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:157
+msgid "Blurred"
+msgstr "Borrados"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:158
+msgid "REFL^Good"
+msgstr "Boa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:159
+msgid "Sharp"
+msgstr "Alta"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:163
+msgid "Decals"
+msgstr "Decalques"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:164
+msgid "Enable decals (bullet holes and blood) (default: enabled)"
+msgstr "Habilita decalques (buracos de bala e sangue) (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:165
+msgid "Decals on models"
+msgstr "Decalques em modelos"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:169
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:253
+msgid "Distance:"
+msgstr "Distância:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:172
+msgid "Decals further away than this will not be drawn (default: 300)"
+msgstr "Decalques mais distantes que isso não serão desenhados (padrão: 300)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:176
+msgid "Time:"
+msgstr "Tempo:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:179
+msgid "Time in seconds before decals fade away (default: 2)"
+msgstr "Tempo em segundos antes de decalques desaparecerem (padrão: 2)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:183
+msgid "Damage effects:"
+msgstr "Efeitos de dano:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:185
+msgid "DMGFX^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:186
+msgid "Skeletal"
+msgstr "Esquelético"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:187
+msgid "DMGFX^All"
+msgstr "Todos"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:191
+msgid "No dynamic lighting"
+msgstr "Desabilitar iluminação dinâmica"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:192
+msgid "Enable corona flares around certain lights (default: enabled)"
+msgstr "Habilita luzes de corona ao redor de certas luzes (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:194
+msgid "Fake corona lighting"
+msgstr "Iluminação de coronas falsa"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:195
+msgid ""
+"Enable faster but uglier dynamic lights by rendering bright coronas instead "
+"of real dynamic lights (default: disabled)"
+msgstr ""
+"Habilita luzes dinâmicas mais rápidas porém mais feias renderizando coronas "
+"brilhantes em vez de luzes dinâmicas reais (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:198
+msgid "Realtime dynamic lighting"
+msgstr "Iluminação dinâmica em tempo real"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:199
+msgid ""
+"Enable rendering of dynamic lights such as explosions and rocket lights "
+"(default: enabled)"
+msgstr ""
+"Habilita a renderização de luzes dinâmicas como explosões e luzes de "
+"foguetes (padrão: habilitada)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:201
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:207
+msgid "Shadows"
+msgstr "Sombras"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:202
+msgid "Enable rendering of shadows from dynamic lights (default: disabled)"
+msgstr ""
+"Habilita a renderização de sombras a partir de luzes dinâmicas (padrão: "
+"desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:205
+msgid "Realtime world lighting"
+msgstr "Iluminação de mundo em tempo real"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:206
+msgid ""
+"Enable rendering of full realtime world lighting on maps that support it. "
+"Note that this might have a big impact on performance. (default: disabled)"
+msgstr ""
+"Habilita a renderização de iluminação de mundo em tempo real em mapas que a "
+"suportam. Note que isso pode causar um grande impacto no desempenho (padrão: "
+"desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:208
+msgid ""
+"Enable rendering of shadows from realtime world lights (default: disabled)"
+msgstr ""
+"Habilita a renderização de sombras de luzes de mundo em tempo real (padrão: "
+"desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:212
+msgid "Use normal maps"
+msgstr "Usar normal maps"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:213
+msgid "Enable use of directional shading on textures (default: enabled)"
+msgstr "Habilita o uso de shaders direcionais em texturas (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:215
+msgid "Soft shadows"
+msgstr "Sombras suaves"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:219
+msgid "Fade corona according to visibility"
+msgstr "Enfraquecer corona de acordo com a visibilidade"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:220
+msgid "Fade coronas according to visibility (default: enabled)"
+msgstr "Enfraquece coronas de acordo com a visibilidade (padrão: habilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:224
+msgid "Bloom"
+msgstr "Bloom"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:225
+msgid ""
+"Enable bloom effect, which brightens the neighboring pixels of very bright "
+"pixels. Has a big impact on performance. (default: disabled)"
+msgstr ""
+"Habilita o efeito bloom, o qual ilumina os pixeis próximos de pixeis muito "
+"brilhantes. Causa um grande impacto no desempenho (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:226
+msgid "Extra postprocessing effects"
+msgstr "Efeitos extras de pós-processamento"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:227
+msgid ""
+"Enables special postprocessing effects for when damaged or under water or "
+"using a powerup (default: disabled)"
+msgstr ""
+"Habilita efeitos especiais de pós-processamento para quando receber dano, "
+"estar debaixo d'água ou ao usar potencializadores (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:232
+msgid "Motion blur strength - 0.4 recommended"
+msgstr "Intensidade do desfoque de movimento - 0.4 recomendado"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:233
+msgid "Motion blur:"
+msgstr "Desfoque de movimento:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
+msgid "Particles"
+msgstr "Partículas"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:240
+msgid "Spawnpoint effects"
+msgstr "Efeitos de ponto de surgimento"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:241
+msgid "Particles effects at all spawn points and whenever a player spawns"
+msgstr ""
+"Efeitos de partículas em todos os pontos de surgimento e sempre que um "
+"jogador nascer"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:246
+msgid "Quality:"
+msgstr "Qualidade:"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:249
+msgid ""
+"Multiplier for amount of particles. Less means less particles, which in turn "
+"gives for better performance (default: 1.0)"
+msgstr ""
+"Multiplicador para a quantidade de partículas. Menos significa menos "
+"partículas, o que resulta em um melhor desempenho (padrão: 1.0)"
+
+#: qcsrc/menu/xonotic/dialog_settings_effects.qc:256
+msgid "Particles further away than this will not be drawn (default: 1000)"
+msgstr "Partículas mais distantes que isso não serão desenhadas (padrão: 1000)"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:31
+msgid "No crosshair"
+msgstr "Sem retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:33
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:62
+msgid "Per weapon"
+msgstr "Por arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:34
+msgid ""
+"Set a different crosshair for each weapon, good if you play without weapon "
+"models"
+msgstr ""
+"Define um retículo diferente para cada uma das armas, uma boa opção caso "
+"você jogue sem os modelos das armas na tela"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:48
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:81
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:97
+msgid "Size:"
+msgstr "Tamanho:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:64
+msgid "By health"
+msgstr "Por saúde"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:76
+msgid "Use rings to indicate weapon status"
+msgstr "Usar anéis para indicar status da arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:93
+msgid "Enable center crosshair dot"
+msgstr "Habilitar ponto no centro do retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:111
+msgid "Use normal crosshair color"
+msgstr "Usa cor normal do retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:122
+msgid "Smooth effects of crosshairs"
+msgstr "Suavizar efeitos dos retículos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:125
+msgid "Hit testing:"
+msgstr "Teste de acerto:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:128
+msgid ""
+"None: do not do hit tests for the crosshair; TrueAim: blur the crosshair "
+"when there's an obstacle between your gun and the target; Enemies: also "
+"enlarge the crosshair when you would hit an enemy"
+msgstr ""
+"Nenhum: não realiza testes de acerto para o retículo; Retículo Real: desfoca "
+"o retículo quando há um obstáculo entre a sua arma e o alvo; Inimigos: o "
+"retículo também é ampliado quando você acertaria um inimigo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:129
+msgid "HTTST^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:130
+msgid "HTTST^TrueAim"
+msgstr "Mira Real"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:131
+msgid "HTTST^Enemies"
+msgstr "Inimigos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:136
+msgid "Blur crosshair if the shot is obstructed"
+msgstr "Borrar retículo se o disparo for obstruído"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:140
+msgid "Enlarge crosshair if targeting an enemy"
+msgstr "Ampliar retículo ao focar em um inimigo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:143
+msgid "Animate crosshair when hitting an enemy"
+msgstr "Animar retículo ao acertar um inimigo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:146
+msgid "Animate crosshair when picking up an item"
+msgstr "Animar retículo ao pegar um item"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh:7
+msgid "Crosshair"
+msgstr "Retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:48
+msgid "Fading speed:"
+msgstr "Vel. de desaparecimento:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:51
+msgid "Enable rows / columns highlighting"
+msgstr "Habilitar destacamento de fileiras/colunas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:55
+msgid "Show decimals in respawn countdown"
+msgstr "Exibir decimais na contagem de ressurgimento"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
+msgid "Show accuracy underneath scoreboard"
+msgstr "Exibir precisão embaixo do placar"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
+msgid "Waypoints"
+msgstr "Caminhos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:63
+msgid "Display waypoint markers for objectives on the map"
+msgstr "Mostra os marcadores de caminhos para objetivos no mapa"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:64
+msgid "Show various gametype specific waypoints"
+msgstr "Mostra diversos caminhos específicos de modos de jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:70
+msgid "Control transparency of the waypoints"
+msgstr "Transparência dos caminhos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:74
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:124
+msgid "Fontsize:"
+msgstr "Tamanho da fonte:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:80
+msgid "Edge offset:"
+msgstr "Extremidade:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:89
+msgid "Fade when near the crosshair"
+msgstr "Desvanecer ao se aproximar do retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:94
+msgid "Damage"
+msgstr "Dano"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:96
+msgid "Overlay:"
+msgstr "Sobreposição:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:99
+msgid "Factor:"
+msgstr "Fator:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:104
+msgid "Fade rate:"
+msgstr "Taxa de desaparecimento:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:112
+msgid "Player Names"
+msgstr "Nomes de Jogadores"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:114
+msgid "Show names above players"
+msgstr "Exibir nomes sobre jogadores"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:130
+msgid "Max distance:"
+msgstr "Distância máxima:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:136
+msgid "Decolorize:"
+msgstr "Descoloração:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:140
+#: qcsrc/menu/xonotic/keybinder.qc:99
+msgid "Teamplay"
+msgstr "Equipe"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:148
+msgid "Only when near crosshair"
+msgstr "Apenas quando próximo ao retículo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
+msgid "Display health and armor"
+msgstr "Exibir saúde e armadura"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:157
+msgid "Damage overlay:"
+msgstr "Sobreposição do dano:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:160
+msgid "Dynamic HUD"
+msgstr "HUD dinâmico"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:161
+msgid "HUD moves around following player's movement"
+msgstr "O HUD se move de acordo com o movimento do jogador"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:163
+msgid "Shake the HUD when hurt"
+msgstr "Vibrar o HUD ao ser atingido"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:167
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qh:6
+msgid "Enter HUD editor"
+msgstr "Entrar no editor do HUD"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
+msgid "HUD"
+msgstr "HUD"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:21
+msgid "In order for the HUD editor to show, you must first be in game."
+msgstr "Para o editor do HUD aparecer, é necessário estar jogando em um mapa."
+
+#: qcsrc/menu/xonotic/dialog_settings_game_hudconfirm.qc:23
+msgid "Do you wish to start a local game to set up the HUD?"
+msgstr "Quer iniciar um jogo local para personalizar o HUD?"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:24
+msgid "Frag Information"
+msgstr "Informações de Execuções"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:26
+msgid "Display information about killing sprees"
+msgstr "Exibir informação sobre sequências de mortes"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:29
+msgid "Only display sprees if they are achievements"
+msgstr "Apenas exibir sequências se forem conquistas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:34
+msgid "Show spree information in centerprints"
+msgstr "Exibir informação de sequências em impressões centrais"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:38
+msgid "Show spree information in death messages"
+msgstr "Exibir informação de sequências em mensagens de morte"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:43
+msgid "Sprees in info messages:"
+msgstr "Sequências em mensagens de informação:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
+msgid "SPREES^Disabled"
+msgstr "Desabilitadas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
+msgid "Target"
+msgstr "Alvo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:48
+msgid "Attacker"
+msgstr "Atacante"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:49
+msgid "SPREES^Both"
+msgstr "Ambos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:55
+msgid "Print on a seperate line"
+msgstr "Imprimir numa linha separada"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:58
+msgid "Add extra frag information to centerprint when available"
+msgstr ""
+"Adicionar informações extras de execução à impressão central quando "
+"disponível"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
+msgid "Add frag location to death messages when available"
+msgstr ""
+"Adicionar localização de execução nas mensagens de morte quando disponível"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:65
+msgid "Gamemode Settings"
+msgstr "Configurações do Modo de Jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:67
+msgid "Display capture times in Capture The Flag"
+msgstr "Exibir tempos de captura em Capture a Bandeira"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:71
+msgid "Display name of flag stealer in Capture The Flag"
+msgstr "Exibir nome do ladrão da bandeira em Capture a Bandeira"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:76
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:91
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:133
+msgid "Other"
+msgstr "Outros"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
+msgid "Display console messages in the top left corner"
+msgstr "Exibir mensagens de console no canto superior esquerdo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
+msgid "Display all info messages in the chatbox"
+msgstr "Exibir todas as mensagens de informação no bate-papo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
+msgid "Display player statuses in the chatbox"
+msgstr "Exibir status de jogadores no bate-papo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
+msgid "Powerup notifications"
+msgstr "Notificações de potencializador"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
+msgid "Weapon centerprint notifications"
+msgstr "Notificações centrais de armas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:92
+msgid "Weapon info message notifications"
+msgstr "Notificações de informação de arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:96
+msgid "Announcers"
+msgstr "Locutores"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:98
+msgid "Respawn countdown sounds"
+msgstr "Sons da contagem de ressurgimento"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:101
+msgid "Killstreak sounds"
+msgstr "Sons de sequências de mortes"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:104
+msgid "Achievement sounds"
+msgstr "Sons de conquistas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
+msgid "Messages"
+msgstr "Mensagens"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
+msgid "Items"
+msgstr "Itens"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:32
+msgid "Use simple 2D images instead of item models"
+msgstr "Usar imagens 2D simples em vez de modelos de itens"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:34
+msgid "Unavailable alpha:"
+msgstr "Alfa indisponível:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:37
+msgid "Unavailable color:"
+msgstr "Cor indisponível:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:39
+msgid "GHOITEMS^Black"
+msgstr "Preto"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:40
+msgid "GHOITEMS^Dark"
+msgstr "Escuro"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:41
+msgid "GHOITEMS^Tinted"
+msgstr "Pintado"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:42
+msgid "GHOITEMS^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:43
+msgid "GHOITEMS^Blue"
+msgstr "Azul"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:49
+#: qcsrc/menu/xonotic/serverlist.qc:767
+msgid "Players"
+msgstr "Jogadores"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:51
+msgid "Force player models to mine"
+msgstr "Forçar modelos dos jogadores para ficarem iguais ao meu"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:53
+msgid "Force player colors to mine"
+msgstr "Forçar cores de jogadores para ficarem iguais às minhas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:56
+msgid "In non teamplay modes only"
+msgstr "Apenas em modos de jogo que não sejam de equipes"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
+msgid "Body fading:"
+msgstr "Desaparecimento de corpos:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:63
+msgid "Gibs:"
+msgstr "Tripas:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:65
+msgid "GIBS^None"
+msgstr "Desabilitadas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:66
+msgid "GIBS^Few"
+msgstr "Poucas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:67
+msgid "GIBS^Many"
+msgstr "Muitas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:68
+msgid "GIBS^Lots"
+msgstr "Excessivas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qh:7
+msgid "Models"
+msgstr "Modelos"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_model.qh:8
+msgid "Customize how players and items are displayed in game"
+msgstr "Personalize como jogadores e itens são exibidos dentro do jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:26
+msgid "1st person perspective"
+msgstr "Perspectiva em 1ª pessoa"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:30
+msgid "Slide to third person upon death"
+msgstr "Mudar para terceira pessoa depois de morrer"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:34
+msgid "Smooth the view when landing from a jump"
+msgstr "Suavizar a visão quando aterrissar de um salto"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:38
+msgid "Smooth the view while crouching"
+msgstr "Suavizar a visão quando estiver agachado"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:42
+msgid "View waving while idle"
+msgstr "Ver acenos quando ausente"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:46
+msgid "View bobbing while walking around"
+msgstr "Oscilação de visão ao andar"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:51
+msgid "3rd person perspective"
+msgstr "Perspectiva em 3ª pessoa"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:55
+msgid "Back distance"
+msgstr "Distância das costas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:61
+msgid "Up distance"
+msgstr "Distância para cima"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:67
+msgid "Allow passing through walls while spectating"
+msgstr "Atravessar paredes quando estiver de espectador"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:70
+msgid "Field of view:"
+msgstr "Campo de visão:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:72
+msgid "Field of vision in degrees (default: 100)"
+msgstr "Campo de visão em graus (padrão: 100)"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:76
+msgid "ZOOM^Zoom factor:"
+msgstr "Fator do zoom:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:78
+msgid "How big the zoom factor is when the zoom button is pressed"
+msgstr ""
+"Quão grande o fator do zoom será quando o botão de zoom for pressionado"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:81
+msgid "ZOOM^Zoom speed:"
+msgstr "Velocidade do zoom:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:83
+msgid "How fast the view will be zoomed, disable to zoom instantly"
+msgstr "Quão rápido será o zoom da visão, desabilite para zoom instantâneo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:92
+msgid "ZOOM^Instant"
+msgstr "Instantâneo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:96
+msgid "ZOOM^Zoom sensitivity:"
+msgstr "Sensibilidade do zoom:"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:98
+msgid ""
+"How zoom changes sensitivity, from 0 (lower sensitivity) to 1 (no "
+"sensitivity change)"
+msgstr ""
+"Como o zoom altera a sensibilidade, a partir do valor 0 (sensibilidade mais "
+"baixa) até 1 (sem alterações na sensibilidade)"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:101
+msgid "Velocity zoom"
+msgstr "Zoom baseado na velocidade"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:102
+msgid "Forward movement only"
+msgstr "Apenas ao movimentar-se para frente"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:106
+msgid "VZOOM^Factor"
+msgstr "Fator"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:113
+msgid "Display reticle 2D overlay while zooming"
+msgstr "Exibe uma sobreposição reticular em 2D durante o zoom"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:116
+msgid "Release zoom when you die or respawn"
+msgstr "Soltar o zoom quando você morre ou ressurge"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:120
+msgid "Release zoom when you switch weapons"
+msgstr "Soltar o zoom quando você troca de arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_view.qh:7
+#: qcsrc/menu/xonotic/keybinder.qc:76
+msgid "View"
+msgstr "Visão"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:34
+msgid "Weapon Priority List (* = mutator weapon)"
+msgstr "Lista de Prioridade de Armas (* = arma de modificador)"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:40
+msgid "Up"
+msgstr "Mover para cima"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:44
+msgid "Down"
+msgstr "Mover para baixo"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:50
+msgid "Use priority list for weapon cycling"
+msgstr "Usar lista de prioridades como ordem de alternação de armas"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:51
+msgid ""
+"Make use of the list above when cycling through weapons with the mouse wheel"
+msgstr ""
+"Faz uso da lista acima durante a alternação de armas com a roda do mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:53
+msgid "Cycle through only usable weapon selections"
+msgstr "Alterne somente entre armas utilizáveis"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:57
+msgid "Auto switch weapons on pickup"
+msgstr "Trocar para a arma coletada automaticamente"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:58
+msgid ""
+"Automatically switch to newly picked up weapons if they are better than what "
+"you are carrying"
+msgstr ""
+"Alterna automaticamente para a arma coletada caso ela seja melhor do que a "
+"que você está carregando"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:61
+msgid "Release attack buttons when you switch weapons"
+msgstr "Soltar os botões de ataque durante a troca de arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:64
+msgid "Draw 1st person weapon model"
+msgstr "Renderizar modelo de arma em 1ª pessoa"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:65
+msgid "Draw the weapon model"
+msgstr "Exibe os modelos das armas em sua tela"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:69
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:72
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:75
+msgid "Position of the weapon model; requires reconnect"
+msgstr "Posicionamento do modelo de arma; é preciso reconectar-se"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:80
+msgid "Gun model swaying"
+msgstr "Mover modelo de arma ao mover o mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:85
+msgid "Gun model bobbing"
+msgstr "Oscilar modelo de arma"
+
+#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qh:7
+#: qcsrc/menu/xonotic/keybinder.qc:43
+msgid "Weapons"
+msgstr "Armas"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:33
+msgid "Key Bindings"
+msgstr "Teclas de Atalho"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:37
+msgid "Change key..."
+msgstr "Alterar botão..."
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:41
+msgid "Edit..."
+msgstr "Editar..."
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:47
+msgid "Clear"
+msgstr "Limpar"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:52
+msgid "Reset all"
+msgstr "Redefinir tudo"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:57
+msgid "Mouse"
+msgstr "Mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:59
+msgid "Sensitivity:"
+msgstr "Sensibilidade:"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:61
+msgid "Mouse speed multiplier"
+msgstr "Multiplicador da velocidade do mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:63
+msgid "Smooth aiming"
+msgstr "Suavizar mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:64
+msgid "Smoothes the mouse movement, but makes aiming slightly less responsive"
+msgstr ""
+"Suaviza os movimentos do mouse, mas torna a mira levemente menos responsiva"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:66
+msgid "Invert aiming"
+msgstr "Inverter mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:67
+msgid "Invert mouse movement on the Y-axis"
+msgstr "Inverter eixo Y do movimento do mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:69
+msgid "Use system mouse positioning"
+msgstr "Usar posicionamento de mouse do sistema"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:74
+msgid "Enable built in mouse acceleration"
+msgstr "Habilitar aceleração de mouse imbutida"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:78
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:82
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:85
+msgid "Disable system mouse acceleration"
+msgstr "Desabilitar aceleração de mouse do SO"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:79
+msgid "Make use of DGA mouse input"
+msgstr "Fazer uso da entrada DGA de mouse"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:93
+msgid "Pressing \"enter console\" key also closes it"
+msgstr " Pressionar \"abrir console\" também o fecha"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:94
+msgid "Allow the console toggling bind to also close the console"
+msgstr "Permite que o atalho para abrir o console também feche-o"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:96
+msgid "Automatically repeat jumping if holding jump"
+msgstr " Saltar continuamente ao segurar o botão de saltar"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:99
+msgid "Jetpack on jump:"
+msgstr "Mochila a jato ao saltar:"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:101
+msgid "JPJUMP^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:102
+msgid "Air only"
+msgstr "Somente no ar"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:103
+msgid "JPJUMP^All"
+msgstr "Todos"
+
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:109
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:114
+#: qcsrc/menu/xonotic/dialog_settings_input.qc:119
+msgid "Use joystick input"
+msgstr "Usar entrada de gamepad"
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:31
+msgid "Command when pressed:"
+msgstr "Comando quando pressionado:"
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:34
+msgid "Command when released:"
+msgstr "Comando quando largado:"
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:40
+msgid "Cancel"
+msgstr "Cancelar"
+
+#: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
+msgid "User defined key bind"
+msgstr "Botão de atalho definido pelo usuário"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:11
+#, c-format
+msgid "%d fps"
+msgstr "%d fps"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:12
+#, c-format
+msgid "%d KB/s"
+msgstr "%d KB/s"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:13
+#, c-format
+msgid "%d MB/s"
+msgstr "%d MB/s"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:27
+msgid "Network"
+msgstr "Rede"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:29
+msgid "Client UDP port:"
+msgstr "Porta UDP do cliente:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:31
+msgid "Force client to use chosen port unless it is set to 0"
+msgstr ""
+"Força os clientes a utilizarem as portas escolhidas a menos que esteja "
+"definido como 0"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
+msgid "Bandwidth:"
+msgstr "Largura de banda:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:36
+msgid "Specify your network speed"
+msgstr "Especifique a velocidade da sua rede"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
+msgid "56k"
+msgstr "56k"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:38
+msgid "ISDN"
+msgstr "ISDN"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:39
+msgid "Slow ADSL"
+msgstr "ADSL lenta"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:40
+msgid "Fast ADSL"
+msgstr "ADSL rápida"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:41
+msgid "Broadband"
+msgstr "Banda larga"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:44
+msgid "Input packets/s:"
+msgstr "Pacotes de entrada/s:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:46
+msgid "How many input packets to send to the server each second"
+msgstr "Quantos pacotes de entrada serão enviados ao servidor a cada segundo"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:48
+msgid "Server queries/s:"
+msgstr "Consultas ao servidor/s:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
+msgid "Downloads:"
+msgstr "Downloads:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:54
+msgid "Maximum number of concurrent HTTP/FTP downloads"
+msgstr "Número máximo de downloads simultâneos via HTTP/FTP"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:56
+msgid "Download speed:"
+msgstr "Velocidade de download:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:69
+msgid "Local latency:"
+msgstr "Latência local:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:73
+msgid "Show netgraph"
+msgstr "Exibir gráfico de rede"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:74
+msgid "Show a graph of packet sizes and other information"
+msgstr "Exibe um gráfico de tamanhos de pacotes e outras informações"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:76
+msgid "Client-side movement prediction"
+msgstr "Previsão de movimento pelo cliente"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:78
+msgid "Movement error compensation"
+msgstr "Compensação de erro de movimento"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:82
+msgid "Use encryption (AES) when available"
+msgstr "Usar encriptação (AES) quando disponível"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:85
+msgid "Framerate"
+msgstr "Taxa de Quadros por Segundo (FPS)"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:87
+msgid "Maximum:"
+msgstr "Máximo:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:99
+msgid "MAXFPS^Unlimited"
+msgstr "Ilimitada"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:102
+msgid "Target:"
+msgstr "Alvo:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:104
+msgid "TRGT^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:116
+msgid "Idle limit:"
+msgstr "Em segundo plano:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:122
+msgid "IDLFPS^Unlimited"
+msgstr "Ilimitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:126
+msgid "Save processing time for other apps"
+msgstr "Salvar tempo de processamento para outras aplicações"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:129
+msgid "Show frames per second"
+msgstr "Exibir taxa de quadros por segundo"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:130
+msgid "Show your rendered frames per second"
+msgstr "Exibe a sua taxa de quadros por segundo"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
+msgid "Menu tooltips:"
+msgstr "Dicas de menu:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:137
+msgid ""
+"Menu tooltips: disabled, standard or advanced (also shows cvar or console "
+"command bound to the menu item)"
+msgstr ""
+"Dicas de menu: desabilitado, padrão ou avançado (também mostra a cvar ou "
+"comando de console ligado ao item de menu)"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:138
+msgid "TLTIP^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:139
+msgid "TLTIP^Standard"
+msgstr "Padrão"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:140
+msgid "TLTIP^Advanced"
+msgstr "Avançado"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:143
+msgid "Show current date and time"
+msgstr "Exibir data e hora atual"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:144
+msgid "Show current date and time of day, useful on screenshots"
+msgstr "Exibe a data e hora atual do dia, útil para capturas de tela"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:147
+msgid "Enable developer mode"
+msgstr "Habilitar modo de desenvolvedor"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:151
+msgid "Advanced settings..."
+msgstr "Configurações avançadas..."
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:152
+msgid "Advanced settings where you can tweak every single variable of the game"
+msgstr ""
+"Definições avançadas onde você poderá ajustar cada uma das variáveis do jogo"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc.qc:157
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qh:6
+msgid "Factory reset"
+msgstr "Configurações padrões"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:31
+msgid "Cvar filter:"
+msgstr "Filtro de cvar:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:38
+msgid "Modified cvars only"
+msgstr "Somente cvars modificadas"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:45
+msgid "Setting:"
+msgstr "Configuração:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:49
+msgid "Type:"
+msgstr "Modo:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:53
+msgid "Value:"
+msgstr "Valor:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:70
+msgid "Description:"
+msgstr "Descrição:"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qh:7
+msgid "Advanced settings"
+msgstr "Configurações avançadas"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:11
+msgid "Are you sure you want to reset all settings?"
+msgstr ""
+"Tem certeza de que deseja redefinir todas as configurações para o padrão?"
+
+#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:13
+msgid "This will create a backup config in your data directory"
+msgstr ""
+"Isso irá criar uma cópia da sua configuração na seguinte pasta: C:\\Users"
+"\\[usuário]\\Saved Games\\xonotic\\data"
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:25
+msgid "Menu Skins"
+msgstr "Visuais de Menu"
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:64
+msgid "Text Language"
+msgstr "Idioma dos Textos"
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:69
+msgid "Set language"
+msgstr "Definir idioma"
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:74
+msgid "Disable gore effects and harsh language"
+msgstr "Desabilitar sangue e linguagem inapropriada"
+
+#: qcsrc/menu/xonotic/dialog_settings_user.qc:75
+msgid ""
+"Replace blood and gibs with content that does not have any gore effects "
+"(default: disabled)"
+msgstr ""
+"Substitui o sangue com conteúdo que não contém nenhum efeito violento "
+"(padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:10
+msgid "While connected language changes will be applied only to the menu,"
+msgstr ""
+"Enquanto estiver conectado, alterações no idioma serão aplicadas somente no "
+"menu."
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
+msgid "full language changes will take effect starting from the next game"
+msgstr ""
+"Alterações completas de idioma surtirão efeito a partir da próxima partida"
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
+msgid "Disconnect now"
+msgstr "Desconectar agora"
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:17
+msgid "Switch language"
+msgstr "Alterar idioma"
+
+#: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qh:6
+msgid "Warning"
+msgstr "Aviso"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:33
+msgid "Resolution:"
+msgstr "Resolução:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:37
+msgid "Font/UI size:"
+msgstr "Tamanho da fonte/UI:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:39
+msgid "SZ^Unreadable"
+msgstr "Ilegível"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:40
+msgid "SZ^Tiny"
+msgstr "Minúsculo"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:41
+msgid "SZ^Little"
+msgstr "Muito Pequeno"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:42
+msgid "SZ^Small"
+msgstr "Pequeno"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:43
+msgid "SZ^Medium"
+msgstr "Médio"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:44
+msgid "SZ^Large"
+msgstr "Grande"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:45
+msgid "SZ^Huge"
+msgstr "Enorme"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:46
+msgid "SZ^Gigantic"
+msgstr "Gigante"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:47
+msgid "SZ^Colossal"
+msgstr "Colossal"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:51
+msgid "Color depth:"
+msgstr "Profundidade da cor:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:53
+msgid "How many bits per pixel (BPP) to render at, 32 is recommended"
+msgstr "Quantos bits por pixel (BPP) a serem renderizados, 32 é o recomendado"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:54
+msgid "16bit"
+msgstr "16bit"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:55
+msgid "32bit"
+msgstr "32bit"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:59
+msgid "Full screen"
+msgstr "Tela cheia"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:61
+msgid "Vertical Synchronization"
+msgstr "Sincronização Vertical"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:62
+msgid ""
+"Enable vertical synchronization to prevent tearing, will cap your fps to the "
+"screen refresh rate (default: disabled)"
+msgstr ""
+"Habilita a sincronização vertical para evitar cortes na tela. Isso irá "
+"limitar a quantidade de quadros por segundo em relação à taxa de atualização "
+"do monitor (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:67
+msgid "Flip view horizontally"
+msgstr "Girar a visão horizontalmente"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:68
+msgid "Poor man's left handed mode (default: off)"
+msgstr "Modo canhoto (padrão: desligado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:71
+msgid "Anisotropy:"
+msgstr "Filtro anisotrópico:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:73
+msgid "Anisotropic filtering quality (default: 1x)"
+msgstr "Qualidade do filtro anisotrópico (padrão: 1x)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:74
+msgid "ANISO^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:75
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:86
+msgid "2x"
+msgstr "2x"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:76
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:87
+msgid "4x"
+msgstr "4x"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:77
+msgid "8x"
+msgstr "8x"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:78
+msgid "16x"
+msgstr "16x"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:81
+msgid "Antialiasing:"
+msgstr "Anti-serrilhado:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:84
+msgid ""
+"Enable antialiasing, which smooths the edges of 3D geometry. Note that it "
+"might decrease performance by quite a lot (default: disabled)"
+msgstr ""
+"Habilita o anti-serrilhado, o qual suaviza as bordas da geometria em 3D. "
+"Note que isso pode diminuir bastante o desempenho (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:85
+msgid "AA^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:92
+msgid "High-quality frame buffer"
+msgstr "Buffer de quadro de alta qualidade"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:97
+msgid "Depth first:"
+msgstr "Profundidade principal:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:99
+msgid ""
+"Eliminate overdraw by rendering a depth-only version of the scene before the "
+"normal rendering starts (default: disabled)"
+msgstr ""
+"Elimina o sobredesenho renderizando uma versão de profundidade única da cena "
+"antes que a renderização normal comece (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:100
+msgid "DF^Disabled"
+msgstr "Desabilitado"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:101
+msgid "DF^World"
+msgstr "Mundo"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:102
+msgid "DF^All"
+msgstr "Todos"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:105
+msgid "Vertex Buffer Objects (VBOs)"
+msgstr "Objetos de Buffers de Vertex (VBOs)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:108
+msgid "VBO^Off"
+msgstr "Desligado"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:109
+msgid "Vertices, some Tris (compatible)"
+msgstr "Vértices, alguns Triângulos (compatível)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:110
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:114
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:116
+msgid ""
+"Make use of Vertex Buffer Objects to store static geometry in video memory "
+"for faster rendering (default: Vertex and Triangles)"
+msgstr ""
+"Faz uso de objetos de buffers de vertex (VBOs) para armazenar geometria "
+"estática na memória de vídeo para renderização mais rápida. (padrão: "
+"Vértices e Triângulos)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:113
+msgid "Vertices"
+msgstr "Vértices"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:115
+msgid "Vertices and Triangles"
+msgstr "Vértices e Triângulos"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:119
+msgid "Brightness:"
+msgstr "Brilho:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:121
+msgid "Brightness of black (default: 0)"
+msgstr "Brilho do preto (padrão: 0)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:123
+msgid "Contrast:"
+msgstr "Contraste:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:125
+msgid "Brightness of white (default: 1)"
+msgstr "Brilho do branco (padrão: 1)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:127
+msgid "Gamma:"
+msgstr "Gama:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:130
+msgid ""
+"Inverse gamma correction value, a brightness effect that does not affect "
+"white or black (default: 1.125)"
+msgstr ""
+"Valor de correção de gama inverso, é um efeito de brilho que não afeta o "
+"branco ou preto (padrão: 1.125)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:133
+msgid "Contrast boost:"
+msgstr "Impulso do contraste:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:136
+msgid "By how much to multiply the contrast in dark areas (default: 1)"
+msgstr ""
+"Por quanto deve ser multiplicado o contraste em áreas escuras (padrão: 1)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:139
+msgid "Saturation:"
+msgstr "Saturação:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:142
+msgid ""
+"Saturation adjustment (0 = grayscale, 1 = normal, 2 = oversaturated), "
+"requires GLSL color control (default: 1)"
+msgstr ""
+"Ajuste da saturação (0 = tons de cinza, 1 = normal, 2 = muito saturado), "
+"requer controle de cor GLSL (padrão: 1)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:146
+msgid "LIT^Ambient:"
+msgstr "Iluminação ambiental:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:148
+msgid ""
+"Ambient lighting, if set too high it tends to make light on maps look dull "
+"and flat (default: 4)"
+msgstr ""
+"Iluminação ambiental, caso o valor seja muito alto, poderá fazer com que as "
+"luzes dos mapas fiquem achatadas e sem graça (padrão: 4)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:150
+msgid "Intensity:"
+msgstr "Intensidade:"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:152
+msgid "Global rendering brightness (default: 1)"
+msgstr "Brilho geral da renderização (padrão: 1)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:155
+msgid "Wait for GPU to finish each frame"
+msgstr "Esperar que a placa de vídeo termine cada quadro"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:156
+msgid ""
+"Make the CPU wait for the GPU to finish each frame, can help with some "
+"strange input or video lag on some machines (default: disabled)"
+msgstr ""
+"Faz com que o processador espere pela placa de vídeo terminar cada quadro. "
+"Pode ajudar no caso de alguns atrasos nos dispositivos de entrada ou lag de "
+"vídeo em algumas máquinas (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:158
+msgid "Use OpenGL 2.0 shaders (GLSL)"
+msgstr "Usar shaders de OpenGL 2.0 (GLSL)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:162
+msgid "Use GLSL to handle color control"
+msgstr "Usar GLSL para o controle de cores"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:163
+msgid ""
+"Enable use of GLSL to apply gamma correction, note that it might decrease "
+"performance by a lot (default: disabled)"
+msgstr ""
+"Habilita o uso de GLSL para aplicar correção de gama. Note que isso pode "
+"diminuir bastante o desempenho (padrão: desabilitado)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:168
+msgid "Psycho coloring (easter egg)"
+msgstr "Cores 'Psycho' (easter egg)"
+
+#: qcsrc/menu/xonotic/dialog_settings_video.qc:171
+msgid "Trippy vertices (easter egg)"
+msgstr "Vértices 'Trip' (easter egg)"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:110
+msgid "Instant action! (random map with bots)"
+msgstr "Ação Instantânea! (mapa aleatório com bots)"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:117
+msgid "???"
+msgstr "???"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:130
+msgid "Campaign Difficulty:"
+msgstr "Dificuldade da Campanha:"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:131
+msgid "CSKL^Easy"
+msgstr "Fácil"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:132
+msgid "CSKL^Medium"
+msgstr "Média"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:133
+msgid "CSKL^Hard"
+msgstr "Difícil"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qc:135
+msgid "Start Singleplayer!"
+msgstr "Iniciar Campanha!"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qh:6
+msgid "Singleplayer"
+msgstr "Um Jogador"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer.qh:7
+msgid "Play the singleplayer campaign or instant action matches against bots"
+msgstr ""
+"Jogue a campanha de um jogador ou inicie uma partida de ação instantânea "
+"contra bots"
+
+#: qcsrc/menu/xonotic/dialog_singleplayer_winner.qh:7
+msgid "Winner"
+msgstr "Vencedor"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:32
+msgid "join 'best' team (auto-select)"
+msgstr "juntar-se à 'melhor' equipe (seleção automática)"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:33
+msgid "Autoselect team (recommended)"
+msgstr "Selecionar equipe automaticamente (recomendado)"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:37
+msgid "red"
+msgstr "vermelha"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:38
+msgid "blue"
+msgstr "azul"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:39
+msgid "yellow"
+msgstr "amarela"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:40
+msgid "pink"
+msgstr "rosa"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qc:43
+msgid "spectate"
+msgstr "assistir"
+
+#: qcsrc/menu/xonotic/dialog_teamselect.qh:7
+msgid "Team Selection"
+msgstr "Seleção de Equipe"
+
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:10
+msgid "Allow player statistics to use your nickname?"
+msgstr "Permitir que as estatísticas de jogadores usem o seu apelido?"
+
+#: qcsrc/menu/xonotic/dialog_uid2name.qc:12
+msgid "Answering \"No\" you will appear as \"Anonymous player\""
+msgstr ""
+"Selecionando \"Não\" você aparecerá como \"Anonymous player\" (em português, "
+"\"Jogador anônimo\")"
+
+#: qcsrc/menu/xonotic/gametypelist.qc:86
+msgid "teamplay"
+msgstr "jogo em equipe"
+
+#: qcsrc/menu/xonotic/gametypelist.qc:88
+msgid "free for all"
+msgstr "cada um por si"
+
+#: qcsrc/menu/xonotic/keybinder.qc:29
+msgid "Moving"
+msgstr "Movimento"
+
+#: qcsrc/menu/xonotic/keybinder.qc:30
+msgid "forward"
+msgstr "Mover-se para frente"
+
+#: qcsrc/menu/xonotic/keybinder.qc:31
+msgid "backpedal"
+msgstr "Mover-se para trás"
+
+#: qcsrc/menu/xonotic/keybinder.qc:32
+msgid "strafe left"
+msgstr "Mover-se para a esquerda"
+
+#: qcsrc/menu/xonotic/keybinder.qc:33
+msgid "strafe right"
+msgstr "Mover-se para a direita"
+
+#: qcsrc/menu/xonotic/keybinder.qc:34
+msgid "jump / swim"
+msgstr "saltar / nadar"
+
+#: qcsrc/menu/xonotic/keybinder.qc:35
+msgid "crouch / sink"
+msgstr "agachar / afundar"
+
+#: qcsrc/menu/xonotic/keybinder.qc:36
+msgid "off-hand hook"
+msgstr "gancho imediato"
+
+#: qcsrc/menu/xonotic/keybinder.qc:37
+msgid "jet pack"
+msgstr "mochila a jato"
+
+#: qcsrc/menu/xonotic/keybinder.qc:39
+msgid "Attacking"
+msgstr "Ataques"
+
+#: qcsrc/menu/xonotic/keybinder.qc:44
+msgid "WEAPON^previous"
+msgstr "anterior"
+
+#: qcsrc/menu/xonotic/keybinder.qc:45
+msgid "WEAPON^next"
+msgstr "seguinte"
+
+#: qcsrc/menu/xonotic/keybinder.qc:46
+msgid "WEAPON^previously used"
+msgstr "usada anteriormente"
+
+#: qcsrc/menu/xonotic/keybinder.qc:47
+msgid "WEAPON^best"
+msgstr "melhor"
+
+#: qcsrc/menu/xonotic/keybinder.qc:48
+msgid "reload"
+msgstr "recarregar"
+
+#: qcsrc/menu/xonotic/keybinder.qc:49
+msgid "drop weapon / throw nade"
+msgstr "largar arma / arremessar granada"
+
+#: qcsrc/menu/xonotic/keybinder.qc:77
+msgid "hold zoom"
+msgstr "manter zoom"
+
+#: qcsrc/menu/xonotic/keybinder.qc:78
+msgid "toggle zoom"
+msgstr "ativar/desativar zoom"
+
+#: qcsrc/menu/xonotic/keybinder.qc:79
+msgid "show scores"
+msgstr "exibir pontuações"
+
+#: qcsrc/menu/xonotic/keybinder.qc:80
+msgid "screen shot"
+msgstr "tirar captura de tela"
+
+#: qcsrc/menu/xonotic/keybinder.qc:81
+msgid "maximize radar"
+msgstr "maximizar radar"
+
+#: qcsrc/menu/xonotic/keybinder.qc:82
+msgid "3rd person view"
+msgstr "visão em 3ª pessoa"
+
+#: qcsrc/menu/xonotic/keybinder.qc:83
+msgid "enter spectator mode"
+msgstr "entrar no modo de espectador"
+
+#: qcsrc/menu/xonotic/keybinder.qc:85
+msgid "Communicate"
+msgstr "Comunicação"
+
+#: qcsrc/menu/xonotic/keybinder.qc:86
+msgid "public chat"
+msgstr "Bate-papo público"
+
+#: qcsrc/menu/xonotic/keybinder.qc:87 qcsrc/menu/xonotic/keybinder.qc:100
+msgid "team chat"
+msgstr "Bate-papo de equipe"
+
+#: qcsrc/menu/xonotic/keybinder.qc:88
+msgid "show chat history"
+msgstr "exibir histórico do bate-papo"
+
+#: qcsrc/menu/xonotic/keybinder.qc:89
+msgid "vote YES"
+msgstr "votar SIM"
+
+#: qcsrc/menu/xonotic/keybinder.qc:90
+msgid "vote NO"
+msgstr "votar NÃO"
+
+#: qcsrc/menu/xonotic/keybinder.qc:93
+msgid "Client"
+msgstr "Cliente"
+
+#: qcsrc/menu/xonotic/keybinder.qc:95
+msgid "enter console"
+msgstr "abrir o console"
+
+#: qcsrc/menu/xonotic/keybinder.qc:96
+msgid "disconnect"
+msgstr "desconectar"
+
+#: qcsrc/menu/xonotic/keybinder.qc:97
+msgid "quit"
+msgstr "sair"
+
+#: qcsrc/menu/xonotic/keybinder.qc:101
+msgid "auto-join team"
+msgstr "juntar-se à uma equipe automáticamente"
+
+#: qcsrc/menu/xonotic/keybinder.qc:103
+msgid "drop key / drop flag"
+msgstr "largar chave / largar bandeira"
+
+#: qcsrc/menu/xonotic/keybinder.qc:106
+msgid "quick menu"
+msgstr "menu rápido"
+
+#: qcsrc/menu/xonotic/keybinder.qc:107
+msgid "sandbox menu"
+msgstr "menu sandbox"
+
+#: qcsrc/menu/xonotic/keybinder.qc:108
+msgid "drag object"
+msgstr "arrastar objeto"
+
+#: qcsrc/menu/xonotic/keybinder.qc:110
+msgid "User defined"
+msgstr "Definido pelo usuário"
+
+#: qcsrc/menu/xonotic/mainwindow.qc:64 qcsrc/menu/xonotic/mainwindow.qc:67
+msgid "Do not press this button again!"
+msgstr "Não aperte este botão novamente!"
+
+#: qcsrc/menu/xonotic/maplist.qc:291
+msgid ""
+"Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"
+msgstr ""
+"Huh? Não posso jogar isto (m é NULO). Refiltrando para que isso não ocorra "
+"novamente.\n"
+
+#: qcsrc/menu/xonotic/maplist.qc:299
+#, c-format
+msgid "%s's Xonotic Server"
+msgstr "Servidor de Xonotic de %s"
+
+#: qcsrc/menu/xonotic/maplist.qc:304
+msgid ""
+"Huh? Can't play this (invalid game type). Refiltering so this won't happen "
+"again.\n"
+msgstr ""
+"Huh? Não posso jogar isto (modo de jogo inválido). Refiltrando para que isso "
+"não ocorra novamente.\n"
+
+#: qcsrc/menu/xonotic/playerlist.qc:100 qcsrc/menu/xonotic/playerlist.qc:110
+msgid "spectator"
+msgstr "espectador"
+
+#: qcsrc/menu/xonotic/playermodel.qc:170
+msgid "<no model found>"
+msgstr "<nenhum modelo encontrado>"
+
+#: qcsrc/menu/xonotic/serverlist.qc:273
+msgid "Favorite"
+msgstr "Favoritar"
+
+#: qcsrc/menu/xonotic/serverlist.qc:274
+msgid ""
+"Bookmark the currently highlighted server so that it's faster to find in the "
+"future"
+msgstr ""
+"Marca o servidor selecionado como favorito para que seja mais rápido "
+"encontrá-lo no futuro"
+
+#: qcsrc/menu/xonotic/serverlist.qc:763
+msgid "Ping"
+msgstr "Ping"
+
+#: qcsrc/menu/xonotic/serverlist.qc:764
+msgid "Hostname"
+msgstr "Servidor"
+
+#: qcsrc/menu/xonotic/serverlist.qc:765
+msgid "Map"
+msgstr "Mapa"
+
+#: qcsrc/menu/xonotic/serverlist.qc:766
+msgid "Type"
+msgstr "Modo"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+#, c-format
+msgid "AES level %d"
+msgstr "Nível AES %d"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+msgid "ENC^none"
+msgstr "nenhuma"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1060
+msgid "encryption:"
+msgstr "encriptação:"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1061
+#, c-format
+msgid "mod: %s"
+msgstr "modificação: %s"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1063
+#, c-format
+msgid "modified settings"
+msgstr "configurações modificadas"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1063
+#, c-format
+msgid "official settings"
+msgstr "configurações oficiais"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1065
+msgid "stats disabled"
+msgstr "estatísticas desabilitadas"
+
+#: qcsrc/menu/xonotic/serverlist.qc:1065
+msgid "stats enabled"
+msgstr "estatísticas habilitadas"
+
+#: qcsrc/menu/xonotic/serverlist.qh:151
+msgid "SLCAT^Favorites"
+msgstr "Favoritos"
+
+#: qcsrc/menu/xonotic/serverlist.qh:152
+msgid "SLCAT^Recommended"
+msgstr "Recomendados"
+
+#: qcsrc/menu/xonotic/serverlist.qh:153
+msgid "SLCAT^Normal Servers"
+msgstr "Servidores Normais"
+
+#: qcsrc/menu/xonotic/serverlist.qh:154
+msgid "SLCAT^Servers"
+msgstr "Servidores"
+
+#: qcsrc/menu/xonotic/serverlist.qh:155
+msgid "SLCAT^Competitive Mode"
+msgstr "Modo Competitivo"
+
+#: qcsrc/menu/xonotic/serverlist.qh:156
+msgid "SLCAT^Modified Servers"
+msgstr "Servidores Modificados"
+
+#: qcsrc/menu/xonotic/serverlist.qh:157
+msgid "SLCAT^Overkill"
+msgstr "Overkill"
+
+#: qcsrc/menu/xonotic/serverlist.qh:158
+msgid "SLCAT^InstaGib"
+msgstr "InstaGib"
+
+#: qcsrc/menu/xonotic/serverlist.qh:159
+msgid "SLCAT^Defrag Mode"
+msgstr "Modo Defrag"
+
+#: qcsrc/menu/xonotic/skinlist.qc:70
+msgid "<TITLE>"
+msgstr "<TÍTULO>"
+
+#: qcsrc/menu/xonotic/skinlist.qc:71
+msgid "<AUTHOR>"
+msgstr "<AUTOR>"
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:72
+msgid "VOL^MAX"
+msgstr "MÁX"
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:74
+msgid "VOL^OFF"
+msgstr "DESLIGADO"
+
+#: qcsrc/menu/xonotic/slider_decibels.qc:82
+#, c-format
+msgid "%s dB"
+msgstr "%s dB"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:13
+msgid ""
+"Multiplier for amount of particles. Less means less particles, which in turn "
+"gives for better performance (default: 1)"
+msgstr ""
+"Multiplicador para a quantidade de partículas. Menos significa menos "
+"partículas, o que resulta em um melhor desempenho (padrão: 1)"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:14
+msgid "PART^OMG"
+msgstr "MEUDEUS"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:15
+msgid "PART^Low"
+msgstr "Baixa"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:16
+msgid "PART^Medium"
+msgstr "Média"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:17
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:14
+msgid "PART^Normal"
+msgstr "Normal"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:18
+msgid "PART^High"
+msgstr "Alta"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:19
+msgid "PART^Ultra"
+msgstr "Ultra"
+
+#: qcsrc/menu/xonotic/slider_particles.qc:20
+msgid "PART^Ultimate"
+msgstr "Extrema"
+
+#: qcsrc/menu/xonotic/slider_picmip.qc:13
+msgid ""
+"Change the sharpness of the textures. Lowering it will effectively reduce "
+"texture memory usage, but make the textures appear very blurry. (default: "
+"good)"
+msgstr ""
+"Altera a nitidez das texturas. Usar valores baixos irá efetivamente reduzir "
+"a utilização de memória para as texturas, mas fará com que elas pareçam mais "
+"desfocadas. (padrão: boa)"
+
+#: qcsrc/menu/xonotic/slider_resolution.qc:115
+msgid "Screen resolution"
+msgstr "Resolução da tela"
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:13
+msgid "PART^Slow"
+msgstr "Lento"
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:15
+msgid "PART^Fast"
+msgstr "Rápido"
+
+#: qcsrc/menu/xonotic/slider_sbfadetime.qc:16
+msgid "PART^Instant"
+msgstr "Instantâneo"
+
+#: qcsrc/menu/xonotic/statslist.qc:29
+msgid "January"
+msgstr "Janeiro"
+
+#: qcsrc/menu/xonotic/statslist.qc:30
+msgid "February"
+msgstr "Fevereiro"
+
+#: qcsrc/menu/xonotic/statslist.qc:31
+msgid "March"
+msgstr "Março"
+
+#: qcsrc/menu/xonotic/statslist.qc:32
+msgid "April"
+msgstr "Abril"
+
+#: qcsrc/menu/xonotic/statslist.qc:33
+msgid "May"
+msgstr "Maio"
+
+#: qcsrc/menu/xonotic/statslist.qc:34
+msgid "June"
+msgstr "Junho"
+
+#: qcsrc/menu/xonotic/statslist.qc:35
+msgid "July"
+msgstr "Julho"
+
+#: qcsrc/menu/xonotic/statslist.qc:36
+msgid "August"
+msgstr "Agosto"
+
+#: qcsrc/menu/xonotic/statslist.qc:37
+msgid "September"
+msgstr "Setembro"
+
+#: qcsrc/menu/xonotic/statslist.qc:38
+msgid "October"
+msgstr "Outubro"
+
+#: qcsrc/menu/xonotic/statslist.qc:39
+msgid "November"
+msgstr "Novembro"
+
+#: qcsrc/menu/xonotic/statslist.qc:40
+msgid "December"
+msgstr "Dezembro"
+
+#: qcsrc/menu/xonotic/statslist.qc:96
+msgid "Joined:"
+msgstr "Juntou-se:"
+
+#: qcsrc/menu/xonotic/statslist.qc:103
+msgid "Last_Seen:"
+msgstr "Última_Visita:"
+
+#: qcsrc/menu/xonotic/statslist.qc:110
+msgid "Time_Played:"
+msgstr "Tempo_Jogado:"
+
+#: qcsrc/menu/xonotic/statslist.qc:117
+msgid "Favorite_Map:"
+msgstr "Mapa_Favorito:"
+
+#: qcsrc/menu/xonotic/statslist.qc:201 qcsrc/menu/xonotic/statslist.qc:245
+#, c-format
+msgid "%s_Matches:"
+msgstr "%s_Partidas:"
+
+#: qcsrc/menu/xonotic/statslist.qc:208
+#, c-format
+msgid "%s_ELO:"
+msgstr "%s_ELO:"
+
+#: qcsrc/menu/xonotic/statslist.qc:215
+#, c-format
+msgid "%s_Rank:"
+msgstr "%s_Posição:"
+
+#: qcsrc/menu/xonotic/statslist.qc:222
+#, c-format
+msgid "%s_Percentile:"
+msgstr "%s_Percentil:"
+
+#: qcsrc/menu/xonotic/statslist.qc:231
+#, c-format
+msgid "%s_Favorite_Map:"
+msgstr "%s_Mapa_Favorito:"
+
+#: qcsrc/menu/xonotic/statslist.qc:246
+#, c-format
+msgid "%d (unranked)"
+msgstr "%d (não classificado)"
+
+#: qcsrc/menu/xonotic/util.qc:417
+#, c-format
+msgid ""
+"Update can be downloaded at:\n"
+"%s\n"
+msgstr ""
+"A atualização pode ser baixada em:\n"
+"%s\n"
+
+#: qcsrc/menu/xonotic/util.qc:528
+msgid "Autogenerating mapinfo for newly added maps..."
+msgstr "Gerando mapinfo automaticamente para os novos mapas adicionados..."
+
+#: qcsrc/menu/xonotic/util.qc:557
+#, c-format
+msgid "^1%s TEST BUILD"
+msgstr "^1%s VERSÃO DE TESTE"
+
+#: qcsrc/menu/xonotic/util.qc:577
+#, c-format
+msgid "Update to %s now!"
+msgstr "Atualize para %s agora!"
+
+#: qcsrc/menu/xonotic/util.qc:662
+msgid ""
+"^1ERROR: Texture compression is required but not supported.\n"
+"^1Expect visual problems.\n"
+msgstr ""
+"^1ERRO: A compressão de texturas é necessária, mas não é suportada.\n"
+"^1Espere problemas visuais.\n"
+"\n"
+
+#: qcsrc/menu/xonotic/util.qc:780
+msgid "Use default"
+msgstr "Usar padrão"
+
+#: qcsrc/menu/xonotic/util.qc:800
+msgid "Team Color:"
+msgstr "Cor de Equipe:"
+
+#: qcsrc/menu/xonotic/util.qh:44
+msgid "Enable panel"
+msgstr "Habilitar painel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Bate-papo"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 chegou muito perto do foguete de ^BG%s^K1%s%s"
index 55e03f10515b2b5e465e55c1187d4ecd3ea7b362..06e1922ae77fc612fb754d24eb30aba42d40dd4f 100644 (file)
@@ -18,7 +18,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2018-03-01 20:50+0000\n"
+"PO-Revision-Date: 2018-03-16 06:43+0000\n"
 "Last-Translator: Andrei Stepanov\n"
 "Language-Team: Russian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/ru/)\n"
@@ -102,7 +102,7 @@ msgstr "бросить оружие"
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/menu/xonotic/keybinder.qc:41
 msgid "secondary fire"
-msgstr "вÑ\82оÑ\80иÑ\87ный огонь"
+msgstr "алÑ\8cÑ\82еÑ\80наÑ\82ивный огонь"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
@@ -136,7 +136,7 @@ msgstr "прыжок"
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
 msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1Старт игры через ^3%d^1 секунд(ы)"
+msgstr "^1Старт игры через ^3%d^1 секунд"
 
 #: qcsrc/client/hud/panel/infomessages.qc:145
 msgid "^2Currently in ^1warmup^2 stage!"
@@ -1022,7 +1022,7 @@ msgstr "^2Имя ^7вместо \"^1Anonymous player^7\" в статистике
 
 #: qcsrc/client/hud/panel/vote.qc:115
 msgid "A vote has been called for:"
-msgstr "Ð\93олоÑ\81ование Ð±Ñ\8bло Ñ\81оздано для:"
+msgstr "Создано Ð³Ð¾Ð»Ð¾Ñ\81ование для:"
 
 #: qcsrc/client/hud/panel/vote.qc:117
 msgid "Allow servers to store and display your name?"
@@ -1113,7 +1113,7 @@ msgstr "Голосование за карту"
 #: qcsrc/client/mapvoting.qc:382
 #, c-format
 msgid "%d seconds left"
-msgstr "Осталось %d секунд(ы)"
+msgstr "Осталось %d секунд"
 
 #: qcsrc/client/mapvoting.qc:497
 msgid ""
@@ -1912,11 +1912,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:246
 msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
-msgstr "^BG ^TC^TT^BG Ð¤Ð»Ð°Ð³ Ð±Ñ\8bл Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91н Ð½Ð° Ð±Ð°Ð·Ñ\83 Ð²Ð»Ð°Ð´ÐµÐ»Ñ\8cÑ\86ем"
+msgstr "^BG ^TC^TT^BG Флаг возвращён на базу владельцем"
 
 #: qcsrc/common/notifications/all.inc:247
 msgid "^BGThe flag was returned by its owner"
-msgstr "^BGФлаг Ð±Ñ\8bл Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91н Ð½Ð° Ð±Ð°Ð·Ñ\83 Ð²Ð»Ð°Ð´ÐµÐ»Ñ\8cÑ\86ем"
+msgstr "^BGФлаг возвращён на базу владельцем"
 
 #: qcsrc/common/notifications/all.inc:248
 msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
@@ -2022,12 +2022,12 @@ msgstr "^F2Вы станете зрителем со следующего рау
 #: qcsrc/common/notifications/all.inc:274
 #, c-format
 msgid "^BG%s%s^K1 was killed by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
-msgstr "^BG%s%s^K1 был убит ^BG%s^K1 с усилителем ^BG%s^K1 ^K1%s%s"
+msgstr "^BG%s%s^K1 убит ^BG%s^K1 с усилителем ^BG%s^K1 ^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:274
 #, c-format
 msgid "^BG%s%s^K1 was scored against by ^BG%s^K1's ^BG%s^K1 buff ^K1%s%s"
-msgstr "^BG%s%s^K1 был растерзан ^BG%s^K1 с усилителем ^BG%s^K1 ^K1%s%s"
+msgstr "^BG%s%s^K1 растерзан ^BG%s^K1 с усилителем ^BG%s^K1 ^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:275
 #, c-format
@@ -2047,22 +2047,22 @@ msgstr "^BG%s%s^K1 был впечатан в землю ^BG%s^K1%s%s"
 #: qcsrc/common/notifications/all.inc:278
 #, c-format
 msgid "^BG%s%s^K1 felt a little hot from ^BG%s^K1's fire^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ Ð¿Ð¾Ð´Ð¿Ð°Ð»Ñ\91н Ð¸Ð· ^BG%s^K1^K1%s%s"
+msgstr "^BG%s%s^K1 немного подпалён из ^BG%s^K1^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:278
 #, c-format
 msgid "^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¿Ñ\80ожаÑ\80ен Ð´Ð¾ Ñ\85Ñ\80Ñ\83Ñ\81Ñ\82Ñ\8fÑ\89ей ÐºÐ¾Ñ\80оÑ\87ки ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 прожарен до хрустящей корочки ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:279
 #, c-format
 msgid "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¸Ñ\81пеÑ\87Ñ\91н Ñ\81 Ð¿Ð¾Ð¼Ð¾Ñ\89Ñ\8cÑ\8e ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 испечён с помощью ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:280
 #, c-format
 msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¾Ñ\82пÑ\80авлен Ðº Ð¼Ð¾Ð½Ñ\81Ñ\82Ñ\80ам Ñ\80Ñ\83кой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 отправлен к монстрам рукой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:281
 #, c-format
@@ -2077,17 +2077,17 @@ msgstr "^BG%s%s^K1 слишком близко подошёл к взрыву н
 #: qcsrc/common/notifications/all.inc:282
 #, c-format
 msgid "^BG%s%s^K1 was burned to death by ^BG%s^K1's Napalm Nade%s%s"
-msgstr "^BG%s%s^K1 был сожжён заживо Гранатой Напалма ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 сожжён заживо Гранатой Напалма ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:283
 #, c-format
 msgid "^BG%s%s^K1 was blown up by ^BG%s^K1's Ice Nade%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð²Ð·орван Ледяной Гранатой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð¿Ð¾Ð´орван Ледяной Гранатой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:284
 #, c-format
 msgid "^BG%s%s^K1 was frozen to death by ^BG%s^K1's Ice Nade%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð·Ð°Ð¼Ð¾Ñ\80ожен Ð\9bедÑ\8fной Ð\93Ñ\80анаÑ\82ой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 заморожен Ледяной Гранатой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:285
 #, c-format
@@ -2097,7 +2097,7 @@ msgstr "^BG%s%s^K1 не был вылечен Лечащей Гранатой ^B
 #: qcsrc/common/notifications/all.inc:286
 #, c-format
 msgid "^BG%s%s^K1 was shot into space by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¾Ñ\82пÑ\80авлен Ð² Ð¾Ñ\82кÑ\80Ñ\8bÑ\82Ñ\8bй ÐºÐ¾Ñ\81моÑ\81 ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 отправлен в открытый космос ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:287
 #, c-format
@@ -2176,8 +2176,7 @@ msgstr "^BG%s%s^K1 измельчён Пуком-ботом, управляем
 #: qcsrc/common/notifications/all.inc:299
 #, c-format
 msgid "^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s"
-msgstr ""
-"^BG%s%s^K1 был разорван на куски Пауком-ботом, управляемым ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван на куски Пауком-ботом, управляемым ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:300
 #, c-format
@@ -2198,7 +2197,7 @@ msgstr "^BG%s%s^K1 не смог скрыться от Гонщика, упра
 #: qcsrc/common/notifications/all.inc:303
 #, c-format
 msgid "^BG%s%s^K1 was thrown into a world of hurt by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¾Ñ\82пÑ\80авлен Ð² Ð¼Ð¸Ñ\80 Ð±Ð¾Ð»Ð¸ Ñ\80Ñ\83кой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 отправлен в мир боли рукой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:305
 #, c-format
@@ -2268,7 +2267,7 @@ msgstr "^BG%s^K1 сгорел дотла%s%s"
 #: qcsrc/common/notifications/all.inc:315
 #, c-format
 msgid "^BG%s^K1 was exploded by a Mage%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð²Ð·орван Магом%s%s"
+msgstr "^BG%s^K1 Ð¿Ð¾Ð´орван Магом%s%s"
 
 #: qcsrc/common/notifications/all.inc:316
 #, c-format
@@ -2278,22 +2277,22 @@ msgstr "^BG%s^K1's вывернут наизнанку Шамблером%s%s"
 #: qcsrc/common/notifications/all.inc:317
 #, c-format
 msgid "^BG%s^K1 was smashed by a Shambler%s%s"
-msgstr "^BG%s^K1 был раздавлен Шамблером%s%s"
+msgstr "^BG%s^K1 раздавлен Шамблером%s%s"
 
 #: qcsrc/common/notifications/all.inc:318
 #, c-format
 msgid "^BG%s^K1 was zapped to death by a Shambler%s%s"
-msgstr "^BG%s^K1 был стёрт в порошок Шамблером%s%s"
+msgstr "^BG%s^K1 стёрт в порошок Шамблером%s%s"
 
 #: qcsrc/common/notifications/all.inc:319
 #, c-format
 msgid "^BG%s^K1 was bitten by a Spider%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð¿Ð¾Ð±Ð¸Ñ\82 Ð\9fаÑ\83ком%s%s"
+msgstr "^BG%s^K1 побит Пауком%s%s"
 
 #: qcsrc/common/notifications/all.inc:320
 #, c-format
 msgid "^BG%s^K1 was fireballed by a Wyvern%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð¿Ð¾Ñ\80ажÑ\91н Ð¾Ð³Ð½ÐµÐ½Ð½Ñ\8bм Ñ\88аÑ\80ом Ð\92ивеÑ\80на%s%s"
+msgstr "^BG%s^K1 поражён огненным шаром Виверна%s%s"
 
 #: qcsrc/common/notifications/all.inc:321
 #, c-format
@@ -2320,7 +2319,7 @@ msgstr "^BG%s^K1 захотел посмотреть на взрыв своег
 #: qcsrc/common/notifications/all.inc:324
 #, c-format
 msgid "^BG%s^K1 was burned to death by their own Napalm Nade%s%s"
-msgstr "^BG%s^K1 был сожжён заживо своей же Гранатой Напалма%s%s"
+msgstr "^BG%s^K1 сожжён заживо своей же Гранатой Напалма%s%s"
 
 #: qcsrc/common/notifications/all.inc:326
 #, c-format
@@ -2330,7 +2329,7 @@ msgstr "^BG%s^K1 немного обжёгся%s%s"
 #: qcsrc/common/notifications/all.inc:326
 #, c-format
 msgid "^BG%s^K1 was frozen to death by their own Ice Nade%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð·Ð°Ð¼Ð¾Ñ\80ожен Ñ\81воей Ð¶Ðµ Ð\9bедÑ\8fной Ð\93Ñ\80анаÑ\82ой%s%s"
+msgstr "^BG%s^K1 заморожен своей же Ледяной Гранатой%s%s"
 
 #: qcsrc/common/notifications/all.inc:327
 #, c-format
@@ -2390,7 +2389,7 @@ msgstr "^BG%s^K1 налетел на турель%s%s"
 #: qcsrc/common/notifications/all.inc:337
 #, c-format
 msgid "^BG%s^K1 was blasted away by an eWheel turret%s%s"
-msgstr "^BG%s^K1 был разорван в клочья турелью еМобиля%s%s"
+msgstr "^BG%s^K1 разорван в клочья турелью еМобиля%s%s"
 
 #: qcsrc/common/notifications/all.inc:338
 #, c-format
@@ -2400,7 +2399,7 @@ msgstr "^BG%s^K1 попал под огонь Зенитной Пушки %s%s"
 #: qcsrc/common/notifications/all.inc:339
 #, c-format
 msgid "^BG%s^K1 was blasted away by a Hellion turret%s%s"
-msgstr "^BG%s^K1 был разорван в клочья турелью Hellion%s%s"
+msgstr "^BG%s^K1 разорван в клочья турелью Hellion%s%s"
 
 #: qcsrc/common/notifications/all.inc:340
 #, c-format
@@ -2415,12 +2414,12 @@ msgstr "^BG%s^K1 изрешечён Пулемётной башней%s%s"
 #: qcsrc/common/notifications/all.inc:342
 #, c-format
 msgid "^BG%s^K1 got turned into smoldering gibs by an MLRS turret%s%s"
-msgstr "^BG%s^K1 был разорван на тлеющие кусочки турелью MLRS%s%s"
+msgstr "^BG%s^K1 разорван на тлеющие кусочки турелью MLRS%s%s"
 
 #: qcsrc/common/notifications/all.inc:343
 #, c-format
 msgid "^BG%s^K1 was phased out by a turret%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð¾Ñ\82менÑ\91н турелью%s%s"
+msgstr "^BG%s^K1 Ð»Ð¸ÐºÐ²Ð¸Ð´Ð¸Ñ\80ован турелью%s%s"
 
 #: qcsrc/common/notifications/all.inc:344
 #, c-format
@@ -2430,7 +2429,7 @@ msgstr "^BG%s^K1 отведал перегретой плазмы из туре
 #: qcsrc/common/notifications/all.inc:345
 #, c-format
 msgid "^BG%s^K1 was electrocuted by a Tesla turret%s%s"
-msgstr "^BG%s^K1 был убит электрическим током турели Теслы%s%s"
+msgstr "^BG%s^K1 убит электрическим током турели Теслы%s%s"
 
 #: qcsrc/common/notifications/all.inc:346
 #, c-format
@@ -2440,12 +2439,12 @@ msgstr "^BG%s^K1 обогащён свинцом из турели Ходунa%s
 #: qcsrc/common/notifications/all.inc:347
 #, c-format
 msgid "^BG%s^K1 was impaled by a Walker turret%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð¿Ñ\80онзÑ\91н Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e Ð¥Ð¾Ð´Ñ\83на%s%s"
+msgstr "^BG%s^K1 пронзён турелью Ходуна%s%s"
 
 #: qcsrc/common/notifications/all.inc:348
 #, c-format
 msgid "^BG%s^K1 was blasted away by a Walker turret%s%s"
-msgstr "^BG%s^K1 был разорван в клочья турелью Ходуна%s%s"
+msgstr "^BG%s^K1 разорван в клочья турелью Ходуна%s%s"
 
 #: qcsrc/common/notifications/all.inc:349
 #, c-format
@@ -2455,7 +2454,7 @@ msgstr "^BG%s^K1 зацепило взрывной волной от Шмеля
 #: qcsrc/common/notifications/all.inc:350
 #, c-format
 msgid "^BG%s^K1 was crushed by a vehicle%s%s"
-msgstr "^BG%s^K1 был раздавлен весом тяжёлой машины%s%s"
+msgstr "^BG%s^K1 раздавлен весом тяжёлой машины%s%s"
 
 #: qcsrc/common/notifications/all.inc:351
 #, c-format
@@ -2475,7 +2474,7 @@ msgstr "^BG%s^K1 задело взрывной волной от Паука-бо
 #: qcsrc/common/notifications/all.inc:354
 #, c-format
 msgid "^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s"
-msgstr "^BG%s^K1 был разорван на кусочки ракетой Паука-бота%s%s"
+msgstr "^BG%s^K1 разорван на кусочки ракетой Паука-бота%s%s"
 
 #: qcsrc/common/notifications/all.inc:355
 #, c-format
@@ -2515,12 +2514,12 @@ msgstr "^BG%s^K3 воскрес после падения"
 #: qcsrc/common/notifications/all.inc:366
 #, c-format
 msgid "^BG%s^K3 was revived by their Nade explosion"
-msgstr "^BG%s^K3 Ð±Ñ\8bл Ð¾Ð¶Ð¸Ð²Ð»Ñ\91н Ð²Ð·Ñ\80Ñ\8bвом Ñ\81воей Ð³Ñ\80анаÑ\82Ñ\8b"
+msgstr "^BG%s^K3 оживлён взрывом своей гранаты"
 
 #: qcsrc/common/notifications/all.inc:367
 #, c-format
 msgid "^BG%s^K3 was automatically revived after %s second(s)"
-msgstr "^BG%s^K3 Ð±Ñ\8bл Ð°Ð²Ñ\82омаÑ\82иÑ\87еÑ\81ки Ð¾Ð¶Ð¸Ð²Ð»Ñ\91н Ð¿Ð¾Ñ\81ле %s Ñ\81екÑ\83нд(Ñ\8b)"
+msgstr "^BG%s^K3 автоматически оживлён после %s секунд(ы)"
 
 #: qcsrc/common/notifications/all.inc:368
 #, c-format
@@ -2708,7 +2707,7 @@ msgstr "Контрольная точка %s^BG команды ^TC^TT^BG был
 
 #: qcsrc/common/notifications/all.inc:414
 msgid "^TC^TT^BG generator has been destroyed"
-msgstr "^TC^TT^BG генератор был уничтожен"
+msgstr "^TC^TT^BG генератор уничтожен"
 
 #: qcsrc/common/notifications/all.inc:415
 msgid "^TC^TT^BG generator spontaneously combusted due to overtime!"
@@ -2894,7 +2893,7 @@ msgstr "^BG%s%s^K1 попал под раздачу тока из Дуговой
 #: qcsrc/common/notifications/all.inc:457
 #, c-format
 msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Arc bolts%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð²Ð·Ð¾Ñ\80ван ÐºÑ\80ивÑ\8bми Ð±Ð¾Ð»Ñ\82ами%s%s ^BG%s^K1's"
+msgstr "^BG%s%s^K1 взорван кривыми болтами%s%s ^BG%s^K1's"
 
 #: qcsrc/common/notifications/all.inc:458
 #, c-format
@@ -2934,7 +2933,7 @@ msgstr "^BG%s^K1 взорвал себя с помощью Разрушител
 #: qcsrc/common/notifications/all.inc:465
 #, c-format
 msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"
-msgstr "^BG%s%s^K1 был разорван зарядом Электро от ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван зарядом Электро ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:466
 #, c-format
@@ -2964,7 +2963,7 @@ msgstr "^BG%s%s^K1 оказался слишком близко к огненн
 #: qcsrc/common/notifications/all.inc:471
 #, c-format
 msgid "^BG%s%s^K1 got burnt by ^BG%s^K1's firemine%s%s"
-msgstr "^BG%s%s^K1 был сожжён зажигательной миной ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 сожжён зажигательной миной ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:472
 #, c-format
@@ -2974,7 +2973,7 @@ msgstr "^BG%s^K1 должен был выбрать пушку поменьше%
 #: qcsrc/common/notifications/all.inc:473
 #, c-format
 msgid "^BG%s^K1 forgot about their firemine%s%s"
-msgstr "^BG%s^K1 забыл о своей зажигательной мине ds%s%s"
+msgstr "^BG%s^K1 забыл о своей зажигательной мине %s%s"
 
 #: qcsrc/common/notifications/all.inc:474
 #, c-format
@@ -2984,7 +2983,7 @@ msgstr "^BG%s%s^K1 утрамбован очередью из Хагара от
 #: qcsrc/common/notifications/all.inc:475
 #, c-format
 msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s"
-msgstr "^BG%s%s^K1 обстрелян из Хагара со стороны ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 обстрелян из Хагара ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:476
 #, c-format
@@ -3100,7 +3099,7 @@ msgstr "^BG%s%s^K1 не смог спрятаться от Винтовки ^BG%
 #: qcsrc/common/notifications/all.inc:497
 #, c-format
 msgid "^BG%s%s^K1 was sawn in half by ^BG%s^K1's Rocket Propelled Chainsaw%s%s"
-msgstr "^BG%s%s^K1 был распилен пополам Реактивной Бензопилой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 распилен пополам Реактивной Бензопилой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:498
 #, c-format
@@ -3110,7 +3109,7 @@ msgstr "^BG%s%s^K1 почти уклонился от Реактивной Бе
 #: qcsrc/common/notifications/all.inc:499
 #, c-format
 msgid "^BG%s^K1 was sawn in half by their own Rocket Propelled Chainsaw%s%s"
-msgstr "^BG%s^K1 был распилен пополам своей же Реактивной Бензопилой%s%s"
+msgstr "^BG%s^K1 распилен пополам своей же Реактивной Бензопилой%s%s"
 
 #: qcsrc/common/notifications/all.inc:500
 #, c-format
@@ -3142,7 +3141,7 @@ msgstr "^BG%s%s^K1 застрелен из Шоковой Волны ^BG%s^K1%s%
 #: qcsrc/common/notifications/all.inc:505
 #, c-format
 msgid "^BG%s%s^K1 slapped ^BG%s^K1 around a bit with a large Shockwave%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¾Ñ\82Ñ\88лÑ\91пан ^BG%s^K1 Ð¾Ð³Ñ\80омной Ð¨Ð¾ÐºÐ¾Ð²Ð¾Ð¹ Ð\92олной%s%s"
+msgstr "^BG%s%s^K1 отшлёпан ^BG%s^K1 огромной Шоковой Волной%s%s"
 
 #: qcsrc/common/notifications/all.inc:506
 #, c-format
@@ -3172,7 +3171,7 @@ msgstr "^BGУ %s^K1 завяли уши от собственной игры @!#
 #: qcsrc/common/notifications/all.inc:511
 #, c-format
 msgid "^BG%s%s^K1 has been sublimated by ^BG%s^K1's Vaporizer%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¿Ñ\80еобÑ\80азован Ð² Ð¿Ð°Ñ\80 Ð\98Ñ\81паÑ\80иÑ\82елем ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 преобразован в пар Испарителем ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:512
 #, c-format
@@ -3824,7 +3823,7 @@ msgstr "^BGОжидание присоединения %s игроков(а)..."
 
 #: qcsrc/common/notifications/all.inc:723
 msgid "^BGYour weapon has been downgraded until you find some ammo!"
-msgstr "^BGÐ\92аÑ\88е Ð¾Ñ\80Ñ\83жие Ð±Ñ\8bло Ð¾Ñ\81лаблено Ð´Ð¾ Ñ\82еÑ\85 Ð¿Ð¾Ñ\80, Ð¿Ð¾ÐºÐ° Ð²Ñ\8b Ð½Ðµ Ð½Ð°Ð¹Ð´Ñ\91Ñ\82е Ð¿Ð°Ñ\82Ñ\80онÑ\8b!"
+msgstr "^BGВаше оружие ослаблено до тех пор, пока вы не найдёте патроны!"
 
 #: qcsrc/common/notifications/all.inc:724
 msgid "^F4^COUNT^BG left to find some ammo!"
@@ -3990,7 +3989,7 @@ msgstr "^F2Гонка окончена, завершите ваш круг!"
 
 #: qcsrc/common/notifications/all.inc:764
 msgid "^BGSecondary fire inflicts no damage!"
-msgstr "^BGÐ\92Ñ\82оÑ\80иÑ\87ный режим огня не наносит урона!"
+msgstr "^BGÐ\90лÑ\8cÑ\82еÑ\80наÑ\82ивный режим огня не наносит урона!"
 
 #: qcsrc/common/notifications/all.inc:766
 msgid "^BGSequence completed!"
@@ -4087,7 +4086,7 @@ msgstr "основной"
 
 #: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
 msgid "secondary"
-msgstr "вÑ\82оÑ\80иÑ\87ный"
+msgstr "алÑ\8cÑ\82еÑ\80наÑ\82ивный"
 
 #: qcsrc/common/notifications/all.qh:410
 msgid "point"
@@ -4295,7 +4294,7 @@ msgstr ", прервав серию из %d очков подряд"
 #: qcsrc/common/notifications/all.qh:610
 #, c-format
 msgid ", losing their %d frag spree"
-msgstr ", Ð¾ÐºÐ¾Ð½Ñ\87ив свою серию из %d убийств подряд"
+msgstr ", Ð¿Ñ\80еÑ\80вав свою серию из %d убийств подряд"
 
 #: qcsrc/common/notifications/all.qh:611
 #, c-format
@@ -6345,8 +6344,8 @@ msgid ""
 msgstr ""
 "Игроки получат только одно оружие, которое немедленно убьёт противника с "
 "одного выстрела. Если игрок испытывает недостаток патронов, у него есть 10 "
-"Ñ\81екÑ\83нд, Ñ\87Ñ\82обÑ\8b Ð½Ð°Ð¹Ñ\82и ÐµÑ\89Ñ\91, Ð¸Ð½Ð°Ñ\87е Ð¾Ð½ Ð²Ñ\81Ñ\82Ñ\80еÑ\82иÑ\82 Ñ\81меÑ\80Ñ\82Ñ\8c. Ð ÐµÐ¶Ð¸Ð¼ Ð²Ñ\82оÑ\80иÑ\87ного Ð¾Ð³Ð½Ñ\8f Ð½Ðµ "
-"наносит урона, но он хорош для трюков."
+"Ñ\81екÑ\83нд, Ñ\87Ñ\82обÑ\8b Ð½Ð°Ð¹Ñ\82и ÐµÑ\89Ñ\91, Ð¸Ð½Ð°Ñ\87е Ð¾Ð½ Ð²Ñ\81Ñ\82Ñ\80еÑ\82иÑ\82 Ñ\81меÑ\80Ñ\82Ñ\8c. Ð ÐµÐ¶Ð¸Ð¼ Ð°Ð»Ñ\8cÑ\82еÑ\80наÑ\82ивного "
+"огнÑ\8f Ð½Ðµ Ð½Ð°Ð½Ð¾Ñ\81иÑ\82 Ñ\83Ñ\80она, Ð½Ð¾ Ð¾Ð½ Ñ\85оÑ\80оÑ\88 Ð´Ð»Ñ\8f Ñ\82Ñ\80Ñ\8eков."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
 msgid ""
@@ -8361,11 +8360,11 @@ msgstr "Беречь время процессора для других при
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:129
 msgid "Show frames per second"
-msgstr "Показывать кол-во кадров в секунду (FPS)"
+msgstr "Показывать счётчик кадров (FPS)"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:130
 msgid "Show your rendered frames per second"
-msgstr "Показывать кол-во отрисованных кадров в секунду"
+msgstr "Показывать количество отрисованных кадров в секунду"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
 msgid "Menu tooltips:"
@@ -8833,7 +8832,7 @@ msgstr "Победитель"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:32
 msgid "join 'best' team (auto-select)"
-msgstr "пÑ\80иÑ\81оединиÑ\82Ñ\8cÑ\81Ñ\8f Ðº 'лÑ\83Ñ\87Ñ\88ей' ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ (авÑ\82овÑ\8bбоÑ\80)"
+msgstr "авÑ\82овÑ\8bбоÑ\80 'лÑ\83Ñ\87Ñ\88ей' ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ\8b"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:33
 msgid "Autoselect team (recommended)"
index a57869003c3137e29edaeb5a61e85de61d18b95a..f164a92f212400290df133137b41875ca61b47c6 100644 (file)
@@ -20,8 +20,10 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
-"%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
+"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != "
+"11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % "
+"100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || "
+"(n % 100 >=11 && n % 100 <=14 )) ? 2: 3);\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
index 0287246689cb31b05e8ad8136f331899289c44eb..050f5f680ab9d1bf62be321dca7d5c12a480d102 100644 (file)
@@ -7,14 +7,16 @@
 # Antoni Das <Antonidas159@gmail.com>, 2015,2017
 # sapphireliu <balancedliu@gmail.com>, 2014
 # kalawore <kalawore@outlook.com>, 2015
+# Losier Blackheath <losier.cc@gmail.com>, 2018
 # sapphireliu <balancedliu@gmail.com>, 2014
+# 茂森 杜 <dumaosen_main01@outlook.com>, 2018
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 23:30+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-06-02 05:39+0000\n"
+"Last-Translator: Losier Blackheath <losier.cc@gmail.com>\n"
 "Language-Team: Chinese (China) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/zh_CN/)\n"
 "Language: zh_CN\n"
@@ -180,11 +182,11 @@ msgstr "团队菜单"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating this player:"
-msgstr ""
+msgstr "^1观看这个玩家:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:209
 msgid "^1Spectating you:"
-msgstr ""
+msgstr "^1观看你自己:"
 
 #: qcsrc/client/hud/panel/infomessages.qc:225
 msgid "^7Press ^3ESC ^7to show HUD options."
@@ -192,7 +194,7 @@ msgstr "^7按下 ^3ESC ^7来显示HUD设置。"
 
 #: qcsrc/client/hud/panel/infomessages.qc:226
 msgid "^3Doubleclick ^7a panel for panel-specific options."
-msgstr ""
+msgstr "^3双击 ^7面板以获取面板特定选项。"
 
 #: qcsrc/client/hud/panel/infomessages.qc:227
 msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
@@ -200,7 +202,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/infomessages.qc:228
 msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
-msgstr ""
+msgstr "^3ALT ^7+ ^3箭头键 ^7以微调。"
 
 #: qcsrc/client/hud/panel/modicons.qc:566
 msgid "Personal best"
@@ -250,11 +252,11 @@ msgstr "QMCMD^好游戏"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:797
 msgid "QMCMD^hi / good luck"
-msgstr "QMCMD^hi / 祝好运"
+msgstr "QMCMD^hi / 祝好运"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:797
 msgid "QMCMD^hi / good luck and have fun"
-msgstr ""
+msgstr "QMCMD^hi / 祝你好运,玩的开心"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:802
 #: qcsrc/client/hud/panel/quickmenu.qc:818
@@ -339,7 +341,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier (l:%y^7)"
-msgstr ""
+msgstr "QMCMD^killed flagcarrier (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
@@ -356,7 +358,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "QMCMD^掉落武器, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
@@ -432,11 +434,11 @@ msgstr "QMCMD^第一人称"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:842
 msgid "QMCMD^3rd person around player"
-msgstr ""
+msgstr "QMCMD^玩家周围的第三人称视角"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:843
 msgid "QMCMD^3rd person behind"
-msgstr ""
+msgstr "QMCMD^身后的第三人称视角"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:849
 #: qcsrc/client/hud/panel/quickmenu.qc:854
@@ -490,7 +492,7 @@ msgstr "QMCMD^延长比赛时间"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:871
 msgid "QMCMD^Shuffle teams"
-msgstr ""
+msgstr "QMCMD^随机组队"
 
 #: qcsrc/client/hud/panel/racetimer.qc:37
 #, c-format
@@ -546,11 +548,11 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:81
 msgid "SCO^captime"
-msgstr ""
+msgstr "SCO^captime"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:82
 msgid "SCO^deaths"
-msgstr "SCO^死亡"
+msgstr "SCO^死亡"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:83
 msgid "SCO^destroyed"
@@ -586,19 +588,19 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:91
 msgid "SCO^kdratio"
-msgstr ""
+msgstr "SCO^击杀/死亡比"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:92
 msgid "SCO^k/d"
-msgstr ""
+msgstr "SCO^击杀/死亡"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:93
 msgid "SCO^kdr"
-msgstr ""
+msgstr "SCO^击杀/死亡比"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:94
 msgid "SCO^kills"
-msgstr ""
+msgstr "SCO^击杀数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:95
 msgid "SCO^laps"
@@ -606,7 +608,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:96
 msgid "SCO^lives"
-msgstr ""
+msgstr "SCO^生命数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:97
 msgid "SCO^losses"
@@ -622,7 +624,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:100
 msgid "SCO^nick"
-msgstr ""
+msgstr "SCO^昵称"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:101
 msgid "SCO^objectives"
@@ -650,15 +652,15 @@ msgstr "SCO^排名"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:107
 msgid "SCO^returns"
-msgstr ""
+msgstr "SCO^带回数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:108
 msgid "SCO^revivals"
-msgstr ""
+msgstr "SCO^重生数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:109
 msgid "SCO^rounds won"
-msgstr ""
+msgstr "SCO^赢局数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:110
 msgid "SCO^score"
@@ -666,7 +668,7 @@ msgstr "SCO^分数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:111
 msgid "SCO^suicides"
-msgstr ""
+msgstr "SCO^自杀数"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:112
 msgid "SCO^takes"
@@ -711,11 +713,11 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:305
 msgid "^3ping^7                     Ping time\n"
-msgstr "^3延迟^7                     延迟时间\n"
+msgstr "^3ping^7                     延迟\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:306
 msgid "^3pl^7                       Packet loss\n"
-msgstr ""
+msgstr "^3pl^7                       丢包率\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:307
 msgid "^3elo^7                      Player ELO\n"
@@ -731,23 +733,23 @@ msgstr "^3死亡^7                   死亡数量\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:310
 msgid "^3suicides^7                 Number of suicides\n"
-msgstr ""
+msgstr "^3suicides^7                 自杀数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:311
 msgid "^3frags^7                    kills - suicides\n"
-msgstr ""
+msgstr "^3frags^7                    击杀数 - 自杀数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:312
 msgid "^3kd^7                       The kill-death ratio\n"
-msgstr ""
+msgstr "^3kd^7                       击杀-死亡比\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:313
 msgid "^3dmg^7                      The total damage done\n"
-msgstr ""
+msgstr "^3dmg^7                      造成的总破坏值\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:314
 msgid "^3dmgtaken^7                 The total damage taken\n"
-msgstr ""
+msgstr "^3dmgtaken^7                 遭受的总破坏值\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:315
 msgid "^3sum^7                      frags - deaths\n"
@@ -758,6 +760,7 @@ msgid ""
 "^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was "
 "captured\n"
 msgstr ""
+"^3caps^7                     旗帜(CTF)或钥匙(KeyHunt)被夺取的频率\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:317
 msgid ""
@@ -771,19 +774,19 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:319
 msgid "^3fckills^7                  Number of flag carrier kills\n"
-msgstr ""
+msgstr "^3fckills^7                  击杀旗帜携带者数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
-msgstr ""
+msgstr "^3returns^7                  带回旗帜数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:321
 msgid "^3drops^7                    Number of flag drops\n"
-msgstr ""
+msgstr "^3drops^7                    旗帜掉落数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:322
 msgid "^3lives^7                    Number of lives (LMS)\n"
-msgstr ""
+msgstr "^3lives^7                    生命数 (LMS)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:323
 msgid "^3rank^7                     Player rank\n"
@@ -791,21 +794,21 @@ msgstr "^3排名^7                     玩家排名\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:324
 msgid "^3pushes^7                   Number of players pushed into void\n"
-msgstr ""
+msgstr "^3pushes^7                   被推入虚空中的玩家数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:325
 msgid ""
 "^3destroyed^7                Number of keys destroyed by pushing them into "
 "void\n"
-msgstr ""
+msgstr "^3destroyed^7                被推入虚空而销毁的钥匙数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:326
 msgid "^3kckills^7                  Number of keys carrier kills\n"
-msgstr ""
+msgstr "^3kckills^7                  击杀钥匙携带者数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:327
 msgid "^3losses^7                   Number of times a key was lost\n"
-msgstr ""
+msgstr "^3losses^7                   丢失钥匙数\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:328
 msgid "^3laps^7                     Number of laps finished (race/cts)\n"
@@ -839,7 +842,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:335
 msgid "^3score^7                    Total score\n"
-msgstr ""
+msgstr "^3score^7                    总分\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:338
 msgid ""
@@ -903,7 +906,7 @@ msgstr "秘密已发现:"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Capture time rankings"
-msgstr ""
+msgstr "占领时间排名"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Rankings"
@@ -927,7 +930,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/scoreboard.qc:1604
 #, c-format
 msgid "Spectators"
-msgstr "观察者"
+msgstr "观"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1619
 #, c-format
@@ -949,21 +952,21 @@ msgstr "或者"
 #: qcsrc/client/hud/panel/scoreboard.qc:1645
 #, c-format
 msgid " until ^3%s %s^7"
-msgstr ""
+msgstr " 直到 ^3%s %s^7"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1639
 #: qcsrc/client/hud/panel/scoreboard.qc:1646
 #: qcsrc/client/hud/panel/scoreboard.qc:1658
 #: qcsrc/client/hud/panel/scoreboard.qc:1665
 msgid "SCO^points"
-msgstr ""
+msgstr "SCO^分"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1640
 #: qcsrc/client/hud/panel/scoreboard.qc:1647
 #: qcsrc/client/hud/panel/scoreboard.qc:1659
 #: qcsrc/client/hud/panel/scoreboard.qc:1666
 msgid "SCO^is beaten"
-msgstr ""
+msgstr "SCO^被击败"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1657
 #: qcsrc/client/hud/panel/scoreboard.qc:1664
@@ -992,11 +995,11 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/vote.qc:29
 msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
-msgstr ""
+msgstr "^2名字^7而不是“^1匿名玩家^7”在统计信息中"
 
 #: qcsrc/client/hud/panel/vote.qc:115
 msgid "A vote has been called for:"
-msgstr ""
+msgstr "一轮投票被发起:"
 
 #: qcsrc/client/hud/panel/vote.qc:117
 msgid "Allow servers to store and display your name?"
@@ -1061,7 +1064,7 @@ msgstr "节点"
 #: qcsrc/client/main.qc:1264
 #, c-format
 msgid "%s (not bound)"
-msgstr ""
+msgstr "%s (未绑定)"
 
 #: qcsrc/client/mapvoting.qc:49
 msgid " (1 vote)"
@@ -1112,15 +1115,15 @@ msgstr "节点计时器"
 
 #: qcsrc/client/view.qc:1385
 msgid "Capture progress"
-msgstr ""
+msgstr "占领进度"
 
 #: qcsrc/client/view.qc:1390
 msgid "Revival progress"
-msgstr ""
+msgstr "重生进度"
 
 #: qcsrc/common/command/generic.qc:157
 msgid "error creating curl handle\n"
-msgstr ""
+msgstr "创建下载描述符错误\n"
 
 #: qcsrc/common/command/generic.qc:403
 msgid "Notification restart command only works with cl_cmd and sv_cmd.\n"
@@ -1128,23 +1131,23 @@ msgstr ""
 
 #: qcsrc/common/gamemodes/gamemode/nexball/weapon.qh:7
 msgid "Ball Stealer"
-msgstr ""
+msgstr "偷球者"
 
 #: qcsrc/common/items/item/armor.qh:111
 msgid "Big armor"
-msgstr ""
+msgstr "大护甲"
 
 #: qcsrc/common/items/item/armor.qh:147
 msgid "Mega armor"
-msgstr ""
+msgstr "超级护甲"
 
 #: qcsrc/common/items/item/health.qh:111
 msgid "Big health"
-msgstr ""
+msgstr "大血包"
 
 #: qcsrc/common/items/item/health.qh:147
 msgid "Mega health"
-msgstr ""
+msgstr "超级血包"
 
 #: qcsrc/common/items/item/jetpack.qh:35
 msgid "Jet Pack"
@@ -1156,7 +1159,7 @@ msgstr "恢复燃料"
 
 #: qcsrc/common/items/item/powerup.qh:44
 msgid "Strength"
-msgstr "加强"
+msgstr "神力"
 
 #: qcsrc/common/items/item/powerup.qh:76
 msgid "Shield"
@@ -1189,7 +1192,7 @@ msgstr "赛跑"
 
 #: qcsrc/common/mapinfo.qh:126
 msgid "Race against other players to the finish line"
-msgstr ""
+msgstr "与其他玩家赛跑到达终点线"
 
 #: qcsrc/common/mapinfo.qh:160
 msgid "Race CTS"
@@ -1201,7 +1204,7 @@ msgstr ""
 
 #: qcsrc/common/mapinfo.qh:184
 msgid "Help your team score the most frags against the enemy team"
-msgstr ""
+msgstr "在与敌方队伍的斗争中帮助你的队伍拿到最多人头数"
 
 #: qcsrc/common/mapinfo.qh:184
 msgid "Team Deathmatch"
@@ -1219,7 +1222,7 @@ msgstr "找到并将敌人的旗帜带到你的基地并保护你的基地"
 
 #: qcsrc/common/mapinfo.qh:249
 msgid "Clan Arena"
-msgstr ""
+msgstr "组队竞技"
 
 #: qcsrc/common/mapinfo.qh:249
 msgid "Kill all enemy teammates to win the round"
@@ -1249,11 +1252,11 @@ msgstr "突击"
 msgid ""
 "Destroy obstacles to find and destroy the enemy power core before time runs "
 "out"
-msgstr ""
+msgstr "在一定时间内摧毁障碍物以寻找并摧毁敌方能量核心"
 
 #: qcsrc/common/mapinfo.qh:371
 msgid "Capture control points to reach and destroy the enemy generator"
-msgstr ""
+msgstr "占领控制点以到达并摧毁敌方发电器"
 
 #: qcsrc/common/mapinfo.qh:371
 msgid "Onslaught"
@@ -1261,7 +1264,7 @@ msgstr "猛攻"
 
 #: qcsrc/common/mapinfo.qh:387
 msgid "Nexball"
-msgstr ""
+msgstr "Nexball"
 
 #: qcsrc/common/mapinfo.qh:387
 msgid "Shoot and kick the ball into the enemies goal, keep your goal clean"
@@ -1275,7 +1278,7 @@ msgstr "冻结式对战"
 msgid ""
 "Kill enemies to freeze them, stand next to frozen teammates to revive them; "
 "freeze all enemies to win"
-msgstr ""
+msgstr "杀死敌人以将他们封冻,站在被封冻的队友边以复活他们;封冻所有敌人即胜利"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Hold the ball to get points for kills"
@@ -1291,7 +1294,7 @@ msgstr "入侵"
 
 #: qcsrc/common/mapinfo.qh:461
 msgid "Survive against waves of monsters"
-msgstr ""
+msgstr "在许多波怪物的攻势下幸存"
 
 #: qcsrc/common/minigames/cl_minigames.qc:383
 msgid "It's your turn"
@@ -1329,7 +1332,7 @@ msgstr "小游戏"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1168
 msgid "Better luck next time!"
-msgstr ""
+msgstr "祝你下次好运!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1172
 msgid "Tubular! Press \"Next Level\" to continue!"
@@ -1349,7 +1352,7 @@ msgstr ""
 
 #: qcsrc/common/minigames/minigame/bd.qc:1404
 msgid "Next Level"
-msgstr ""
+msgstr "下一关"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1405
 msgid "Restart"
@@ -1455,7 +1458,7 @@ msgstr ""
 #: qcsrc/common/minigames/minigame/pp.qc:582
 #: qcsrc/common/minigames/minigame/ttt.qc:665
 msgid "Next Match"
-msgstr ""
+msgstr "下场比赛"
 
 #: qcsrc/common/minigames/minigame/ps.qc:478
 #, c-format
@@ -1592,11 +1595,11 @@ msgstr ""
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:20
 msgid "Font size minimum:"
-msgstr ""
+msgstr "最小字体大小:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:25
 msgid "Font size maximum:"
-msgstr ""
+msgstr "最大字体大小:"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:30
 msgid "Accumulate range:"
@@ -1753,7 +1756,7 @@ msgstr "粉红军基地"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:29
 msgid "Return flag here"
-msgstr ""
+msgstr "把旗帜带回这里"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:31
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:32
@@ -1814,7 +1817,7 @@ msgstr "载具"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:62
 msgid "Intruder!"
-msgstr ""
+msgstr "入侵者!"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:64
 msgid "Tagged"
@@ -1836,12 +1839,12 @@ msgstr "^1服务器提示:"
 
 #: qcsrc/common/notifications/all.inc:239
 msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
-msgstr ""
+msgstr "^F4注意:^BG比赛过程中观众聊天不会被发送给玩家"
 
 #: qcsrc/common/notifications/all.inc:241
 #, c-format
 msgid "^BG%s^BG captured the ^TC^TT^BG flag"
-msgstr ""
+msgstr "^BG%s^BG捕获了^TC^TT^BG旗帜"
 
 #: qcsrc/common/notifications/all.inc:242
 #, c-format
@@ -1849,16 +1852,17 @@ msgid ""
 "^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds, breaking ^BG"
 "%s^BG's previous record of ^F2%s^BG seconds"
 msgstr ""
+"^BG%s^BG捕获^TC^TT^BG旗帜用了^F1%s^BG秒,打破了原来^BG%s^BG的^F2%s^BG秒的记录"
 
 #: qcsrc/common/notifications/all.inc:243
 #, c-format
 msgid "^BG%s^BG captured the flag"
-msgstr ""
+msgstr "^BG%s^BG捕获旗帜"
 
 #: qcsrc/common/notifications/all.inc:244
 #, c-format
 msgid "^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"
-msgstr ""
+msgstr "^BG%s^BG捕获^TC^TT^BG旗帜用了^F1%s^BG秒"
 
 #: qcsrc/common/notifications/all.inc:245
 #, c-format
@@ -1866,66 +1870,68 @@ msgid ""
 "^BG%s^BG captured the ^TC^TT^BG flag in ^F2%s^BG seconds, failing to break "
 "^BG%s^BG's previous record of ^F1%s^BG seconds"
 msgstr ""
+"^BG%s^BG捕获^TC^TT^BG旗帜用了^F2%s^BG秒,未能打破原来^BG%s^BG的^F1%s^BG秒的记"
+"录"
 
 #: qcsrc/common/notifications/all.inc:246
 msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜被它的所有者带回基地"
 
 #: qcsrc/common/notifications/all.inc:247
 msgid "^BGThe flag was returned by its owner"
-msgstr ""
+msgstr "^BG旗帜被它的所有者带回"
 
 #: qcsrc/common/notifications/all.inc:248
 msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜被摧毁并回到基地"
 
 #: qcsrc/common/notifications/all.inc:249
 msgid "^BGThe flag was destroyed and returned to base"
-msgstr ""
+msgstr "^BG旗帜被摧毁并回到基地"
 
 #: qcsrc/common/notifications/all.inc:250
 msgid "^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜掉落在基地并自己返回"
 
 #: qcsrc/common/notifications/all.inc:251
 msgid "^BGThe flag was dropped in the base and returned itself"
-msgstr ""
+msgstr "^BG旗帜掉落在基地并自己返回"
 
 #: qcsrc/common/notifications/all.inc:252
 msgid ""
 "^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to "
 "base"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜掉落在无法到达的地方而自动回到基地"
 
 #: qcsrc/common/notifications/all.inc:253
 msgid "^BGThe flag fell somewhere it couldn't be reached and returned to base"
-msgstr ""
+msgstr "^BG旗帜掉落在无法到达的地方而自动回到基地"
 
 #: qcsrc/common/notifications/all.inc:254
 #, c-format
 msgid ""
 "^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned "
 "itself"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜在^F1%.2f^BG秒后失去耐心而自动返回基地"
 
 #: qcsrc/common/notifications/all.inc:255
 #, c-format
 msgid ""
 "^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"
-msgstr ""
+msgstr "^BG旗帜在 ^F1%.2f^BG秒后失去耐心而自动返回基地"
 
 #: qcsrc/common/notifications/all.inc:256
 msgid "^BGThe ^TC^TT^BG flag has returned to the base"
-msgstr ""
+msgstr "^BG^TC^TT^BG旗帜已回到基地"
 
 #: qcsrc/common/notifications/all.inc:257
 msgid "^BGThe flag has returned to the base"
-msgstr ""
+msgstr "^BG旗帜已回到基地"
 
 #: qcsrc/common/notifications/all.inc:258
 #, c-format
 msgid "^BG%s^BG lost the ^TC^TT^BG flag"
-msgstr ""
+msgstr "^BG%s^BG失去了^TC^TT^BG旗帜"
 
 #: qcsrc/common/notifications/all.inc:259
 #, c-format
@@ -1935,24 +1941,24 @@ msgstr "^BG%s^BG 丢掉了旗帜"
 #: qcsrc/common/notifications/all.inc:260
 #, c-format
 msgid "^BG%s^BG got the ^TC^TT^BG flag"
-msgstr ""
+msgstr "^BG%s^BG拿到了^TC^TT^BG旗帜"
 
 #: qcsrc/common/notifications/all.inc:261
 #, c-format
 msgid "^BG%s^BG got the flag"
-msgstr ""
+msgstr "^BG%s^BG拿到了旗帜"
 
 #: qcsrc/common/notifications/all.inc:262
 #: qcsrc/common/notifications/all.inc:263
 #, c-format
 msgid "^BG%s^BG returned the ^TC^TT^BG flag"
-msgstr ""
+msgstr "^BG%s^BG带回^TC^TT^BG旗帜"
 
 #: qcsrc/common/notifications/all.inc:265
 #: qcsrc/common/notifications/all.inc:553
 #, c-format
 msgid "^F2Throwing coin... Result: %s^F2!"
-msgstr ""
+msgstr "^F2丢硬币……结果:%s^F2!"
 
 #: qcsrc/common/notifications/all.inc:267
 msgid "^BGYou don't have any fuel for the ^F1Jetpack"
@@ -1964,11 +1970,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:271
 msgid "^F1Round already started, you will join the game in the next round"
-msgstr ""
+msgstr "^F1这轮比赛已经开始,你将在下一轮加入游戏"
 
 #: qcsrc/common/notifications/all.inc:272
 msgid "^F2You will spectate in the next round"
-msgstr ""
+msgstr "^F2你将在下一轮旁观"
 
 #: qcsrc/common/notifications/all.inc:274
 #, c-format
@@ -2008,7 +2014,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:279
 #, c-format
 msgid "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:280
 #, c-format
@@ -2125,17 +2131,17 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:300
 #, c-format
 msgid "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Racer exploded%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1被 ^BG%s^K1的火箭弹给炸飞了%s%s"
 
 #: qcsrc/common/notifications/all.inc:301
 #, c-format
 msgid "^BG%s%s^K1 was bolted down by ^BG%s^K1's Racer%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1给^BG%s^K1的火箭枪炸翻了%s%s"
 
 #: qcsrc/common/notifications/all.inc:302
 #, c-format
 msgid "^BG%s%s^K1 couldn't find shelter from ^BG%s^K1's Racer%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1来不及躲闪^BG%s^K1的火箭弹%s%s"
 
 #: qcsrc/common/notifications/all.inc:303
 #, c-format
@@ -2240,12 +2246,12 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:321
 #, c-format
 msgid "^BG%s^K1 joins the Zombies%s%s"
-msgstr ""
+msgstr "^BG%s^K1参演行尸走肉%s%s"
 
 #: qcsrc/common/notifications/all.inc:322
 #, c-format
 msgid "^BG%s^K1 was given kung fu lessons by a Zombie%s%s"
-msgstr ""
+msgstr "^K1僵尸给^BG%s^K1上了一节功夫课%s%s"
 
 #: qcsrc/common/notifications/all.inc:323
 #: qcsrc/common/notifications/all.inc:325
@@ -2282,7 +2288,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:328
 #, c-format
 msgid "^BG%s^K1 died%s%s. What's the point of living without ammo?"
-msgstr ""
+msgstr "^BG%s^K1卒%s%s。与其没有弹药的苟活,不如轰轰烈烈的牺牲"
 
 #: qcsrc/common/notifications/all.inc:328
 #, c-format
@@ -2367,7 +2373,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:344
 #, c-format
 msgid "^BG%s^K1 got served some superheated plasma from a turret%s%s"
-msgstr ""
+msgstr "^BG%s^K1 被炮台发出的高温离子弹教会做人%s%s"
 
 #: qcsrc/common/notifications/all.inc:345
 #, c-format
@@ -2422,37 +2428,37 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:355
 #, c-format
 msgid "^BG%s^K1 got caught in the blast of a Racer explosion%s%s"
-msgstr ""
+msgstr "^BG%s^K1被爆炸的火箭弹打中了%s%s"
 
 #: qcsrc/common/notifications/all.inc:356
 #, c-format
 msgid "^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"
-msgstr ""
+msgstr "^BG%s^K1来不及躲闪火箭弹%s%s"
 
 #: qcsrc/common/notifications/all.inc:359
 #, c-format
 msgid "^BG%s^K1 was betrayed by ^BG%s^K1%s%s"
-msgstr ""
+msgstr "^BG%s^K1被^BG%s^K1背叛%s%s"
 
 #: qcsrc/common/notifications/all.inc:361
 #, c-format
 msgid "^BG%s^BG%s^BG (%s %s every %s seconds)"
-msgstr ""
+msgstr "^BG%s^BG%s^BG(%s %s每%s秒)"
 
 #: qcsrc/common/notifications/all.inc:363
 #, c-format
 msgid "^BG%s^K1 was frozen by ^BG%s"
-msgstr ""
+msgstr "^BG%s^K1被^BG%s^K1封冻"
 
 #: qcsrc/common/notifications/all.inc:364
 #, c-format
 msgid "^BG%s^K3 was revived by ^BG%s"
-msgstr ""
+msgstr "^BG%s^K3被^BG%s^K3复活"
 
 #: qcsrc/common/notifications/all.inc:365
 #, c-format
 msgid "^BG%s^K3 was revived by falling"
-msgstr ""
+msgstr "^BG%s^K3由于跌落而复活"
 
 #: qcsrc/common/notifications/all.inc:366
 #, c-format
@@ -2472,23 +2478,23 @@ msgstr "^BG%s^K1 把自己冰冻了"
 #: qcsrc/common/notifications/all.inc:370
 #: qcsrc/common/notifications/all.inc:684
 msgid "^TC^TT^BG team wins the round"
-msgstr ""
+msgstr "^TC^TT^BG赢了这一局"
 
 #: qcsrc/common/notifications/all.inc:371
 #: qcsrc/common/notifications/all.inc:685
 #, c-format
 msgid "^BG%s^BG wins the round"
-msgstr ""
+msgstr "^BG%s^BG赢了这一局"
 
 #: qcsrc/common/notifications/all.inc:372
 #: qcsrc/common/notifications/all.inc:548
 msgid "^BGRound tied"
-msgstr ""
+msgstr "^BG平局"
 
 #: qcsrc/common/notifications/all.inc:373
 #: qcsrc/common/notifications/all.inc:549
 msgid "^BGRound over, there's no winner"
-msgstr ""
+msgstr "^BG这一局结束,没有赢家"
 
 #: qcsrc/common/notifications/all.inc:375
 #, c-format
@@ -2674,7 +2680,7 @@ msgstr "^BG%s^K1 捡到了加速"
 #: qcsrc/common/notifications/all.inc:420
 #, c-format
 msgid "^BG%s^K1 picked up Strength"
-msgstr "^BG%s^K1 捡到了力量"
+msgstr "^BG%s^K1 捡到了神力"
 
 #: qcsrc/common/notifications/all.inc:422
 #, c-format
@@ -2836,12 +2842,12 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:460
 #, c-format
 msgid "^BG%s%s^K1 felt the strong pull of ^BG%s^K1's Crylink%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1 感受到 ^BG%s^K1手里的紫电的强大推力%s%s"
 
 #: qcsrc/common/notifications/all.inc:461
 #, c-format
 msgid "^BG%s^K1 felt the strong pull of their Crylink%s%s"
-msgstr ""
+msgstr "^BG%s^K1 感受到自己手里的紫电的强大推力%s%s"
 
 #: qcsrc/common/notifications/all.inc:462
 #, c-format
@@ -2983,22 +2989,22 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:489
 #, c-format
 msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1离^BG%s^K1打出的榴弹太近了%s%s"
 
 #: qcsrc/common/notifications/all.inc:490
 #, c-format
 msgid "^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"
-msgstr ""
+msgstr "^BG%s%s^K1 吃了一记 ^BG%s^K1的榴弹%s%s"
 
 #: qcsrc/common/notifications/all.inc:491
 #, c-format
 msgid "^BG%s^K1 didn't see their own Mortar grenade%s%s"
-msgstr ""
+msgstr "^BG%s^K1 没看到他们自己的榴弹%s%s"
 
 #: qcsrc/common/notifications/all.inc:492
 #, c-format
 msgid "^BG%s^K1 blew themself up with their own Mortar%s%s"
-msgstr ""
+msgstr "^BG%s^K1 被他们自己的榴弹枪炸成碎尸%s%s"
 
 #: qcsrc/common/notifications/all.inc:493
 #, c-format
@@ -3106,11 +3112,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:539
 msgid "^BGYou are attacking!"
-msgstr ""
+msgstr "^BG你是攻击方!"
 
 #: qcsrc/common/notifications/all.inc:540
 msgid "^BGYou are defending!"
-msgstr ""
+msgstr "^BG你是防守方!"
 
 #: qcsrc/common/notifications/all.inc:541
 #, c-format
@@ -3119,15 +3125,15 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:543
 msgid "^F4Begin!"
-msgstr ""
+msgstr "^F4开始!"
 
 #: qcsrc/common/notifications/all.inc:544
 msgid "^F4Game starts in ^COUNT"
-msgstr ""
+msgstr "^F4游戏开始倒计时^COUNT"
 
 #: qcsrc/common/notifications/all.inc:545
 msgid "^F4Round starts in ^COUNT"
-msgstr ""
+msgstr "^F4下一局开始倒计时^COUNT"
 
 #: qcsrc/common/notifications/all.inc:546
 msgid "^F4Round cannot start"
@@ -3219,12 +3225,12 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:571
 #, c-format
 msgid "^BGYou got your %steam^BG's flag, return it!"
-msgstr ""
+msgstr "^BG你拿到你们 %s队^BG的旗帜,带回它!"
 
 #: qcsrc/common/notifications/all.inc:572
 #, c-format
 msgid "^BGYou got the %senemy^BG's flag, return it!"
-msgstr ""
+msgstr "^BG你拿到敌人%s队^BG的旗帜,带回它!"
 
 #: qcsrc/common/notifications/all.inc:573
 #, c-format
@@ -3282,7 +3288,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:584
 msgid "^BGYou returned the ^TC^TT^BG flag!"
-msgstr ""
+msgstr "^BG你带回了^TC^TT^BG旗帜!"
 
 #: qcsrc/common/notifications/all.inc:585
 msgid "^BGStalemate! Enemies can now see you on radar!"
@@ -3552,11 +3558,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:661
 msgid "^K1You got caught in the blast of a Racer explosion!"
-msgstr ""
+msgstr "^K1你被爆炸的火箭弹给打中了!"
 
 #: qcsrc/common/notifications/all.inc:662
 msgid "^K1You couldn't find shelter from a Racer rocket!"
-msgstr ""
+msgstr "^K1你没能躲过火箭弹!"
 
 #: qcsrc/common/notifications/all.inc:663
 msgid "^K1Watch your step!"
@@ -3591,51 +3597,51 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:670
 #, c-format
 msgid "^BGYou need %s^BG!"
-msgstr ""
+msgstr "^BG你需要 %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:671
 #, c-format
 msgid "^BGYou also need %s^BG!"
-msgstr ""
+msgstr "^BG你也需要 %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:672
 msgid "^BGDoor unlocked!"
-msgstr ""
+msgstr "^BG门已解锁!"
 
 #: qcsrc/common/notifications/all.inc:674
 msgid "^F2You picked up some extra lives"
-msgstr ""
+msgstr "^F2你捡到了额外的生命"
 
 #: qcsrc/common/notifications/all.inc:676
 #, c-format
 msgid "^K3You revived ^BG%s"
-msgstr ""
+msgstr "^K3你复活了 ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:677
 msgid "^K3You revived yourself"
-msgstr ""
+msgstr "^K3你复活了自己"
 
 #: qcsrc/common/notifications/all.inc:678
 #, c-format
 msgid "^K3You were revived by ^BG%s"
-msgstr ""
+msgstr "^K3你被 ^BG%s^K3复活了"
 
 #: qcsrc/common/notifications/all.inc:679
 #, c-format
 msgid "^K3You were automatically revived after %s second(s)"
-msgstr ""
+msgstr "^K3已在 %s 秒(s)后自动复活了"
 
 #: qcsrc/common/notifications/all.inc:681
 msgid "^BGThe generator is under attack!"
-msgstr ""
+msgstr "^BG发电器正在被攻击!"
 
 #: qcsrc/common/notifications/all.inc:683
 msgid "^TC^TT^BG team loses the round"
-msgstr ""
+msgstr "^TC^TT^BG 队伍输了这一轮"
 
 #: qcsrc/common/notifications/all.inc:687
 msgid "^K1You froze yourself"
-msgstr ""
+msgstr "^K1你把自己封冻了"
 
 #: qcsrc/common/notifications/all.inc:688
 msgid "^K1Round already started, you spawn as frozen"
@@ -3644,15 +3650,15 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:690
 #, c-format
 msgid "^K1A %s has arrived!"
-msgstr ""
+msgstr "^K1A %s 到了!"
 
 #: qcsrc/common/notifications/all.inc:694
 msgid "^BGYou got the ^F1Fuel regenerator"
-msgstr ""
+msgstr "^BG你得到了 ^F1燃料重生成器"
 
 #: qcsrc/common/notifications/all.inc:695
 msgid "^BGYou got the ^F1Jet pack"
-msgstr ""
+msgstr "^BG你得到了 ^F1喷气式背包"
 
 #: qcsrc/common/notifications/all.inc:703
 msgid ""
@@ -3835,11 +3841,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:750
 msgid "^F2Strength infuses your weapons with devastating power"
-msgstr ""
+msgstr "^F2神力给你的武器融入毁灭性的力量"
 
 #: qcsrc/common/notifications/all.inc:751
 msgid "^F2Strength has worn off"
-msgstr ""
+msgstr "^F2神力已失效"
 
 #: qcsrc/common/notifications/all.inc:753
 msgid "^F2Shield surrounds you"
@@ -4179,19 +4185,19 @@ msgstr ""
 
 #: qcsrc/common/teams.qh:29
 msgid "TEAM^Red"
-msgstr ""
+msgstr "TEAM^红"
 
 #: qcsrc/common/teams.qh:30
 msgid "TEAM^Blue"
-msgstr ""
+msgstr "TEAM^蓝"
 
 #: qcsrc/common/teams.qh:31
 msgid "TEAM^Yellow"
-msgstr ""
+msgstr "TEAM^黄"
 
 #: qcsrc/common/teams.qh:32
 msgid "TEAM^Pink"
-msgstr ""
+msgstr "TEAM^粉"
 
 #: qcsrc/common/teams.qh:33
 msgid "Team"
@@ -4203,51 +4209,51 @@ msgstr "中立"
 
 #: qcsrc/common/teams.qh:37
 msgid "KEY^Red"
-msgstr ""
+msgstr "KEY^红"
 
 #: qcsrc/common/teams.qh:38
 msgid "KEY^Blue"
-msgstr ""
+msgstr "KEY^蓝"
 
 #: qcsrc/common/teams.qh:39
 msgid "KEY^Yellow"
-msgstr ""
+msgstr "KEY^黄"
 
 #: qcsrc/common/teams.qh:40
 msgid "KEY^Pink"
-msgstr ""
+msgstr "KEY^粉"
 
 #: qcsrc/common/teams.qh:41
 msgid "FLAG^Red"
-msgstr ""
+msgstr "FLAG^红"
 
 #: qcsrc/common/teams.qh:42
 msgid "FLAG^Blue"
-msgstr ""
+msgstr "FLAG^蓝"
 
 #: qcsrc/common/teams.qh:43
 msgid "FLAG^Yellow"
-msgstr ""
+msgstr "FLAG^黄"
 
 #: qcsrc/common/teams.qh:44
 msgid "FLAG^Pink"
-msgstr ""
+msgstr "FLAG^粉"
 
 #: qcsrc/common/teams.qh:45
 msgid "GENERATOR^Red"
-msgstr ""
+msgstr "GENERATOR^红"
 
 #: qcsrc/common/teams.qh:46
 msgid "GENERATOR^Blue"
-msgstr ""
+msgstr "GENERATOR^蓝"
 
 #: qcsrc/common/teams.qh:47
 msgid "GENERATOR^Yellow"
-msgstr ""
+msgstr "GENERATOR^黄"
 
 #: qcsrc/common/teams.qh:48
 msgid "GENERATOR^Pink"
-msgstr ""
+msgstr "GENERATOR^粉"
 
 #: qcsrc/common/turrets/all.qh:51
 msgid "Turrets dump command only works with sv_cmd.\n"
@@ -4288,7 +4294,7 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret/hellion_weapon.qh:7
 msgid "Hellion"
-msgstr ""
+msgstr "海龙"
 
 #: qcsrc/common/turrets/turret/hk.qh:15
 msgid "Hunter-Killer Turret"
@@ -4296,11 +4302,11 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret/hk_weapon.qh:7
 msgid "Hunter-Killer"
-msgstr ""
+msgstr "猎手"
 
 #: qcsrc/common/turrets/turret/machinegun.qh:13
 msgid "Machinegun Turret"
-msgstr ""
+msgstr "机枪炮台"
 
 #: qcsrc/common/turrets/turret/machinegun_weapon.qh:7
 msgid "Machinegun"
@@ -4312,31 +4318,31 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret/mlrs_weapon.qh:7
 msgid "MLRS"
-msgstr ""
+msgstr "MLRS"
 
 #: qcsrc/common/turrets/turret/phaser.qh:13
 msgid "Phaser Cannon"
-msgstr ""
+msgstr "飞射炮"
 
 #: qcsrc/common/turrets/turret/phaser_weapon.qh:7
 msgid "Phaser"
-msgstr ""
+msgstr "飞射"
 
 #: qcsrc/common/turrets/turret/plasma.qh:13
 msgid "Plasma Cannon"
-msgstr ""
+msgstr "离子炮"
 
 #: qcsrc/common/turrets/turret/plasma_dual.qh:7
 msgid "Dual plasma"
-msgstr ""
+msgstr "双离子枪"
 
 #: qcsrc/common/turrets/turret/plasma_dual.qh:19
 msgid "Dual Plasma Cannon"
-msgstr ""
+msgstr "双离子炮"
 
 #: qcsrc/common/turrets/turret/plasma_weapon.qh:7
 msgid "Plasma"
-msgstr ""
+msgstr "离子枪"
 
 #: qcsrc/common/turrets/turret/tesla.qh:13
 #: qcsrc/common/turrets/turret/tesla_weapon.qh:7
@@ -4349,7 +4355,7 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret/walker_weapon.qh:7
 msgid "Walker"
-msgstr ""
+msgstr "沃克"
 
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 #, c-format
@@ -4366,19 +4372,19 @@ msgstr ""
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
 msgid "Bumblebee"
-msgstr ""
+msgstr "黄蜂"
 
 #: qcsrc/common/vehicles/vehicle/racer.qh:19
 msgid "Racer"
-msgstr ""
+msgstr "火箭枪"
 
 #: qcsrc/common/vehicles/vehicle/racer_weapon.qh:9
 msgid "Racer cannon"
-msgstr ""
+msgstr "火箭炮"
 
 #: qcsrc/common/vehicles/vehicle/raptor.qh:19
 msgid "Raptor"
-msgstr ""
+msgstr "猛枭"
 
 #: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:9
 msgid "Raptor cannon"
@@ -4410,15 +4416,15 @@ msgstr ""
 
 #: qcsrc/common/weapons/weapon/crylink.qc:17
 msgid "Crylink"
-msgstr ""
+msgstr "紫电"
 
 #: qcsrc/common/weapons/weapon/devastator.qc:17
 msgid "Devastator"
-msgstr ""
+msgstr "灭世"
 
 #: qcsrc/common/weapons/weapon/electro.qc:17
 msgid "Electro"
-msgstr ""
+msgstr "电射枪"
 
 #: qcsrc/common/weapons/weapon/fireball.qc:17
 msgid "Fireball"
@@ -4426,7 +4432,7 @@ msgstr "火球"
 
 #: qcsrc/common/weapons/weapon/hagar.qc:17
 msgid "Hagar"
-msgstr ""
+msgstr "哈格"
 
 #: qcsrc/common/weapons/weapon/hlac.qc:17
 msgid "Heavy Laser Assault Cannon"
@@ -4446,7 +4452,7 @@ msgstr "地雷放置者"
 
 #: qcsrc/common/weapons/weapon/mortar.qc:17
 msgid "Mortar"
-msgstr ""
+msgstr "榴弹枪"
 
 #: qcsrc/common/weapons/weapon/porto.qc:17
 msgid "Port-O-Launch"
@@ -4462,7 +4468,7 @@ msgstr ""
 
 #: qcsrc/common/weapons/weapon/shockwave.qc:17
 msgid "Shockwave"
-msgstr ""
+msgstr "脉冲波枪"
 
 #: qcsrc/common/weapons/weapon/shotgun.qc:17
 msgid "Shotgun"
@@ -4664,22 +4670,22 @@ msgstr "CI_MUL^%d 秒"
 #: qcsrc/lib/counting.qh:79
 #, c-format
 msgid "%dst"
-msgstr ""
+msgstr "第%d名"
 
 #: qcsrc/lib/counting.qh:80
 #, c-format
 msgid "%dnd"
-msgstr ""
+msgstr "第%d名"
 
 #: qcsrc/lib/counting.qh:81
 #, c-format
 msgid "%drd"
-msgstr ""
+msgstr "第%d名"
 
 #: qcsrc/lib/counting.qh:82 qcsrc/lib/counting.qh:85
 #, c-format
 msgid "%dth"
-msgstr ""
+msgstr "第%d名"
 
 #: qcsrc/lib/oo.qh:298
 msgid "No description"
@@ -4695,12 +4701,12 @@ msgstr ""
 #: qcsrc/lib/string.qh:48
 #, c-format
 msgid "%d days, %02d:%02d:%02d"
-msgstr ""
+msgstr "%d天,%02d:%02d:%02d"
 
 #: qcsrc/lib/string.qh:49
 #, c-format
 msgid "%02d:%02d:%02d"
-msgstr ""
+msgstr "%02d:%02d:%02d"
 
 #: qcsrc/menu/command/menu_cmd.qc:48
 msgid "Usage: menu_cmd command..., where possible commands are:\n"
@@ -4777,11 +4783,11 @@ msgstr "游戏编码"
 
 #: qcsrc/menu/xonotic/credits.qc:116
 msgid "Marketing / PR"
-msgstr ""
+msgstr "销售 / 人力资源"
 
 #: qcsrc/menu/xonotic/credits.qc:122
 msgid "Legal"
-msgstr ""
+msgstr "法律信息"
 
 #: qcsrc/menu/xonotic/credits.qc:127
 msgid "Game Engine"
@@ -4797,7 +4803,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/credits.qc:142
 msgid "Other Active Contributors"
-msgstr ""
+msgstr "其他活跃贡献者"
 
 #: qcsrc/menu/xonotic/credits.qc:149
 msgid "Translators"
@@ -4809,39 +4815,39 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/credits.qc:156
 msgid "Belarusian"
-msgstr ""
+msgstr "白俄罗斯语"
 
 #: qcsrc/menu/xonotic/credits.qc:159
 msgid "Bulgarian"
-msgstr ""
+msgstr "保加利亚语"
 
 #: qcsrc/menu/xonotic/credits.qc:166
 msgid "Chinese (China)"
-msgstr "中文(中国)"
+msgstr "中文(中国)"
 
 #: qcsrc/menu/xonotic/credits.qc:172
 msgid "Chinese (Taiwan)"
-msgstr ""
+msgstr "中文(台湾)"
 
 #: qcsrc/menu/xonotic/credits.qc:177
 msgid "Cornish"
-msgstr ""
+msgstr "康沃尔语"
 
 #: qcsrc/menu/xonotic/credits.qc:180
 msgid "Czech"
-msgstr ""
+msgstr "捷克语"
 
 #: qcsrc/menu/xonotic/credits.qc:185
 msgid "Dutch"
-msgstr ""
+msgstr "荷兰语"
 
 #: qcsrc/menu/xonotic/credits.qc:192
 msgid "English (Australia)"
-msgstr ""
+msgstr "英语(澳大利亚)"
 
 #: qcsrc/menu/xonotic/credits.qc:197
 msgid "Finnish"
-msgstr ""
+msgstr "芬兰语"
 
 #: qcsrc/menu/xonotic/credits.qc:202
 msgid "French"
@@ -4857,11 +4863,11 @@ msgstr "希腊语"
 
 #: qcsrc/menu/xonotic/credits.qc:227
 msgid "Hungarian"
-msgstr ""
+msgstr "匈牙利语"
 
 #: qcsrc/menu/xonotic/credits.qc:231
 msgid "Irish"
-msgstr ""
+msgstr "爱尔兰语"
 
 #: qcsrc/menu/xonotic/credits.qc:234
 msgid "Italian"
@@ -4869,11 +4875,11 @@ msgstr "意大利语"
 
 #: qcsrc/menu/xonotic/credits.qc:240
 msgid "Kazakh"
-msgstr ""
+msgstr "哈萨克语"
 
 #: qcsrc/menu/xonotic/credits.qc:243
 msgid "Korean"
-msgstr ""
+msgstr "韩语"
 
 #: qcsrc/menu/xonotic/credits.qc:247
 msgid "Polish"
@@ -4881,11 +4887,11 @@ msgstr "波兰语"
 
 #: qcsrc/menu/xonotic/credits.qc:255
 msgid "Portuguese"
-msgstr ""
+msgstr "葡萄牙语"
 
 #: qcsrc/menu/xonotic/credits.qc:261
 msgid "Romanian"
-msgstr ""
+msgstr "罗马尼亚语"
 
 #: qcsrc/menu/xonotic/credits.qc:268
 msgid "Russian"
@@ -4893,19 +4899,19 @@ msgstr "俄文"
 
 #: qcsrc/menu/xonotic/credits.qc:279
 msgid "Scottish Gaelic"
-msgstr ""
+msgstr "苏格兰盖尔语"
 
 #: qcsrc/menu/xonotic/credits.qc:282
 msgid "Serbian"
-msgstr ""
+msgstr "塞尔维亚语"
 
 #: qcsrc/menu/xonotic/credits.qc:288
 msgid "Spanish"
-msgstr ""
+msgstr "西班牙语"
 
 #: qcsrc/menu/xonotic/credits.qc:299
 msgid "Swedish"
-msgstr ""
+msgstr "瑞典语"
 
 #: qcsrc/menu/xonotic/credits.qc:303
 msgid "Ukrainian"
@@ -4913,19 +4919,19 @@ msgstr "乌克兰语"
 
 #: qcsrc/menu/xonotic/credits.qc:310
 msgid "Past Contributors"
-msgstr ""
+msgstr "过去的贡献者"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:73
 msgid "forced to be saved to config.cfg"
-msgstr ""
+msgstr "强制保存到config.cfg"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:79 qcsrc/menu/xonotic/cvarlist.qc:89
 msgid "will not be saved"
-msgstr ""
+msgstr "将不会被保存"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:84
 msgid "will be saved to config.cfg"
-msgstr ""
+msgstr "将被保存到config.cfg"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:93
 msgid "private"
@@ -4971,7 +4977,7 @@ msgstr "名字:"
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:53
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
 msgid "Name under which you will appear in the game"
-msgstr ""
+msgstr "你在游戏里的名字"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:69
 msgid "Text language:"
@@ -4979,7 +4985,7 @@ msgstr "文本语言:"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:78
 msgid "Allow player statistics to use your nickname at stats.xonotic.org?"
-msgstr ""
+msgstr "允许stats.xonotic.org使用你的昵称做玩家统计?"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:84
 msgid "Undecided"
@@ -5057,13 +5063,13 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:27
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:15
 msgid "Text alignment:"
-msgstr ""
+msgstr "文本对齐:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:31
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:19
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:71
 msgid "Center"
-msgstr ""
+msgstr "中心"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:35
 msgid "Font scale:"
@@ -5221,17 +5227,17 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_notification.qh:6
 msgid "Notification Panel"
-msgstr ""
+msgstr "通知面板"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:15
 #: qcsrc/menu/xonotic/dialog_hudpanel_pressedkeys.qc:14
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:15
 msgid "Panel disabled"
-msgstr ""
+msgstr "面板已禁用"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:16
 msgid "Panel enabled"
-msgstr ""
+msgstr "面板已启用"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:17
 msgid "Panel enabled even observing"
@@ -5248,20 +5254,20 @@ msgstr "状态栏"
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:26
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:68
 msgid "Left align"
-msgstr ""
+msgstr "向左对齐"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:27
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:74
 msgid "Right align"
-msgstr ""
+msgstr "向右对齐"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:28
 msgid "Inward align"
-msgstr ""
+msgstr "向内对齐"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:29
 msgid "Outward align"
-msgstr ""
+msgstr "向外对齐"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:33
 msgid "Flip speed/acceleration positions"
@@ -6072,7 +6078,7 @@ msgstr "半空中"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:87
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:224
 msgid "Piñata"
-msgstr ""
+msgstr "皮纳塔"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:89
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:229
@@ -6225,23 +6231,23 @@ msgstr "插件"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:38
 msgid "SRVS^Categories"
-msgstr ""
+msgstr "SRVS^类别"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:41
 msgid "SRVS^Empty"
-msgstr ""
+msgstr "SRVS^空"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:42
 msgid "Show empty servers"
-msgstr ""
+msgstr "显示空服务器"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:46
 msgid "SRVS^Full"
-msgstr ""
+msgstr "SRVS^满员"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:47
 msgid "Show full servers that have no slots available"
-msgstr ""
+msgstr "显示没有多余空位的满员服务器"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:51
 msgid "Pause"
@@ -6254,7 +6260,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:53
 msgid "Reload the server list"
-msgstr ""
+msgstr "重新载入服务器列表"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:67
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:223
@@ -6267,7 +6273,7 @@ msgstr "信息..."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:79
 msgid "Show more information about the currently highlighted server"
-msgstr ""
+msgstr "显示当前高亮服务器的更多信息"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join.qc:84
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:303
@@ -6277,7 +6283,7 @@ msgstr "加入!"
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:154
 #: qcsrc/menu/xonotic/serverlist.qc:1061
 msgid "MOD^Default"
-msgstr ""
+msgstr "MOD^默认"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
 #, c-format
@@ -6286,31 +6292,31 @@ msgstr "%d 修改"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:161
 msgid "Official"
-msgstr "正式"
+msgstr "官方"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:169
 msgid "N/A (auth library missing, can't connect)"
-msgstr ""
+msgstr "N/A (缺失验证库,无法连接)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:171
 msgid "N/A (auth library missing)"
-msgstr ""
+msgstr "N/A (缺失验证库)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:177
 msgid "Not supported (can't connect)"
-msgstr ""
+msgstr "不支持(无法连接)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:179
 msgid "Not supported (won't encrypt)"
-msgstr ""
+msgstr "不支持(不加密)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:183
 msgid "Supported (will encrypt)"
-msgstr ""
+msgstr "支持(加密)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:185
 msgid "Supported (won't encrypt)"
-msgstr ""
+msgstr "支持(不加密)"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:189
 msgid "Requested (will encrypt)"
@@ -6416,7 +6422,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:15
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qc:15
 msgid "Do you really wish to disconnect now?"
-msgstr ""
+msgstr "你真的希望现在断开连接吗?"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qh:6
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_timeconfirm.qh:6
@@ -6429,55 +6435,55 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:37
 msgid "MUSICPL^Add"
-msgstr ""
+msgstr "MUSICPL^添加"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:40
 msgid "MUSICPL^Add all"
-msgstr ""
+msgstr "MUSICPL^添加全部"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:44
 msgid "Set as menu track"
-msgstr ""
+msgstr "设为菜单音轨"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:48
 msgid "Reset default menu track"
-msgstr ""
+msgstr "重设默认菜单音轨"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:54
 msgid "Playlist:"
-msgstr "播放列表"
+msgstr "播放列表"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:55
 msgid "Random order"
-msgstr ""
+msgstr "随机顺序"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:60
 msgid "MUSICPL^Stop"
-msgstr ""
+msgstr "MUSICPL^停止"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:63
 msgid "MUSICPL^Play"
-msgstr ""
+msgstr "MUSICPL^播放"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:66
 msgid "MUSICPL^Pause"
-msgstr ""
+msgstr "MUSICPL^暂停"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:69
 msgid "MUSICPL^Prev"
-msgstr ""
+msgstr "MUSICPL^上一首"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:72
 msgid "MUSICPL^Next"
-msgstr ""
+msgstr "MUSICPL^下一首"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:76
 msgid "MUSICPL^Remove"
-msgstr ""
+msgstr "MUSICPL^移除"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qc:79
 msgid "MUSICPL^Remove all"
-msgstr ""
+msgstr "MUSICPL^全部移除"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qc:43
 msgid "Auto screenshot scoreboard"
@@ -6510,7 +6516,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:20
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:21
 msgid "Apply immediately"
-msgstr ""
+msgstr "立即应用"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
 msgid "Name"
@@ -6786,11 +6792,11 @@ msgstr "武器装备:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:99
 msgid "New style sound attenuation"
-msgstr ""
+msgstr "新式声音衰减"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:102
 msgid "Mute sounds when not active"
-msgstr ""
+msgstr "不活动时静音"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:105
 msgid "Frequency:"
@@ -6798,7 +6804,7 @@ msgstr "频率:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:107
 msgid "Sound output frequency"
-msgstr ""
+msgstr "音频输出频率"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:108
 msgid "8 kHz"
@@ -6838,7 +6844,7 @@ msgstr "声道:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:121
 msgid "Number of channels for the sound output"
-msgstr ""
+msgstr "音频输出声道数"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:122
 msgid "Mono"
@@ -6908,15 +6914,15 @@ msgstr "菜单声音"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:150
 msgid "Play sounds when clicking menu items"
-msgstr ""
+msgstr "点击菜单项时播放声音"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:151
 msgid "Focus sounds"
-msgstr "点音效"
+msgstr "点音效"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:152
 msgid "Play sounds when hovering over menu items too"
-msgstr ""
+msgstr "悬停在菜单项时也播放声音"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:156
 msgid "Time announcer:"
@@ -6940,7 +6946,7 @@ msgstr "自动嘲讽:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:166
 msgid "Automatically taunt enemies after fragging them"
-msgstr ""
+msgstr "杀死敌人后自动嘲讽他们"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
 msgid "Sometimes"
@@ -6998,7 +7004,7 @@ msgstr "几何细节:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:67
 msgid "Change the smoothness of the curves on the map (default: normal)"
-msgstr ""
+msgstr "改变地图中曲线的光滑程度(默认:正常)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:68
 msgid "DET^Lowest"
@@ -7006,27 +7012,27 @@ msgstr "DET^极低"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:69
 msgid "DET^Low"
-msgstr "DET^低"
+msgstr "DET^低"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:70
 msgid "DET^Normal"
-msgstr "DET^æ \87å\87\86"
+msgstr "DET^正常"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:71
 msgid "DET^Good"
-msgstr "DET^好"
+msgstr "DET^好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:72
 msgid "DET^Best"
-msgstr "DET^Best"
+msgstr "DET^最好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:73
 msgid "DET^Insane"
-msgstr "DET^Insane"
+msgstr "DET^疯狂"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:77
 msgid "Player detail:"
-msgstr "ç\8e©å®¶è¯¦ç»\86ä¿¡æ\81¯:"
+msgstr "ç\8e©å®¶èº«ä½\93ç»\86è\8a\82:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:79
 msgid "PDET^Low"
@@ -7042,11 +7048,11 @@ msgstr "PDET^标准"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:82
 msgid "PDET^Good"
-msgstr "PDET^好"
+msgstr "PDET^好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:83
 msgid "PDET^Best"
-msgstr "PDET^Best"
+msgstr "PDET^最好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:87
 msgid "Texture resolution:"
@@ -7066,7 +7072,7 @@ msgstr "RES^超低"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:94
 msgid "RES^Low"
-msgstr "RES^低"
+msgstr "RES^低"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:95
 msgid "RES^Normal"
@@ -7074,11 +7080,11 @@ msgstr "RES^标准"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:96
 msgid "RES^Good"
-msgstr "RES^好"
+msgstr "RES^好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:97
 msgid "RES^Best"
-msgstr "RES^Best"
+msgstr "RES^最好"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:110
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:115
@@ -7095,6 +7101,8 @@ msgid ""
 "Disable textures completely for very slow hardware. This gives a huge "
 "performance boost, but looks very ugly. (default: disabled)"
 msgstr ""
+"完全禁用纹理,针对速度非常慢的硬件。这可以导致性能的巨大提升,但画面会非常难"
+"看。(默认:禁用)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:135
 msgid "Use lightmaps"
@@ -7105,6 +7113,7 @@ msgid ""
 "Use high resolution lightmaps, which will look pretty but use up some extra "
 "video memory (default: enabled)"
 msgstr ""
+"使用高分辨率光照贴图,可以改善视觉效果,但会消耗额外的显存(默认:启用)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:138
 msgid "Deluxe mapping"
@@ -7212,7 +7221,7 @@ msgstr "骨骼肌"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:187
 msgid "DMGFX^All"
-msgstr ""
+msgstr "DMGFX^全部"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:191
 msgid "No dynamic lighting"
@@ -7410,15 +7419,15 @@ msgstr "如果显示镜头受阻,则模糊准星显示"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:140
 msgid "Enlarge crosshair if targeting an enemy"
-msgstr "如果有针对性敌人,则放大准星显示"
+msgstr "瞄准敌人时放大准星"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:143
 msgid "Animate crosshair when hitting an enemy"
-msgstr "å\87»ä¸­æ\95\8c人æ\97¶ï¼\8cå\88\99å\8a¨ç\94»准星"
+msgstr "å\90\91æ\95\8c人å°\84å\87»æ\97¶æ\8a\96å\8a¨准星"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:146
 msgid "Animate crosshair when picking up an item"
-msgstr "拿起物品时,则动画准星"
+msgstr "拿起物品时抖动准星"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh:7
 msgid "Crosshair"
@@ -7508,7 +7517,7 @@ msgstr "团队配合"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:148
 msgid "Only when near crosshair"
-msgstr ""
+msgstr "仅在接近准星时"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
 msgid "Display health and armor"
@@ -7623,11 +7632,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
 msgid "Display all info messages in the chatbox"
-msgstr ""
+msgstr "在聊天盒中显示所有信息"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
 msgid "Display player statuses in the chatbox"
-msgstr ""
+msgstr "在聊天盒中显示玩家状态"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
 msgid "Powerup notifications"
@@ -7776,27 +7785,27 @@ msgstr "第三人称透视"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:55
 msgid "Back distance"
-msgstr ""
+msgstr "后方距离"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:61
 msgid "Up distance"
-msgstr ""
+msgstr "上方距离"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:67
 msgid "Allow passing through walls while spectating"
-msgstr ""
+msgstr "旁观时允许穿过墙体"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:70
 msgid "Field of view:"
-msgstr ""
+msgstr "视野:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:72
 msgid "Field of vision in degrees (default: 100)"
-msgstr ""
+msgstr "视场角度(默认:100)"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:76
 msgid "ZOOM^Zoom factor:"
-msgstr ""
+msgstr "ZOOM^缩放因子:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:78
 msgid "How big the zoom factor is when the zoom button is pressed"
@@ -7804,7 +7813,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:81
 msgid "ZOOM^Zoom speed:"
-msgstr ""
+msgstr "ZOOM^缩放速度:"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:83
 msgid "How fast the view will be zoomed, disable to zoom instantly"
@@ -7812,7 +7821,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:92
 msgid "ZOOM^Instant"
-msgstr ""
+msgstr "ZOOM^即时"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:96
 msgid "ZOOM^Zoom sensitivity:"
@@ -8375,7 +8384,7 @@ msgstr "垂直同步"
 msgid ""
 "Enable vertical synchronization to prevent tearing, will cap your fps to the "
 "screen refresh rate (default: disabled)"
-msgstr ""
+msgstr "启用垂直同步以阻止图像撕裂,这会把fps限制在屏幕刷新率以内 (默认: 禁用)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:67
 msgid "Flip view horizontally"
@@ -8423,7 +8432,7 @@ msgstr "抗锯齿:"
 msgid ""
 "Enable antialiasing, which smooths the edges of 3D geometry. Note that it "
 "might decrease performance by quite a lot (default: disabled)"
-msgstr ""
+msgstr "启用抗锯齿,这会平滑3D图形的边缘。注意它会大大降低性能 (默认: 禁用)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:85
 msgid "AA^Disabled"
@@ -8707,19 +8716,19 @@ msgstr "攻击"
 
 #: qcsrc/menu/xonotic/keybinder.qc:44
 msgid "WEAPON^previous"
-msgstr ""
+msgstr "WEAPON^前一个"
 
 #: qcsrc/menu/xonotic/keybinder.qc:45
 msgid "WEAPON^next"
-msgstr ""
+msgstr "WEAPON^后一个"
 
 #: qcsrc/menu/xonotic/keybinder.qc:46
 msgid "WEAPON^previously used"
-msgstr ""
+msgstr "WEAPON^曾用过"
 
 #: qcsrc/menu/xonotic/keybinder.qc:47
 msgid "WEAPON^best"
-msgstr ""
+msgstr "WEAPON^最佳"
 
 #: qcsrc/menu/xonotic/keybinder.qc:48
 msgid "reload"
@@ -8807,7 +8816,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:106
 msgid "quick menu"
-msgstr ""
+msgstr "快速菜单"
 
 #: qcsrc/menu/xonotic/keybinder.qc:107
 msgid "sandbox menu"
@@ -8857,7 +8866,7 @@ msgstr "偏好"
 msgid ""
 "Bookmark the currently highlighted server so that it's faster to find in the "
 "future"
-msgstr ""
+msgstr "收藏当前高亮的服务器以便日后查找"
 
 #: qcsrc/menu/xonotic/serverlist.qc:763
 msgid "Ping"
@@ -8865,7 +8874,7 @@ msgstr "延迟"
 
 #: qcsrc/menu/xonotic/serverlist.qc:764
 msgid "Hostname"
-msgstr ""
+msgstr "主机名"
 
 #: qcsrc/menu/xonotic/serverlist.qc:765
 msgid "Map"
@@ -8886,7 +8895,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:1060
 msgid "encryption:"
-msgstr ""
+msgstr "加密:"
 
 #: qcsrc/menu/xonotic/serverlist.qc:1061
 #, c-format
@@ -8933,7 +8942,7 @@ msgstr "SLCAT^竞争模式"
 
 #: qcsrc/menu/xonotic/serverlist.qh:156
 msgid "SLCAT^Modified Servers"
-msgstr "已更改服务器"
+msgstr "SLCAT^Mod服务器"
 
 #: qcsrc/menu/xonotic/serverlist.qh:157
 msgid "SLCAT^Overkill"
@@ -8972,11 +8981,11 @@ msgstr "%s dB"
 msgid ""
 "Multiplier for amount of particles. Less means less particles, which in turn "
 "gives for better performance (default: 1)"
-msgstr ""
+msgstr "粒子数量的倍数。该值越小代表粒子数目更少,以及更高的性能(默认:1)"
 
 #: qcsrc/menu/xonotic/slider_particles.qc:14
 msgid "PART^OMG"
-msgstr ""
+msgstr "PART^OMG"
 
 #: qcsrc/menu/xonotic/slider_particles.qc:15
 msgid "PART^Low"
@@ -9009,6 +9018,8 @@ msgid ""
 "texture memory usage, but make the textures appear very blurry. (default: "
 "good)"
 msgstr ""
+"改变纹理的锐度,降低该值可以有效减少纹理的内存占用,但会使纹理显得非常模糊。"
+"(默认:好)"
 
 #: qcsrc/menu/xonotic/slider_resolution.qc:115
 msgid "Screen resolution"
@@ -9080,7 +9091,7 @@ msgstr "加入:"
 
 #: qcsrc/menu/xonotic/statslist.qc:103
 msgid "Last_Seen:"
-msgstr ""
+msgstr "上次活动:"
 
 #: qcsrc/menu/xonotic/statslist.qc:110
 msgid "Time_Played:"
index b2544fa0740c89e540773baa6b08dd9cd12483c0..128169c502911d760c7de4707850887c805f6284 100644 (file)
@@ -7581,6 +7581,15 @@ effect arc_lightning
        underwater
        velocityjitter 250 250 250
        velocitymultiplier 20
+effect arc_lightning
+       type smoke
+       alpha 40 40 350
+       color 0x80C0FF 0x80C0FF
+       countabsolute 1
+       sizeincrease 400
+       size 4 4
+       tex 38 38
+       velocitymultiplier 100
 effect arc_beam
        type spark
        airfriction -10
index 6790a3b4fb9575ab91e070c57bc984ac97609ba2..7319cba4e8d1d1d286261036a5da4b215e26364c 100644 (file)
@@ -308,6 +308,7 @@ exec ctfscoring-samual.cfg
 set g_cts 0 "CTS: complete the stage"
 set g_cts_selfdamage 1 "0 = disable all selfdamage and falldamage in cts"
 set g_cts_finish_kill_delay 10 "prevent cheating by running back to the start line, and starting out with more speed than otherwise possible"
+set g_cts_send_rankings_cnt 15 "send this number of map records to clients"
 
 
 // ==========================
diff --git a/gfx/hud/default/nade_veil.tga b/gfx/hud/default/nade_veil.tga
new file mode 100644 (file)
index 0000000..3134d1b
Binary files /dev/null and b/gfx/hud/default/nade_veil.tga differ
diff --git a/gfx/hud/luma/nade_veil.tga b/gfx/hud/luma/nade_veil.tga
new file mode 100644 (file)
index 0000000..edb66b5
Binary files /dev/null and b/gfx/hud/luma/nade_veil.tga differ
index 95726571679ae6e985e0391b10f43c8a8af6a63e..9dcfe0629a03a1e249d4b9f2e37f8e65f673b40e 100644 (file)
@@ -44,7 +44,7 @@ seta hud_panel_weapons_bg_alpha ""
 seta hud_panel_weapons_bg_border ""
 seta hud_panel_weapons_bg_padding "0"
 seta hud_panel_weapons_accuracy "0"
-seta hud_panel_weapons_label "1"
+seta hud_panel_weapons_label "2"
 seta hud_panel_weapons_label_scale "0.3"
 seta hud_panel_weapons_complainbubble "1"
 seta hud_panel_weapons_complainbubble_padding "0"
index 8c037dc23d9dc22198d495b4a1abad8a2e042ce5..65ce9094219c56f80574f2735befda22cf3c46bd 100644 (file)
@@ -1,24 +1,25 @@
+ko    Korean "한국의" 33%
 ast   Asturian "Asturianu" 73%
+zh_CN "Chinese (China)" "中文" 62%
 de    German "Deutsch"
 de_CH German "Deutsch (Schweiz)"
 en    English "English"
 en_AU English "English (Australia)" 86%
 es    Spanish "Español" 99%
 fr    French "Français"
-ga    Irish "Irish" 32%
+ga    Irish "Irish" 35%
 it    Italian "Italiano"
-hu    Hungarian "Magyar" 53%
-nl    Dutch "Nederlands" 67%
-pl    Polish "Polski" 80%
+hu    Hungarian "Magyar" 55%
+nl    Dutch "Nederlands" 70%
+pl    Polish "Polski" 81%
 pt    Portuguese "Português"
+pt_BR pt_BR "pt_BR" 99%
 ro    Romanian "Romana" 83%
-fi    Finnish "Suomi" 31%
-zh_CN "Chinese (China)" "中文" 47%
-zh_TW "Chinese (Taiwan)" "國語" 67%
-ko    Korean "한국의" 32%
-el    Greek "Ελληνική" 32%
-be    Belarusian "Беларуская" 59%
-bg    Bulgarian "Български" 66%
+fi    Finnish "Suomi" 33%
+zh_TW "Chinese (Taiwan)" "國語" 68%
+el    Greek "Ελληνική" 33%
+be    Belarusian "Беларуская" 61%
+bg    Bulgarian "Български" 68%
 ru    Russian "Русский"
-sr    Serbian "Српски" 69%
-uk    Ukrainian "Українська" 57%
\ No newline at end of file
+sr    Serbian "Српски" 71%
+uk    Ukrainian "Українська" 57%
index 51ae3f140fae169c02967a4dc5f6a398c6e381ee..a4c8144fc209b51b36863d5735b19522ca633408 100644 (file)
@@ -55,6 +55,7 @@ set g_instagib_friendlypush 1 "allow pushing teammates with the vaporizer primar
 //  overkill
 // ==========
 set g_overkill 0 "internal cvar, to enable overkill, use  `exec ruleset-overkill.cfg`"
+set g_overkill_weapons 0 "Whether to enable overkill weapons outside of overkill ruleset."
 
 set g_overkill_powerups_replace 1
 set g_overkill_itemwaypoints 1
@@ -198,7 +199,7 @@ set g_nades_nade_edgedamage 90
 set g_nades_nade_radius 300
 set g_nades_nade_force 650
 set g_nades_nade_newton_style 0 "0 is absolute, 1 is relative (takes into account player speed), 2 is something in between"
-set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
+set g_nades_nade_type 1 "Type of the off-hand grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap 9:veil"
 
 seta cl_nade_timer 1 "show a visual timer for nades, 1 = only circle, 2 = circle with text"
 seta cl_nade_type 3
@@ -216,7 +217,7 @@ seta cl_pokenade_type "zombie"
 //
 set g_nades_bonus 0 "Enable bonus grenades"
 set g_nades_bonus_client_select 0 "Allow client side selection of bonus nade type"
-set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap"
+set g_nades_bonus_type 2 "Type of the bonus grenade. 1:normal 2:napalm 3:ice 4:translocate 5:spawn 6:heal 7:pokenade 8:entrap 9:veil"
 set g_nades_bonus_onstrength 1 "Always give bonus grenades to players that have the strength powerup"
 set g_nades_bonus_max 3 "Maximum number of bonus grenades"
 set g_nades_bonus_only 0 "Disallow regular nades, only bonus nades can be used"
@@ -274,6 +275,10 @@ set g_nades_entrap_speed 0.5 "Running speed while entrapped"
 set g_nades_entrap_time 10 "Life time of the orb"
 set g_nades_entrap_radius 500
 
+// Veil (9)
+set g_nades_veil_time 8 "Life time of the orb"
+set g_nades_veil_radius 200
+
 
 // ============
 //  camp check
@@ -307,7 +312,7 @@ set g_buffs_random_location 0 "randomize buff location on start and when reset"
 set g_buffs_random_location_attempts 10 "number of random locations a single buff will attempt to respawn at before giving up"
 set g_buffs_spawn_count 0 "how many buffs to spawn on the map if none exist already"
 set g_buffs_replace_powerups 0 "replace powerups on the map with random buffs"
-set g_buffs_drop 1 "allow dropping buffs"
+set g_buffs_drop 0 "allow dropping buffs"
 set g_buffs_cooldown_activate 5 "cooldown period when buff is first activated"
 set g_buffs_cooldown_respawn 3 "cooldown period when buff is reloading"
 set g_buffs_ammo 1 "ammo buff: infinite ammunition"
index b74f68b3db4d1c3c341c70216e80765f7c28f8cc..823e85bce3c237bae128e9840a882762f4a6ab88 100644 (file)
@@ -7,7 +7,7 @@
 //  Main options
 // ==============
 set g_physics_clientselect 0 "allow clients to select their physics set"
-set g_physics_clientselect_options "xonotic nexuiz quake warsow defrag quake3 vecxis quake2 bones"
+set g_physics_clientselect_options "xonotic nexuiz quake warsow defrag quake3 vecxis quake2 bones overkill"
 set g_physics_clientselect_default "" "override default physics"
 
 // =========
index 240e07a4aed707f674c447d01bd2239a65af117c..aa20961a2b1a60d8037567f340518922df69ebac 100644 (file)
@@ -9,7 +9,6 @@
 #include <client/shownames.qc>
 #include <client/teamradar.qc>
 #include <client/view.qc>
-#include <client/wall.qc>
 
 #include <client/commands/_mod.inc>
 #include <client/hud/_mod.inc>
index 10482caaa4b5081b492f925976c5a3fbbd2cc9fe..ecfa4ee1a6751d0d97c68e4b8f646befab9d2bba 100644 (file)
@@ -9,7 +9,6 @@
 #include <client/shownames.qh>
 #include <client/teamradar.qh>
 #include <client/view.qh>
-#include <client/wall.qh>
 
 #include <client/commands/_mod.qh>
 #include <client/hud/_mod.qh>
index 62b732bec25034e773801113d86aa9f268bfcbf4..bcbe7244692eb85bb4c6c28fcf8e8c0b111fc252 100644 (file)
@@ -1,6 +1,6 @@
 #include "announcer.qh"
 
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
 
 #include <common/notifications/all.qh>
 #include <common/stats.qh>
index 2db9e54cf1af01dfd8bf9e0348a204f11d9e4f47..02739194a858b799752f06dca40e36b8aade1bae 100644 (file)
@@ -11,12 +11,12 @@ float bgmscriptbuf;
 float bgmscriptbufsize;
 float bgmscriptbufloaded;
 
-class(BGMScript) .float bgmscriptline;
-class(BGMScript) .float bgmscriptline0;
-class(BGMScript) .float bgmscriptvolume;
-class(BGMScript) .float bgmscripttime;
-class(BGMScript) .float bgmscriptstate;
-class(BGMScript) .float bgmscriptstatetime;
+classfield(BGMScript) .float bgmscriptline;
+classfield(BGMScript) .float bgmscriptline0;
+classfield(BGMScript) .float bgmscriptvolume;
+classfield(BGMScript) .float bgmscripttime;
+classfield(BGMScript) .float bgmscriptstate;
+classfield(BGMScript) .float bgmscriptstatetime;
 
 float GetAttackDecaySustainAmplitude(float a, float d, float s, float t)
 {
@@ -139,8 +139,7 @@ void BGMScript_InitEntity(entity e)
                if(i >= bgmscriptbufsize)
                {
                        LOG_INFOF("ERROR: bgmscript does not define %s", e.bgmscript);
-                       strunzone(e.bgmscript);
-                       e.bgmscript = string_null;
+                       strfree(e.bgmscript);
                }
        }
 }
index 18b0d5ee4231c5c9e95998fdad5be86331b0b1e8..a3044d537cd3200bedd070f38be867b801456e9e 100644 (file)
@@ -1,13 +1,13 @@
 #pragma once
 
 entityclass(BGMScript);
-class(BGMScript) .string bgmscript;
-class(BGMScript) .float bgmscriptattack;
-class(BGMScript) .float bgmscriptdecay;
-class(BGMScript) .float bgmscriptsustain;
-class(BGMScript) .float bgmscriptrelease;
+classfield(BGMScript) .string bgmscript;
+classfield(BGMScript) .float bgmscriptattack;
+classfield(BGMScript) .float bgmscriptdecay;
+classfield(BGMScript) .float bgmscriptsustain;
+classfield(BGMScript) .float bgmscriptrelease;
 
-class(BGMScript) .float just_toggled;
+classfield(BGMScript) .float just_toggled;
 
 #ifdef CSQC
 void BGMScript_InitEntity(entity e);
index 8faf0f387b6ccd33103cbfd825dec2692a7ac760..034bb6336680e7ead16421fcaf5fba0c8f78d69c 100644 (file)
 #include "../autocvars.qh"
 #include "../defs.qh"
 #include <client/hud/_mod.qh>
+#include <client/hud/panel/quickmenu.qh>
+#include <client/hud/panel/radar.qh>
 #include "../main.qh"
 #include "../mapvoting.qh"
 #include "../miscfunctions.qh"
 
-#include "../mutators/events.qh"
+#include <client/mutators/_mod.qh>
+
+#include <common/minigames/cl_minigames_hud.qh>
 
 #include <common/mapinfo.qh>
 
@@ -249,16 +253,6 @@ void LocalCommand_handlevote(int request, int argc)
        }
 }
 
-bool QuickMenu_IsOpened();
-void QuickMenu_Close();
-bool QuickMenu_Open(string mode, string submenu, string file);
-
-bool HUD_MinigameMenu_IsOpened();
-void HUD_MinigameMenu_Close(entity this, entity actor, entity trigger);
-void HUD_MinigameMenu_Open();
-
-void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
-
 void LocalCommand_hud(int request, int argc)
 {
     TC(int, request); TC(int, argc);
@@ -418,7 +412,7 @@ void LocalCommand_sendcvar(int request, int argc)
                        if (argv(1))
                        {
                                // W_FixWeaponOrder will trash argv, so save what we need.
-                               string thiscvar = strzone(argv(1));
+                               string thiscvar = string_null; strcpy(thiscvar, argv(1));
                                string s = cvar_string(thiscvar);
 
                                if (thiscvar == "cl_weaponpriority")
@@ -427,7 +421,7 @@ void LocalCommand_sendcvar(int request, int argc)
                                        s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
 
                                localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
-                               strunzone(thiscvar);
+                               strfree(thiscvar);
                                return;
                        }
                }
index f1be4315fe5df1caeaaca2b6e29b62031bae2001..f6f96501aee2abb928a8de29ca923f602f80ea6b 100644 (file)
@@ -2,6 +2,7 @@
 
 void Cmd_Scoreboard_SetFields(int);
 void Cmd_Scoreboard_Help();
+void ConsoleCommand_macro_init();
 
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
 void LocalCommand_macro_write_aliases(int fh);
index 6499a683e8f4c2cf198be39cb0bee2c9eb9e9a3f..d8f6d26a33895e91fd40fb6a8d1b42e723de8575 100644 (file)
@@ -2,7 +2,7 @@
 #include "autocvars.qh"
 #include "csqcmodel_hooks.qh"
 #include "miscfunctions.qh"
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
 #include "player_skeleton.qh"
 #include "weapons/projectile.qh"
 #include <common/animdecide.qh>
@@ -18,8 +18,6 @@
 .float death_time;
 .int modelflags;
 
-void CSQCModel_Hook_PreDraw(entity this, bool isplayer);
-
 .bool isplayermodel;
 
 // FEATURE: LOD
index 56a3fb4a549097a12295e15ce5c409b7b7e12cfe..8ed256379ff2e6d60b6bbf5a8598472f185999b4 100644 (file)
@@ -24,3 +24,5 @@ const int MF_TRACER3 =  BIT(7);  // purple trail
 .int csqcmodel_traileffect;
 
 void CSQCModel_Effects_Apply(entity this);
+
+void CSQCModel_Hook_PreDraw(entity this, bool isplayer);
index 9bcdd3d6624422a18a245423dc2f44589d6a090c..2b8eed95f7705578fc5ae34a083e8187c0f45a0b 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <client/defs.qh>
 #include <client/miscfunctions.qh>
+#include <client/view.qh>
 #include "panel/scoreboard.qh"
 #include "hud_config.qh"
 #include "../mapvoting.qh"
 #include <common/items/_mod.qh>
 #include <common/mapinfo.qh>
 #include <common/vehicles/all.qh>
+#include <common/vehicles/vehicle/bumblebee.qh>
 #include <common/mutators/mutator/waypoints/all.qh>
 #include <common/stats.qh>
 #include <lib/csqcmodel/cl_player.qh>
-#include <server/mutators/mutator/gamemode_ctf.qh> // TODO: remove
+#include <lib/csqcmodel/cl_model.qh>
+#include <common/gamemodes/_mod.qh>
 
 
 /*
@@ -395,8 +398,6 @@ Main HUD system
 ==================
 */
 
-void CSQC_BUMBLE_GUN_HUD();
-
 void HUD_Vehicle()
 {
        if(autocvar__hud_configure) return;
@@ -485,8 +486,6 @@ bool Hud_Shake_Update()
        return true;
 }
 
-entity CSQCModel_server2csqc(int i);
-void calc_followmodel_ofs(entity view);
 void Hud_Dynamic_Frame()
 {
        vector ofs = '0 0 0';
@@ -579,12 +578,8 @@ void HUD_Main()
        // Drawing stuff
        if (hud_skin_prev != autocvar_hud_skin)
        {
-               if (hud_skin_path)
-                       strunzone(hud_skin_path);
-               hud_skin_path = strzone(strcat("gfx/hud/", autocvar_hud_skin));
-               if (hud_skin_prev)
-                       strunzone(hud_skin_prev);
-               hud_skin_prev = strzone(autocvar_hud_skin);
+               strcpy(hud_skin_path, strcat("gfx/hud/", autocvar_hud_skin));
+               strcpy(hud_skin_prev, autocvar_hud_skin);
        }
 
        // draw the dock
@@ -659,9 +654,7 @@ void HUD_Main()
                        LOG_TRACE("Automatically fixed wrong/missing panel numbers in _hud_panelorder");
 
                cvar_set("_hud_panelorder", s);
-               if(hud_panelorder_prev)
-                       strunzone(hud_panelorder_prev);
-               hud_panelorder_prev = strzone(s);
+               strcpy(hud_panelorder_prev, s);
 
                //now properly set panel_order
                tokenize_console(s);
index d070dce380d3b4877f5ac6457a9993a388717957..950dee17ad5ec77799cab431c5bc3229f13d58af 100644 (file)
@@ -120,18 +120,18 @@ vector panel_size_copied;
 
 entity panel;
 entityclass(HUDPanel);
-class(HUDPanel) .string panel_name;
-class(HUDPanel) .int panel_id;
-class(HUDPanel) .vector current_panel_pos;
-class(HUDPanel) .vector current_panel_size;
-class(HUDPanel) .string current_panel_bg;
-class(HUDPanel) .float current_panel_bg_alpha;
-class(HUDPanel) .float current_panel_bg_border;
-class(HUDPanel) .vector current_panel_bg_color;
-class(HUDPanel) .float current_panel_bg_color_team;
-class(HUDPanel) .float current_panel_bg_padding;
-class(HUDPanel) .float current_panel_fg_alpha;
-class(HUDPanel) .float update_time;
+classfield(HUDPanel) .string panel_name;
+classfield(HUDPanel) .int panel_id;
+classfield(HUDPanel) .vector current_panel_pos;
+classfield(HUDPanel) .vector current_panel_size;
+classfield(HUDPanel) .string current_panel_bg;
+classfield(HUDPanel) .float current_panel_bg_alpha;
+classfield(HUDPanel) .float current_panel_bg_border;
+classfield(HUDPanel) .vector current_panel_bg_color;
+classfield(HUDPanel) .float current_panel_bg_color_team;
+classfield(HUDPanel) .float current_panel_bg_padding;
+classfield(HUDPanel) .float current_panel_fg_alpha;
+classfield(HUDPanel) .float update_time;
 float panel_enabled;
 vector panel_pos;
 vector panel_size;
@@ -148,7 +148,7 @@ string panel_bg_border_str;
 float panel_bg_padding;
 string panel_bg_padding_str;
 
-class(HUDPanel) .void() panel_draw;
+classfield(HUDPanel) .void() panel_draw;
 
 // chat panel can be reduced / moved while the mapvote is active
 // let know the mapvote panel about chat pos and size
@@ -175,8 +175,6 @@ vector hud_shift;
 vector hud_shift_current = '0 0 0';
 vector hud_scale_center;
 
-float stringwidth_colors(string s, vector theSize);
-float stringwidth_nocolors(string s, vector theSize);
 void HUD_Panel_DrawProgressBar(vector theOrigin, vector theSize, string pic, float length_ratio, bool vertical, float baralign, vector theColor, float theAlpha, int drawflag);
 
 .int panel_showflags;
@@ -264,9 +262,7 @@ REGISTER_HUD_PANEL(SCOREBOARD,      Scoreboard_Draw,    PANEL_CONFIG_NO
                        }                                                                                                       \
                }                                                                                                           \
        }                                                                                                               \
-       if (panel.current_panel_bg)                                                                                     \
-               strunzone(panel.current_panel_bg);                                                                          \
-       panel.current_panel_bg = strzone(panel_bg);                                                                     \
+       strcpy(panel.current_panel_bg, panel_bg);                                                                       \
 } MACRO_END
 
 // Get value for panel_bg_color: if "" fetch default, else use panel_bg_color. Convert pants, shirt or teamcolor into a vector.
index ec07ee4095a30e3c1c462f25fae034882e87b123..e8ec807be5bc4f9c4e0f59e9410b748da1520757 100644 (file)
@@ -660,12 +660,10 @@ void HUD_Panel_Arrow_Action(float nPrimary)
        }
 }
 
-void HUD_Panel_EnableMenu();
 entity tab_panels[hud_panels_MAX];
 entity tab_panel;
 vector tab_panel_pos;
 float tab_backward;
-void HUD_Panel_FirstInDrawQ(float id);
 void reset_tab_panels()
 {
        for (int i = 0; i < hud_panels_COUNT; ++i)
@@ -1029,9 +1027,7 @@ void HUD_Panel_FirstInDrawQ(float id)
                s = strcat(s, ftos(panel_order[i]), " ");
        }
        cvar_set("_hud_panelorder", s);
-       if(hud_panelorder_prev)
-               strunzone(hud_panelorder_prev);
-       hud_panelorder_prev = strzone(autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
+       strcpy(hud_panelorder_prev, autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
 }
 
 void HUD_Panel_Highlight(float allow_move)
index 6ab64f6aed2a7548f5b51dc36bbb012713c8c9e7..d91fe370e1d997cd213e661dfeb69adb63ab6312 100644 (file)
@@ -23,3 +23,7 @@ void HUD_Configure_Frame();
 void HUD_Configure_PostDraw();
 
 float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
+
+void HUD_Panel_EnableMenu();
+
+void HUD_Panel_FirstInDrawQ(float id);
index 66ca0772b602933b25d56b0af4a628616863f985..1ea23ae2e758531f19ce24d40843062252a3e277 100644 (file)
@@ -2,4 +2,4 @@
 
 #include "hud.qh"
 #include "hud_config.qh"
-#include <client/mutators/events.qh>
+#include <client/mutators/_mod.qh>
index 0636f3f2e972cfc551eb991b4631732d90aa79ab..01ce50cdbb6f87e03291c9f57232dc683aff76c9 100644 (file)
@@ -6,6 +6,7 @@
 #include <client/view.qh>
 #include <common/t_items.qh>
 #include <common/wepent.qh>
+#include <common/mutators/mutator/nades/nades.qh>
 
 // Ammo (#1)
 
@@ -19,8 +20,6 @@ void DrawNadeProgressBar(vector myPos, vector mySize, float progress, vector col
                autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
 }
 
-void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
-
 void DrawAmmoItem(vector myPos, vector mySize, int ammoType, bool isCurrent, bool isInfinite)
 {
     TC(bool, isCurrent); TC(bool, isInfinite);
index a92bdc69234a1dac1f90762cd8a74243f986c17d..f8f70c8189e671de3cb01fd3d4c4a8aab3e7745a 100644 (file)
@@ -75,9 +75,7 @@ void centerprint_generic(int new_id, string strMessage, float duration, int coun
                        cpm_index = CENTERPRINT_MAX_MSGS - 1;
                j = cpm_index;
        }
-       if(centerprint_messages[j])
-               strunzone(centerprint_messages[j]);
-       centerprint_messages[j] = strzone(strMessage);
+       strcpy(centerprint_messages[j], strMessage);
        centerprint_msgID[j] = new_id;
        if (duration < 0)
        {
@@ -112,9 +110,7 @@ void reset_centerprint_messages()
                centerprint_expire_time[i] = 0;
                centerprint_time[i] = 1;
                centerprint_msgID[i] = 0;
-               if(centerprint_messages[i])
-                       strunzone(centerprint_messages[i]);
-               centerprint_messages[i] = string_null;
+               strfree(centerprint_messages[i]);
        }
 }
 float hud_configure_cp_generation_time;
index 74d4b6d0f49462f522298e276770244dc54e278a..5f309d0b0224bd4c019f9f4d51b29a9f851368a9 100644 (file)
@@ -48,9 +48,7 @@ void HUD_Chat()
                        panel_bg = strcat(hud_skin_path, "/border_default");
                        if(precache_pic(panel_bg) == "")
                                panel_bg = "gfx/hud/default/border_default";
-                       if(panel.current_panel_bg)
-                               strunzone(panel.current_panel_bg);
-                       panel.current_panel_bg = strzone(panel_bg);
+                       strcpy(panel.current_panel_bg, panel_bg);
                        chat_panel_modified = true;
                }
                panel_bg_alpha = max(0.75, panel_bg_alpha);
index 1e5a0c9f2f293403c18408e3ff0cdae1fc72d649..7b7d82b4445c376ea46a019daf14ee2488b0c5dc 100644 (file)
@@ -33,7 +33,6 @@ int img_select(int group_id)
        return img_cur_msg[group_id];
 }
 
-float stringwidth_colors(string s, vector theSize);
 vector InfoMessages_drawstring(string s, vector pos, vector sz, float a, vector fontsize)
 {
        getWrappedLine_remaining = s;
index 65682b3ec7d27006a653449ad69e7b725ba69516..89b8a8c188b4a981774ed1c173b98e8215c62a78 100644 (file)
@@ -5,7 +5,7 @@
 #include <common/mapinfo.qh>
 #include <common/ent_cs.qh>
 #include <common/scores.qh>
-#include <server/mutators/mutator/gamemode_ctf.qh> // TODO: remove
+#include <common/gamemodes/_mod.qh>
 
 // Mod icons (#10)
 
@@ -583,9 +583,7 @@ void HUD_Mod_Race(vector pos, vector mySize)
        if (race_status != race_status_prev || race_status_name != race_status_name_prev) {
                race_status_time = time + 5;
                race_status_prev = race_status;
-               if (race_status_name_prev)
-                       strunzone(race_status_name_prev);
-               race_status_name_prev = strzone(race_status_name);
+               strcpy(race_status_name_prev, race_status_name);
        }
 
        // race "awards"
@@ -621,12 +619,8 @@ void HUD_Mod_Race(vector pos, vector mySize)
        if (race_status_time - time <= 0) {
                race_status_prev = -1;
                race_status = -1;
-               if(race_status_name)
-                       strunzone(race_status_name);
-               race_status_name = string_null;
-               if(race_status_name_prev)
-                       strunzone(race_status_name_prev);
-               race_status_name_prev = string_null;
+               strfree(race_status_name);
+               strfree(race_status_name_prev);
        }
 }
 
index 9af8673dab8941adc2ad73decdd4834ba6ddce63..29f69b3d4d9c506efc1676f48055af6c13011c4e 100644 (file)
@@ -44,29 +44,19 @@ float QuickMenu_TimeOut;
 void QuickMenu_Page_LoadEntry(int i, string s, string s1)
 {
     TC(int, i);
-       //printf("^xc80 entry %d: %s, %s\n", i, s, s1);
-       if (QuickMenu_Page_Description[i])
-               strunzone(QuickMenu_Page_Description[i]);
-       QuickMenu_Page_Description[i] = strzone(s);
-       if (QuickMenu_Page_Command[i])
-               strunzone(QuickMenu_Page_Command[i]);
-       QuickMenu_Page_Command[i] = strzone(s1);
+       //LOG_INFOF("^xc80 entry %d: %s, %s\n", i, s, s1);
+       strcpy(QuickMenu_Page_Description[i], s);
+       strcpy(QuickMenu_Page_Command[i], s1);
 }
 
 void QuickMenu_Page_ClearEntry(int i)
 {
     TC(int, i);
-       if (QuickMenu_Page_Description[i])
-               strunzone(QuickMenu_Page_Description[i]);
-       QuickMenu_Page_Description[i] = string_null;
-       if (QuickMenu_Page_Command[i])
-               strunzone(QuickMenu_Page_Command[i]);
-       QuickMenu_Page_Command[i] = string_null;
+       strfree(QuickMenu_Page_Description[i]);
+       strfree(QuickMenu_Page_Command[i]);
        QuickMenu_Page_Command_Type[i] = 0;
 }
 
-float QuickMenu_Page_Load(string target_submenu, float new_page);
-void QuickMenu_Default(string submenu);
 bool QuickMenu_Open(string mode, string submenu, string file)
 {
        int fh = -1;
@@ -197,9 +187,7 @@ void QuickMenu_Buffer_Close()
 
 void QuickMenu_Close()
 {
-       if (QuickMenu_CurrentSubMenu)
-               strunzone(QuickMenu_CurrentSubMenu);
-       QuickMenu_CurrentSubMenu = string_null;
+       strfree(QuickMenu_CurrentSubMenu);
        int i;
        for (i = 0; i < QUICKMENU_MAXLINES; ++i)
                QuickMenu_Page_ClearEntry(i);
@@ -217,18 +205,17 @@ void QuickMenu_Close()
 // It assumes submenu open tag is already detected
 void QuickMenu_skip_submenu(string submenu)
 {
-       string s, z_submenu;
-       z_submenu = strzone(submenu);
+       string z_submenu = string_null; strcpy(z_submenu, submenu);
        for(++QuickMenu_Buffer_Index ; QuickMenu_Buffer_Index < QuickMenu_Buffer_Size; ++QuickMenu_Buffer_Index)
        {
-               s = QuickMenu_Buffer_Get();
+               string s = QuickMenu_Buffer_Get();
                if(substring(s, 0, 1) != QM_TAG_SUBMENU)
                        continue;
                if(substring(s, 1, -1) == z_submenu) // submenu end
                        break;
                QuickMenu_skip_submenu(substring(s, 1, -1));
        }
-       strunzone(z_submenu);
+       strfree(z_submenu);
 }
 
 bool QuickMenu_IsOpened()
@@ -236,7 +223,6 @@ bool QuickMenu_IsOpened()
        return (QuickMenu_Page_Entries > 0);
 }
 
-void HUD_Quickmenu_PlayerListEntries(string cmd, int teamplayers, bool without_me);
 bool HUD_Quickmenu_PlayerListEntries_Create(string cmd, int teamplayers, bool without_me)
 {
     TC(int, teamplayers); TC(bool, without_me);
@@ -273,9 +259,7 @@ bool QuickMenu_Page_Load(string target_submenu, bool new_page)
                ++QuickMenu_Page;
 
        z_submenu = strzone(target_submenu);
-       if (QuickMenu_CurrentSubMenu)
-               strunzone(QuickMenu_CurrentSubMenu);
-       QuickMenu_CurrentSubMenu = strzone(z_submenu);
+       strcpy(QuickMenu_CurrentSubMenu, z_submenu);
 
        QuickMenu_IsLastPage = true;
        QuickMenu_Page_Entries = 0;
@@ -289,11 +273,11 @@ bool QuickMenu_Page_Load(string target_submenu, bool new_page)
                        s = QuickMenu_Buffer_Get();
                        if(substring(s, 0, 1) == QM_TAG_SUBMENU && substring(s, 1, -1) == z_submenu)
                        {
-                               // printf("^3 beginning of %s\n", z_submenu);
+                               //LOG_INFOF("^3 beginning of %s\n", z_submenu);
                                ++QuickMenu_Buffer_Index;
                                break; // target_submenu found!
                        }
-                       // printf("^1 skipping %s\n", s);
+                       //LOG_INFOF("^1 skipping %s\n", s);
                }
                if(QuickMenu_Buffer_Index == QuickMenu_Buffer_Size)
                        LOG_WARNF("Couldn't find submenu \"%s\"", z_submenu);
@@ -310,7 +294,7 @@ bool QuickMenu_Page_Load(string target_submenu, bool new_page)
 
                if(z_submenu != "" && substring(s, 1, -1) == z_submenu)
                {
-                       // printf("^3 end of %s\n", z_submenu);
+                       //LOG_INFOF("^3 end of %s\n", z_submenu);
                        break;
                }
 
@@ -335,28 +319,32 @@ bool QuickMenu_Page_Load(string target_submenu, bool new_page)
                                QuickMenu_Page_LoadEntry(QuickMenu_Page_Entries, substring(s, 1, -1), "");
                        QuickMenu_skip_submenu(substring(s, 1, -1));
                }
-               else if(entry_num >= first_entry && substring(s, 0, 1) == QM_TAG_TITLE)
+               else if(substring(s, 0, 1) == QM_TAG_TITLE)
                {
                        ++QuickMenu_Buffer_Index;
-                       cmd = QuickMenu_Buffer_Get();
-                       string command_code = substring(cmd, 0, 1);
-                       if(command_code == QM_TAG_COMMAND)
-                               cmd = substring(cmd, 1, -1);
-                       else if(command_code == QM_TAG_PLCOMMAND)
+                       if(entry_num >= first_entry)
                        {
-                               // throw away the current quickmenu buffer and load a new one
-                               cmd = substring(cmd, 1, -1);
-                               strunzone(z_submenu);
-                               if(HUD_Quickmenu_PlayerListEntries_Create(cmd, stof(substring(s, 1, 1)), stof(substring(s, 2, 1))))
-                                       return QuickMenu_Page_Load("", 0);
-                               QuickMenu_Close();
-                               return false;
-                       }
+                               cmd = QuickMenu_Buffer_Get();
+                               string command_code = substring(cmd, 0, 1);
+                               if(command_code == QM_TAG_COMMAND)
+                                       cmd = substring(cmd, 1, -1);
+                               else if(command_code == QM_TAG_PLCOMMAND)
+                               {
+                                       // throw away the current quickmenu buffer and load a new one
+                                       cmd = substring(cmd, 1, -1);
+                                       strunzone(z_submenu);
+                                       if(HUD_Quickmenu_PlayerListEntries_Create(cmd, stof(substring(s, 1, 1)), stof(substring(s, 2, 1))))
+                                               return QuickMenu_Page_Load("", 0);
+                                       QuickMenu_Close();
+                                       return false;
+                               }
+
+                               tokenize_console(cmd);
+                               QuickMenu_Page_Command_Type[QuickMenu_Page_Entries] = (argv(1) && argv(0) == "toggle");
 
-                       tokenize_console(cmd);
-                       QuickMenu_Page_Command_Type[QuickMenu_Page_Entries] = (argv(1) && argv(0) == "toggle");
+                               QuickMenu_Page_LoadEntry(QuickMenu_Page_Entries, substring(s, 1, -1), cmd);
+                       }
 
-                       QuickMenu_Page_LoadEntry(QuickMenu_Page_Entries, substring(s, 1, -1), cmd);
                }
 
                ++entry_num;
@@ -519,10 +507,10 @@ void QuickMenu_Mouse()
 
        if (mousepos.x >= panel_pos.x && mousepos.y >= first_entry_pos && mousepos.x <= panel_pos.x + panel_size.x && mousepos.y <= first_entry_pos + entries_height)
        {
-               float entry_num;
-               entry_num = floor((mousepos.y - first_entry_pos) / fontsize.y);
+               int entry_num = min(QuickMenu_Page_Entries - 1, floor((mousepos.y - first_entry_pos) / fontsize.y));
                if (QuickMenu_IsLastPage || entry_num != QUICKMENU_MAXLINES - 2)
                {
+                       // recycling panel_pos as entry_pos
                        panel_pos.y = first_entry_pos + entry_num * fontsize.y;
                        vector color;
                        if(mouseClicked & S_MOUSE1)
@@ -798,6 +786,8 @@ void QuickMenu_Default(string target_submenu)
                QUICKMENU_ENTRY_TC(CTX(_("QMCMD^nice one")), "say %s", ":-) / nice one", CTX(_("QMCMD^:-) / nice one")))
                QUICKMENU_ENTRY_TC(CTX(_("QMCMD^good game")), "say %s", "good game", CTX(_("QMCMD^good game")))
                QUICKMENU_ENTRY_TC(CTX(_("QMCMD^hi / good luck")), "say %s", "hi / good luck and have fun", CTX(_("QMCMD^hi / good luck and have fun")))
+               if(prvm_language != "en")
+               QUICKMENU_ENTRY(CTX(_("QMCMD^Send in English")), "toggle hud_panel_quickmenu_translatecommands 0 1; quickmenu; wait; quickmenu default Chat")
        QUICKMENU_SMENU(_("Chat"), "Chat")
 
        if(teamplay)
@@ -858,8 +848,6 @@ void QuickMenu_Default(string target_submenu)
                }
 
                QUICKMENU_ENTRY(CTX(_("QMCMD^Fullscreen")), "toggle vid_fullscreen; vid_restart")
-               if(prvm_language != "en")
-               QUICKMENU_ENTRY(CTX(_("QMCMD^Translate chat messages")), "toggle hud_panel_quickmenu_translatecommands")
        QUICKMENU_SMENU(CTX(_("QMCMD^Settings")), "Settings")
 
        QUICKMENU_SMENU(CTX(_("QMCMD^Call a vote")), "Call a vote")
@@ -876,9 +864,9 @@ void QuickMenu_Default(string target_submenu)
 
        if(target_submenu != "" && !target_submenu_found)
        {
-               LOG_WARNF("Couldn't find submenu \"%s\"", target_submenu);
+               LOG_INFOF("Couldn't find submenu \"%s\"", target_submenu);
                if(prvm_language != "en")
-                       LOG_WARNF("^3Warning: submenu must be in English", target_submenu);
+                       LOG_INFOF("^3Warning: submenu title must be in English", target_submenu);
                QuickMenu_Buffer_Size = 0;
        }
 }
index aad86e6bd689ed786280f6c1b8210e96b69ec6a3..694f0d1d7e0c439cedea395241f62d248e445473 100644 (file)
@@ -4,3 +4,8 @@
 bool QuickMenu_InputEvent(float bInputType, float nPrimary, float nSecondary);
 bool QuickMenu_IsOpened();
 void QuickMenu_Mouse();
+float QuickMenu_Page_Load(string target_submenu, float new_page);
+void QuickMenu_Default(string submenu);
+void HUD_Quickmenu_PlayerListEntries(string cmd, int teamplayers, bool without_me);
+void QuickMenu_Close();
+bool QuickMenu_Open(string mode, string submenu, string file);
index b1cc222ccf1a5dab7f70fa08373a41dd184cbe68..f0ec01c9e7b1847e68734896348da82b7658ad0f 100644 (file)
@@ -214,9 +214,7 @@ void HUD_Radar()
                        panel_bg = "gfx/hud/default/border_default"; // fallback
                if(!radar_panel_modified && panel_bg != panel.current_panel_bg)
                        radar_panel_modified = true;
-               if(panel.current_panel_bg)
-                       strunzone(panel.current_panel_bg);
-               panel.current_panel_bg = strzone(panel_bg);
+               strcpy(panel.current_panel_bg, panel_bg);
 
                switch(hud_panel_radar_maximized_zoommode)
                {
index 6db88c68b39ee50fce1f8acce9c778465a3223ae..d2fbc8f6b25ce5bb6a5afe05bb2637dfe53bd08c 100644 (file)
@@ -1,2 +1,4 @@
 #pragma once
 #include "../panel.qh"
+
+void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
index 200f5b2c55b575ab5b22efa18b2f9c0017ba1f93..5b8964d0d3962a913033d672c7ad4366d9605b06 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <client/autocvars.qh>
 #include <client/defs.qh>
+#include <client/main.qh>
 #include <client/miscfunctions.qh>
 #include "quickmenu.qh"
 #include <common/ent_cs.qh>
@@ -70,10 +71,6 @@ bool autocvar_hud_panel_scoreboard_spectators_showping = true;
 bool autocvar_hud_panel_scoreboard_spectators_aligned = false;
 float autocvar_hud_panel_scoreboard_minwidth = 0.4;
 
-
-void drawstringright(vector, string, vector, vector, float, float);
-void drawstringcenter(vector, string, vector, vector, float, float);
-
 // wrapper to put all possible scores titles through gettext
 string TranslateScoresLabel(string l)
 {
@@ -150,7 +147,6 @@ void Scoreboard_InitScores()
        Cmd_Scoreboard_SetFields(0);
 }
 
-float SetTeam(entity pl, float Team);
 //float lastpnum;
 void Scoreboard_UpdatePlayerTeams()
 {
@@ -297,61 +293,65 @@ void Scoreboard_UpdateTeamPos(entity Team)
 void Cmd_Scoreboard_Help()
 {
        LOG_INFO(_("You can modify the scoreboard using the ^2scoreboard_columns_set command."));
-       LOG_INFO(_("^3|---------------------------------------------------------------|"));
        LOG_INFO(_("Usage:"));
-       LOG_INFO(_("^2scoreboard_columns_set default"));
+       LOG_INFO("^2scoreboard_columns_set default");
        LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ..."));
-       LOG_INFO(_("The following field names are recognized (case insensitive):"));
        LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields."));
+       LOG_INFO(_("The following field names are recognized (case insensitive):"));
        LOG_INFO("");
 
-       LOG_INFO(_("^3name^7 or ^3nick^7             Name of a player"));
-       LOG_INFO(_("^3ping^7                     Ping time"));
-       LOG_INFO(_("^3pl^7                       Packet loss"));
-       LOG_INFO(_("^3elo^7                      Player ELO"));
-       LOG_INFO(_("^3kills^7                    Number of kills"));
-       LOG_INFO(_("^3deaths^7                   Number of deaths"));
-       LOG_INFO(_("^3suicides^7                 Number of suicides"));
-       LOG_INFO(_("^3frags^7                    kills - suicides"));
-       LOG_INFO(_("^3teamkills^7                Number of teamkills"));
-       LOG_INFO(_("^3kd^7                       The kill-death ratio"));
-       LOG_INFO(_("^3dmg^7                      The total damage done"));
-       LOG_INFO(_("^3dmgtaken^7                 The total damage taken"));
-       LOG_INFO(_("^3sum^7                      frags - deaths"));
-       LOG_INFO(_("^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was captured"));
-       LOG_INFO(_("^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up"));
-       LOG_INFO(_("^3captime^7                  Time of fastest cap (CTF)"));
-       LOG_INFO(_("^3fckills^7                  Number of flag carrier kills"));
-       LOG_INFO(_("^3returns^7                  Number of flag returns"));
-       LOG_INFO(_("^3drops^7                    Number of flag drops"));
-       LOG_INFO(_("^3lives^7                    Number of lives (LMS)"));
-       LOG_INFO(_("^3rank^7                     Player rank"));
-       LOG_INFO(_("^3pushes^7                   Number of players pushed into void"));
-       LOG_INFO(_("^3destroyed^7                Number of keys destroyed by pushing them into void"));
-       LOG_INFO(_("^3kckills^7                  Number of keys carrier kills"));
-       LOG_INFO(_("^3losses^7                   Number of times a key was lost"));
-       LOG_INFO(_("^3laps^7                     Number of laps finished (race/cts)"));
-       LOG_INFO(_("^3time^7                     Total time raced (race/cts)"));
-       LOG_INFO(_("^3fastest^7                  Time of fastest lap (race/cts)"));
-       LOG_INFO(_("^3ticks^7                    Number of ticks (DOM)"));
-       LOG_INFO(_("^3takes^7                    Number of domination points taken (DOM)"));
-       LOG_INFO(_("^3bckills^7                  Number of ball carrier kills"));
-       LOG_INFO(_("^3bctime^7                   Total amount of time holding the ball in Keepaway"));
-       LOG_INFO(_("^3score^7                    Total score"));
+       LOG_INFO(strcat("^3name^7                     ", _("Name of a player")));
+       LOG_INFO(strcat("^3nick^7                     ", _("Name of a player")));
+       LOG_INFO(strcat("^3ping^7                     ", _("Ping time")));
+       LOG_INFO(strcat("^3pl^7                       ", _("Packet loss")));
+       LOG_INFO(strcat("^3elo^7                      ", _("Player ELO")));
+       LOG_INFO(strcat("^3fps^7                      ", _("Player FPS")));
+       LOG_INFO(strcat("^3kills^7                    ", _("Number of kills")));
+       LOG_INFO(strcat("^3deaths^7                   ", _("Number of deaths")));
+       LOG_INFO(strcat("^3suicides^7                 ", _("Number of suicides")));
+       LOG_INFO(strcat("^3frags^7                    ", _("kills - suicides")));
+       LOG_INFO(strcat("^3teamkills^7                ", _("Number of teamkills")));
+       LOG_INFO(strcat("^3kd^7                       ", _("The kill-death ratio")));
+       LOG_INFO(strcat("^3dmg^7                      ", _("The total damage done")));
+       LOG_INFO(strcat("^3dmgtaken^7                 ", _("The total damage taken")));
+       LOG_INFO(strcat("^3sum^7                      ", _("kills - deaths")));
+       LOG_INFO(strcat("^3caps^7                     ", _("How often a flag (CTF) or a key (KeyHunt) was captured")));
+       LOG_INFO(strcat("^3pickups^7                  ", _("How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up")));
+       LOG_INFO(strcat("^3captime^7                  ", _("Time of fastest cap (CTF)")));
+       LOG_INFO(strcat("^3fckills^7                  ", _("Number of flag carrier kills")));
+       LOG_INFO(strcat("^3returns^7                  ", _("Number of flag returns")));
+       LOG_INFO(strcat("^3drops^7                    ", _("Number of flag drops")));
+       LOG_INFO(strcat("^3lives^7                    ", _("Number of lives (LMS)")));
+       LOG_INFO(strcat("^3rank^7                     ", _("Player rank")));
+       LOG_INFO(strcat("^3pushes^7                   ", _("Number of players pushed into void")));
+       LOG_INFO(strcat("^3destroyed^7                ", _("Number of keys destroyed by pushing them into void")));
+       LOG_INFO(strcat("^3kckills^7                  ", _("Number of keys carrier kills")));
+       LOG_INFO(strcat("^3losses^7                   ", _("Number of times a key was lost")));
+       LOG_INFO(strcat("^3laps^7                     ", _("Number of laps finished (race/cts)")));
+       LOG_INFO(strcat("^3time^7                     ", _("Total time raced (race/cts)")));
+       LOG_INFO(strcat("^3fastest^7                  ", _("Time of fastest lap (race/cts)")));
+       LOG_INFO(strcat("^3ticks^7                    ", _("Number of ticks (DOM)")));
+       LOG_INFO(strcat("^3takes^7                    ", _("Number of domination points taken (DOM)")));
+       LOG_INFO(strcat("^3bckills^7                  ", _("Number of ball carrier kills")));
+       LOG_INFO(strcat("^3bctime^7                   ", _("Total amount of time holding the ball in Keepaway")));
+       LOG_INFO(strcat("^3score^7                    ", _("Total score")));
        LOG_INFO("");
 
        LOG_INFO(_("Before a field you can put a + or - sign, then a comma separated list\n"
                "of game types, then a slash, to make the field show up only in these\n"
                "or in all but these game types. You can also specify 'all' as a\n"
-               "field to show all fields available for the current game mode.\n\n"));
+               "field to show all fields available for the current game mode."));
+       LOG_INFO("");
 
        LOG_INFO(_("The special game type names 'teams' and 'noteams' can be used to\n"
-               "include/exclude ALL teams/noteams game modes.\n\n"));
+               "include/exclude ALL teams/noteams game modes."));
+       LOG_INFO("");
 
        LOG_INFO(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4"));
-       LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields"
-               "right of the vertical bar aligned to the right.\n"));
-       LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\nother gamemodes except DM.\n"));
+       LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields\n"
+               "right of the vertical bar aligned to the right."));
+       LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+                       "other gamemodes except DM."));
 }
 
 // NOTE: adding a gametype with ? to not warn for an optional field
@@ -359,7 +359,7 @@ void Cmd_Scoreboard_Help()
 // otherwise the previous exclusive rule warns anyway
 // e.g. -teams,rc,cts,lms/kills ?+rc/kills
 #define SCOREBOARD_DEFAULT_COLUMNS \
-"ping pl name |" \
+"ping pl fps name |" \
 " -teams,rc,cts,inv,lms/kills +ft,tdm/kills ?+rc,inv/kills" \
 " -teams,lms/deaths +ft,tdm/deaths" \
 " +tdm/sum" \
@@ -405,8 +405,7 @@ void Cmd_Scoreboard_SetFields(int argc)
                        argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
                else if(argv(2) == "all")
                {
-                       string s;
-                       s = "ping pl name |";
+                       string s = "ping pl name |"; // scores without a label
                        FOREACH(Scores, true, {
                                if(it != ps_primary)
                                if(it != ps_secondary)
@@ -427,10 +426,8 @@ void Cmd_Scoreboard_SetFields(int argc)
 
        for(i = 1; i < argc - 1; ++i)
        {
-               float nocomplain;
                str = argv(i+1);
-
-               nocomplain = false;
+               bool nocomplain = false;
                if(substring(str, 0, 1) == "?")
                {
                        nocomplain = true;
@@ -447,8 +444,7 @@ void Cmd_Scoreboard_SetFields(int argc)
                                continue;
                }
 
-               strunzone(sbt_field_title[sbt_num_fields]);
-               sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(str));
+               strcpy(sbt_field_title[sbt_num_fields], TranslateScoresLabel(str));
                sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
                str = strtolower(str);
 
@@ -464,6 +460,7 @@ void Cmd_Scoreboard_SetFields(int argc)
                        case "elo": sbt_field[sbt_num_fields] = SP_ELO; 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;
+                       case "fps": sbt_field[sbt_num_fields] = SP_FPS; break;
                        default:
                        {
                                FOREACH(Scores, true, {
@@ -538,8 +535,7 @@ LABEL(found)
                }
                else if(!have_separator)
                {
-                       strunzone(sbt_field_title[sbt_num_fields]);
-                       sbt_field_title[sbt_num_fields] = strzone("|");
+                       strcpy(sbt_field_title[sbt_num_fields], "|");
                        sbt_field_size[sbt_num_fields] = stringwidth("|", false, hud_fontsize);
                        sbt_field[sbt_num_fields] = SP_SEPARATOR;
                        ++sbt_num_fields;
@@ -547,8 +543,7 @@ LABEL(found)
                }
                if(!have_secondary)
                {
-                       strunzone(sbt_field_title[sbt_num_fields]);
-                       sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(scores_label(ps_secondary)));
+                       strcpy(sbt_field_title[sbt_num_fields], TranslateScoresLabel(scores_label(ps_secondary)));
                        sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
                        sbt_field[sbt_num_fields] = ps_secondary;
                        ++sbt_num_fields;
@@ -556,8 +551,7 @@ LABEL(found)
                }
                if(!have_primary)
                {
-                       strunzone(sbt_field_title[sbt_num_fields]);
-                       sbt_field_title[sbt_num_fields] = strzone(TranslateScoresLabel(scores_label(ps_primary)));
+                       strcpy(sbt_field_title[sbt_num_fields], TranslateScoresLabel(scores_label(ps_primary)));
                        sbt_field_size[sbt_num_fields] = stringwidth(sbt_field_title[sbt_num_fields], false, hud_fontsize);
                        sbt_field[sbt_num_fields] = ps_primary;
                        ++sbt_num_fields;
@@ -679,6 +673,19 @@ string Scoreboard_GetField(entity pl, PlayerScoreField field)
                        }
                }
 
+               case SP_FPS:
+               {
+                       float fps = pl.(scores(SP_FPS));
+                       if(fps == 0)
+                       {
+                               sbt_field_rgb = '1 1 1';
+                               return ((pl.ping == 0) ? _("N/A") : "..."); // if 0 ping, either connecting or bot (either case can't show proper score)
+                       }
+                       //sbt_field_rgb = HUD_Get_Num_Color(fps, 200);
+                       sbt_field_rgb = '1 0 0' + '0 1 1' * (bound(0, fps, 60) / 60);
+                       return ftos(fps);
+               }
+
                case SP_DMG: case SP_DMGTAKEN:
                        return sprintf("%.1f k", pl.(scores(field)) / 1000);
 
@@ -1474,9 +1481,7 @@ void Scoreboard_Draw()
                        {
                                hud_fontsize = HUD_GetFontsize("hud_fontsize");
                                Scoreboard_initFieldSizes();
-                               if(hud_fontsize_str)
-                                       strunzone(hud_fontsize_str);
-                               hud_fontsize_str = strzone(autocvar_hud_fontsize);
+                               strcpy(hud_fontsize_str, autocvar_hud_fontsize);
                        }
                }
                else {
index 15e18e8f445a2b86f7ed9af851c332a856b99e4c..57b32039dc50fdf401d4da978413c0e4192a800f 100644 (file)
@@ -27,9 +27,7 @@ void HUD_Vote()
                        LOG_INFO(_("^1You must answer before entering hud configure mode"));
                        cvar_set("_hud_configure", "0");
                }
-               if(vote_called_vote)
-                       strunzone(vote_called_vote);
-               vote_called_vote = strzone(_("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
+               strcpy(vote_called_vote, _("^2Name ^7instead of \"^1Anonymous player^7\" in stats"));
                uid2name_dialog = 1;
        }
 
index cebd8f5d65c162b6e3d15d90a5e7a496bbbc0858..4506f69a0c591b603d41ca4fa5f6a497581c071f 100644 (file)
@@ -30,7 +30,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_HIDDEN || 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; \
@@ -94,13 +94,8 @@ void HUD_Weapons()
        if(weaponorder_bypriority != autocvar_cl_weaponpriority || !weaponorder[0])
        {
                int weapon_cnt;
-               if(weaponorder_bypriority)
-                       strunzone(weaponorder_bypriority);
-               if(weaponorder_byimpulse)
-                       strunzone(weaponorder_byimpulse);
-
-               weaponorder_bypriority = strzone(autocvar_cl_weaponpriority);
-               weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
+               strcpy(weaponorder_bypriority, autocvar_cl_weaponpriority);
+               strcpy(weaponorder_byimpulse, W_FixWeaponOrder_BuildImpulseList(W_FixWeaponOrder_ForceComplete(W_NumberWeaponOrder(weaponorder_bypriority))));
                weaponorder_cmp_str = strcat(" ", weaponorder_byimpulse, " ");
 
                weapon_cnt = 0;
@@ -407,7 +402,7 @@ void HUD_Weapons()
                }
                else
                {
-                       if (it.spawnflags & WEP_FLAG_MUTATORBLOCKED && !(weapons_stat & WepSet_FromWeapon(it)))
+                       if (((it.spawnflags & WEP_FLAG_HIDDEN) || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED)) && !(weapons_stat & WepSet_FromWeapon(it)))
                                continue;
                }
 
index 9c146c09bd9115091c24585fc02c323558b75d19..3de8cefeb661084515be0ebe365d88f73888ede5 100644 (file)
@@ -8,13 +8,14 @@
 #include <common/effects/all.qh>
 #include <common/effects/all.inc>
 #include "hud/_mod.qh"
+#include "commands/cl_cmd.qh"
 #include "mapvoting.qh"
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
 #include "hud/panel/scoreboard.qh"
 #include "hud/panel/quickmenu.qh"
 #include "shownames.qh"
+#include "view.qh"
 #include <common/t_items.qh>
-#include "wall.qh"
 #include "weapons/projectile.qh"
 #include <common/deathtypes/all.qh>
 #include <common/items/_mod.qh>
@@ -24,7 +25,7 @@
 #include <common/net_linked.qh>
 #include <common/net_notice.qh>
 #include <common/scores.qh>
-#include <common/triggers/include.qh>
+#include <common/mapobjects/_mod.qh>
 #include <common/vehicles/all.qh>
 #include <lib/csqcmodel/cl_model.qh>
 #include <lib/csqcmodel/interpolate.qh>
@@ -91,7 +92,6 @@ void LoadMenuSkinValues()
 // CSQC_Init : Called every time the CSQC code is initialized (essentially at map load)
 // Useful for precaching things
 
-void ConsoleCommand_macro_init();
 void CSQC_Init()
 {
        prvm_language = strzone(cvar_string("prvm_language"));
@@ -343,7 +343,6 @@ void Playerchecker_Think(entity this)
        this.nextthink = time + 0.2;
 }
 
-void TrueAim_Init();
 void PostInit()
 {
        entity playerchecker = new_pure(playerchecker);
@@ -389,8 +388,6 @@ float CSQC_InputEvent(int bInputType, float nPrimary, float nSecondary)
 // --------------------------------------------------------------------------
 // BEGIN OPTIONAL CSQC FUNCTIONS
 
-void Ent_Remove(entity this);
-
 void Ent_RemovePlayerScore(entity this)
 {
        if(this.owner) {
@@ -555,9 +552,7 @@ NET_HANDLE(ENT_CLIENT_NAGGER, bool isnew)
 
        if(!(nags & BIT(2)))
        {
-               if(vote_called_vote)
-                       strunzone(vote_called_vote);
-               vote_called_vote = string_null;
+               strfree(vote_called_vote);
                vote_active = 0;
        }
        else
@@ -575,9 +570,7 @@ NET_HANDLE(ENT_CLIENT_NAGGER, bool isnew)
 
        if(nags & BIT(7))
        {
-               if(vote_called_vote)
-                       strunzone(vote_called_vote);
-               vote_called_vote = strzone(ReadString());
+               strcpy(vote_called_vote, ReadString());
        }
 
        if(nags & 1)
@@ -951,7 +944,6 @@ void Fog_Force()
                localcmd(sprintf("\nfog %s\nr_fog_exp2 0\nr_drawfog 1\n", forcefog));
 }
 
-void Gamemode_Init();
 NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
 {
        make_pure(this);
@@ -959,14 +951,12 @@ NET_HANDLE(ENT_CLIENT_SCORES_INFO, bool isnew)
        teamplay = _MapInfo_GetTeamPlayBool(gametype);
        HUD_ModIcons_SetFunc();
        FOREACH(Scores, true, {
-               if (scores_label(it)) strunzone(scores_label(it));
-               scores_label(it) = strzone(ReadString());
+               strcpy(scores_label(it), ReadString());
                scores_flags(it) = ReadByte();
        });
        for (int i = 0; i < MAX_TEAMSCORE; ++i)
        {
-               if (teamscores_label(i)) strunzone(teamscores_label(i));
-               teamscores_label(i) = strzone(ReadString());
+               strcpy(teamscores_label(i), ReadString());
                teamscores_flags(i) = ReadByte();
        }
        return = true;
@@ -987,8 +977,7 @@ NET_HANDLE(ENT_CLIENT_INIT, bool isnew)
        arc_shotorigin[2] = decompressShotOrigin(ReadInt24_t());
        arc_shotorigin[3] = decompressShotOrigin(ReadInt24_t());
 
-       if (forcefog) strunzone(forcefog);
-       forcefog = strzone(ReadString());
+       strcpy(forcefog, ReadString());
 
        armorblockpercent = ReadByte() / 255.0;
        damagepush_speedfactor = ReadByte() / 255.0;
@@ -1051,17 +1040,15 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        race_time = ReadInt24_t();
                        race_previousbesttime = ReadInt24_t();
                        race_mypreviousbesttime = ReadInt24_t();
-                       if(race_previousbestname)
-                               strunzone(race_previousbestname);
                        string pbestname = ReadString();
                        if(autocvar_cl_race_cptimes_onlyself)
                        {
                                race_previousbesttime = race_mypreviousbesttime;
                                race_mypreviousbesttime = 0;
-                               race_previousbestname = strzone("");
+                               strcpy(race_previousbestname, "");
                        }
                        else
-                               race_previousbestname = strzone(pbestname);
+                               strcpy(race_previousbestname, pbestname);
 
                        race_checkpointtime = time;
 
@@ -1087,17 +1074,15 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        race_nextbesttime = ReadInt24_t();
                        if(b != RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING) // not while spectating (matches server)
                                race_mybesttime = ReadInt24_t();
-                       if(race_nextbestname)
-                               strunzone(race_nextbestname);
                        string newname = ReadString();
                        if(autocvar_cl_race_cptimes_onlyself && b != RACE_NET_CHECKPOINT_NEXT_SPEC_QUALIFYING)
                        {
                                race_nextbesttime = race_mybesttime;
                                race_mybesttime = 0;
-                               race_nextbestname = strzone("");
+                               strcpy(race_nextbestname, "");
                        }
                        else
-                               race_nextbestname = strzone(newname);
+                               strcpy(race_nextbestname, newname);
                        break;
 
                case RACE_NET_CHECKPOINT_HIT_RACE:
@@ -1107,13 +1092,11 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        race_mycheckpointlapsdelta = ReadByte();
                        if(race_mycheckpointlapsdelta >= 128)
                                race_mycheckpointlapsdelta -= 256;
-                       if(race_mycheckpointenemy)
-                               strunzone(race_mycheckpointenemy);
                        int who = ReadByte();
                        if(who)
-                               race_mycheckpointenemy = strzone(entcs_GetName(who - 1));
+                               strcpy(race_mycheckpointenemy, entcs_GetName(who - 1));
                        else
-                               race_mycheckpointenemy = strzone(""); // TODO: maybe string_null works fine here?
+                               strcpy(race_mycheckpointenemy, ""); // TODO: maybe string_null works fine here?
                        break;
 
                case RACE_NET_CHECKPOINT_HIT_RACE_BY_OPPONENT:
@@ -1123,31 +1106,25 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        race_othercheckpointlapsdelta = ReadByte();
                        if(race_othercheckpointlapsdelta >= 128)
                                race_othercheckpointlapsdelta -= 256;
-                       if(race_othercheckpointenemy)
-                               strunzone(race_othercheckpointenemy);
                        int what = ReadByte();
                        if(what)
-                               race_othercheckpointenemy = strzone(entcs_GetName(what - 1));
+                               strcpy(race_othercheckpointenemy, entcs_GetName(what - 1));
                        else
-                               race_othercheckpointenemy = strzone(""); // TODO: maybe string_null works fine here?
+                               strcpy(race_othercheckpointenemy, ""); // TODO: maybe string_null works fine here?
                        break;
 
                case RACE_NET_PENALTY_RACE:
                        race_penaltyeventtime = time;
                        race_penaltytime = ReadShort();
                        //race_penaltyaccumulator += race_penaltytime;
-                       if(race_penaltyreason)
-                               strunzone(race_penaltyreason);
-                       race_penaltyreason = strzone(ReadString());
+                       strcpy(race_penaltyreason, ReadString());
                        break;
 
                case RACE_NET_PENALTY_QUALIFYING:
                        race_penaltyeventtime = time;
                        race_penaltytime = ReadShort();
                        race_penaltyaccumulator += race_penaltytime;
-                       if(race_penaltyreason)
-                               strunzone(race_penaltyreason);
-                       race_penaltyreason = strzone(ReadString());
+                       strcpy(race_penaltyreason, ReadString());
                        break;
 
                case RACE_NET_SERVER_RECORD:
@@ -1155,21 +1132,16 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        break;
                case RACE_NET_SPEED_AWARD:
                        race_speedaward = ReadInt24_t() * GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
-                       if(race_speedaward_holder)
-                               strunzone(race_speedaward_holder);
-                       race_speedaward_holder = strzone(ReadString());
-                       if(race_speedaward_unit)
-                               strunzone(race_speedaward_unit);
-                       race_speedaward_unit = strzone(GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
+                       strcpy(race_speedaward_holder, ReadString());
+                       strcpy(race_speedaward_unit, GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
                        break;
                case RACE_NET_SPEED_AWARD_BEST:
                        race_speedaward_alltimebest = ReadInt24_t() * GetSpeedUnitFactor(autocvar_hud_panel_physics_speed_unit);
-                       if(race_speedaward_alltimebest_holder)
-                               strunzone(race_speedaward_alltimebest_holder);
-                       race_speedaward_alltimebest_holder = strzone(ReadString());
-                       if(race_speedaward_alltimebest_unit)
-                               strunzone(race_speedaward_alltimebest_unit);
-                       race_speedaward_alltimebest_unit = strzone(GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
+                       strcpy(race_speedaward_alltimebest_holder, ReadString());
+                       strcpy(race_speedaward_alltimebest_unit, GetSpeedUnit(autocvar_hud_panel_physics_speed_unit));
+                       break;
+               case RACE_NET_RANKINGS_CNT:
+                       RANKINGS_DISPLAY_CNT = ReadByte();
                        break;
                case RACE_NET_SERVER_RANKINGS:
                        float prevpos, del;
@@ -1180,49 +1152,44 @@ NET_HANDLE(TE_CSQC_RACE, bool isNew)
                        // move other rankings out of the way
             int i;
                        if (prevpos) {
-                               for (i=prevpos-1;i>pos-1;--i) {
+                               int m = min(prevpos, RANKINGS_DISPLAY_CNT);
+                               for (i=m-1; i>pos-1; --i) {
                                        grecordtime[i] = grecordtime[i-1];
-                                       if(grecordholder[i])
-                                               strunzone(grecordholder[i]);
-                                       grecordholder[i] = strzone(grecordholder[i-1]);
+                                       strcpy(grecordholder[i], grecordholder[i-1]);
                                }
                        } else if (del) { // a record has been deleted by the admin
-                               for (i=pos-1; i<= RANKINGS_CNT-1; ++i) {
-                                       if (i == RANKINGS_CNT-1) { // clear out last record
+                               for (i=pos-1; i<= RANKINGS_DISPLAY_CNT-1; ++i) {
+                                       if (i == RANKINGS_DISPLAY_CNT-1) { // clear out last record
                                                grecordtime[i] = 0;
-                                               if (grecordholder[i])
-                                                       strunzone(grecordholder[i]);
-                                               grecordholder[i] = string_null;
+                                               strfree(grecordholder[i]);
                                        }
                                        else {
                                                grecordtime[i] = grecordtime[i+1];
-                                               if (grecordholder[i])
-                                                       strunzone(grecordholder[i]);
-                                               grecordholder[i] = strzone(grecordholder[i+1]);
+                                               strcpy(grecordholder[i], grecordholder[i+1]);
                                        }
                                }
                        } else { // player has no ranked record yet
-                               for (i=RANKINGS_CNT-1;i>pos-1;--i) {
+                               for (i=RANKINGS_DISPLAY_CNT-1;i>pos-1;--i) {
                                        grecordtime[i] = grecordtime[i-1];
-                                       if(grecordholder[i])
-                                               strunzone(grecordholder[i]);
-                                       grecordholder[i] = strzone(grecordholder[i-1]);
+                                       strcpy(grecordholder[i], grecordholder[i-1]);
                                }
                        }
 
+                       if (grecordtime[RANKINGS_DISPLAY_CNT]) {
+                               // kick off the player who fell from the last displayed position
+                               grecordtime[RANKINGS_DISPLAY_CNT] = 0;
+                               strfree(grecordholder[RANKINGS_DISPLAY_CNT]);
+                       }
+
                        // store new ranking
-                       if(grecordholder[pos-1] != "")
-                               strunzone(grecordholder[pos-1]);
-                       grecordholder[pos-1] = strzone(ReadString());
+                       strcpy(grecordholder[pos-1], ReadString());
                        grecordtime[pos-1] = ReadInt24_t();
                        if(strdecolorize(grecordholder[pos-1]) == strdecolorize(entcs_GetName(player_localnum)))
                                race_myrank = pos;
                        break;
                case RACE_NET_SERVER_STATUS:
                        race_status = ReadShort();
-                       if(race_status_name)
-                               strunzone(race_status_name);
-                       race_status_name = strzone(ReadString());
+                       strcpy(race_status_name, ReadString());
        }
        return true;
 }
index a2f4d18bba97e2ef4070fe83ac362d83dd462404..a95acd5739672b5fe096b1e2891220ab92fe3f40 100644 (file)
@@ -21,9 +21,18 @@ void draw_cursor(vector pos, vector ofs, string img, vector col, float a);
 void draw_cursor_normal(vector pos, vector col, float a);
 void LoadMenuSkinValues();
 
+void PostInit();
+
+void Ent_Remove(entity this);
+
+void Gamemode_Init();
+
+float SetTeam(entity pl, float Team);
+
 vector hud_fontsize;
 
 float RANKINGS_RECEIVED_CNT;
+float RANKINGS_DISPLAY_CNT;
 string grecordholder[RANKINGS_CNT];
 float grecordtime[RANKINGS_CNT];
 
index 87b6d585b38c769cd8d20d65d0be24ad3303d52d..8412bd757964ffdec471381121b8a923af5a152c 100644 (file)
@@ -321,7 +321,6 @@ float MapVote_Selection(vector topleft, vector cellsize, float rows, float colum
        return mv_mouse_selection;
 }
 
-vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect);
 void MapVote_Draw()
 {
        string map;
index fd1647ddcce350abe5a7af8ea85b2e2fe70f1630..01409280a4a4c9f535cf18e6c0f7f21b2eb1d8b0 100644 (file)
@@ -577,9 +577,7 @@ void Accuracy_LoadLevels()
 {
        if(autocvar_accuracy_color_levels != acc_color_levels)
        {
-               if(acc_color_levels)
-                       strunzone(acc_color_levels);
-               acc_color_levels = strzone(autocvar_accuracy_color_levels);
+               strcpy(acc_color_levels, autocvar_accuracy_color_levels);
                acc_levels = tokenize_console(acc_color_levels);
                if(acc_levels > MAX_ACCURACY_LEVELS)
                        acc_levels = MAX_ACCURACY_LEVELS;
index 24d634ce8213e05759f7afed13f2f0b011be5146..cc6fced9b820a2885cf932118997f0bcfe44588b 100644 (file)
@@ -2,6 +2,11 @@
 
 #include <common/mutators/base.qh>
 
+// register all possible hooks here
+
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
+
 /**
  * Called when a client command is parsed
  * NOTE: hooks MUST start with if (MUTATOR_RETURNVALUE) return false;
index 55e54d8ac2c641ad49b10bf03a979f0603eff9d3..bb1b6f919b840c78a2bca6d339245e5b057acbc1 100644 (file)
@@ -2,19 +2,19 @@
 
 #include <common/physics/movetypes/movetypes.qh>
 #include <common/physics/player.qh>
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
 #include "../lib/csqcmodel/cl_player.qh"
 #include "../lib/warpzone/anglestransform.qh"
 
 .float v_angle_save_x;
 
-class(Skeleton) .float skeleton_info_modelindex;
-class(Skeleton) .float skeleton_info_skin;
+classfield(Skeleton) .float skeleton_info_modelindex;
+classfield(Skeleton) .float skeleton_info_skin;
 const int BONETYPE_LOWER = 0;
 const int BONETYPE_UPPER = 1;
 const int MAX_BONES = 128;
-class(Skeleton) .float skeleton_bonetype[MAX_BONES];
-class(Skeleton) .float skeleton_numbones;
+classfield(Skeleton) .float skeleton_bonetype[MAX_BONES];
+classfield(Skeleton) .float skeleton_numbones;
 
 void skeleton_loadinfo(entity e)
 {
index 8c5969b09fb4db0ae068b7aa50338215be07b2dd..082335e4b0f61bedbdd39a62b6bc16f8376c9870 100644 (file)
@@ -7,8 +7,8 @@ void skeleton_from_frames(entity e, float is_dead);
 void skeleton_loadinfo(entity e);
 
 entityclass(Skeleton);
-class(Skeleton) .float bone_upperbody;
-class(Skeleton) .int bone_weapon;
-class(Skeleton) .float bone_aim[MAX_AIM_BONES];
-class(Skeleton) .float bone_aimweight[MAX_AIM_BONES];
-class(Skeleton) .float fixbone;
+classfield(Skeleton) .float bone_upperbody;
+classfield(Skeleton) .int bone_weapon;
+classfield(Skeleton) .float bone_aim[MAX_AIM_BONES];
+classfield(Skeleton) .float bone_aimweight[MAX_AIM_BONES];
+classfield(Skeleton) .float fixbone;
index 24f6568d26629396ff7322bfae3b97695f545d3d..a05ca701d03ab2abfc08495fffc6afb469d7f149 100644 (file)
@@ -1,10 +1,10 @@
 #pragma once
 
 entityclass(ShowNames);
-class(ShowNames) .float healthvalue;
-class(ShowNames) .float armorvalue;
-class(ShowNames) .float sameteam;
-class(ShowNames) .float fadedelay;
-class(ShowNames) .float pointtime;
+classfield(ShowNames) .float healthvalue;
+classfield(ShowNames) .float armorvalue;
+classfield(ShowNames) .float sameteam;
+classfield(ShowNames) .float fadedelay;
+classfield(ShowNames) .float pointtime;
 
 void Draw_ShowNames_All();
index 251c1a53f12a9185f0c5274839479066a4d7e759..41c7d46c564465924e272e585f249db640639b23 100644 (file)
@@ -4,10 +4,10 @@ const int MAX_TEAMRADAR_TIMES = 32;
 
 entityclass(TeamRadar);
 // to make entities have dots on the team radar
-class(TeamRadar) .float teamradar_icon;
-class(TeamRadar) .float teamradar_times[MAX_TEAMRADAR_TIMES];
-class(TeamRadar) .int teamradar_time_index;
-class(TeamRadar) .vector teamradar_color;
+classfield(TeamRadar) .float teamradar_icon;
+classfield(TeamRadar) .float teamradar_times[MAX_TEAMRADAR_TIMES];
+classfield(TeamRadar) .int teamradar_time_index;
+classfield(TeamRadar) .vector teamradar_color;
 
 float teamradar_angle; // player yaw angle
 vector teamradar_origin3d_in_texcoord; // player origin
index 9bfa8db9ad0d6e51590150d28896883626528716..d036bd75df1b95e2552c59741658461796131d43 100644 (file)
@@ -9,7 +9,7 @@
 #include "hud/panel/scoreboard.qh"
 #include "hud/panel/quickmenu.qh"
 
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
 
 #include <common/animdecide.qh>
 #include <common/deathtypes/all.qh>
 #include <common/anim.qh>
 #include <common/constants.qh>
 #include <common/net_linked.qh>
+#include <common/net_notice.qh>
 #include <common/debug.qh>
 #include <common/mapinfo.qh>
 #include <common/gamemodes/_mod.qh>
 #include <common/physics/player.qh>
 #include <common/stats.qh>
-#include <common/triggers/target/music.qh>
+#include <common/mapobjects/target/music.qh>
 #include <common/teams.qh>
 #include <common/wepent.qh>
 
 
 #include <common/vehicles/all.qh>
 #include <common/weapons/_all.qh>
+#include <common/mutators/mutator/overkill/oknex.qh>
+#include <common/mutators/mutator/waypoints/all.qh>
 #include <common/viewloc.qh>
-#include <common/triggers/trigger/viewloc.qh>
+#include <common/mapobjects/trigger/viewloc.qh>
 #include <common/minigames/cl_minigames.qh>
 #include <common/minigames/cl_minigames_hud.qh>
 
@@ -370,7 +373,35 @@ STATIC_INIT(viewmodel) {
        viewmodels[slot] = new(viewmodel);
 }
 
-void Porto_Draw(entity this);
+float showfps_prevfps;
+float showfps_prevfps_time;
+int showfps_framecounter;
+
+void fpscounter_update()
+{
+       if(!STAT(SHOWFPS))
+               return;
+
+       float currentTime = gettime(GETTIME_REALTIME);
+       showfps_framecounter += 1;
+       if(currentTime - showfps_prevfps_time > STAT(SHOWFPS))
+       {
+               showfps_prevfps = showfps_framecounter/(currentTime - showfps_prevfps_time);
+               showfps_framecounter = 0;
+               showfps_prevfps_time = currentTime;
+
+               int channel = MSG_C2S;
+               WriteHeader(channel, fpsreport);
+               WriteShort(channel, bound(0, rint(showfps_prevfps), 65535)); // prevent insane fps values
+       }
+}
+
+STATIC_INIT(fpscounter_init)
+{
+       float currentTime = gettime(GETTIME_REALTIME);
+       showfps_prevfps_time = currentTime; // we must initialize it to avoid an instant low frame sending
+}
+
 STATIC_INIT(Porto)
 {
        entity e = new_pure(porto);
@@ -669,6 +700,7 @@ float TrueAimCheck(entity wepent)
                case WEP_MORTAR: // toss curve
                        return SHOTTYPE_HITWORLD;
                case WEP_VORTEX:
+               case WEP_OVERKILL_NEX:
                case WEP_VAPORIZER:
                        mv = MOVE_NORMAL;
                        break;
@@ -737,8 +769,6 @@ float TrueAimCheck(entity wepent)
        return SHOTTYPE_HITWORLD;
 }
 
-void PostInit();
-void CSQC_Demo_Camera();
 float camera_mode;
 const float CAMERA_FREE = 1;
 const float CAMERA_CHASE = 2;
@@ -1199,6 +1229,8 @@ void HUD_Crosshair(entity this)
                                float arc_heat = wepent.arc_heat_percent;
                                float vcharge = wepent.vortex_charge;
                                float vchargepool = wepent.vortex_chargepool_ammo;
+                               float oknex_charge_ = wepent.oknex_charge;
+                               float oknex_chargepool_ = wepent.oknex_chargepool_ammo;
 
                                if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
                                        vortex_charge_movingavg = vcharge;
@@ -1224,6 +1256,26 @@ void HUD_Crosshair(entity this)
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring_nexgun.tga";
                                }
+                               else if (autocvar_crosshair_ring && (wepent.activeweapon == WEP_OVERKILL_NEX) && oknex_charge_ && autocvar_crosshair_ring_vortex)
+                               {
+                                       if (oknex_chargepool_ || use_vortex_chargepool) {
+                                               use_vortex_chargepool = 1;
+                                               ring_inner_value = oknex_chargepool_;
+                                       } else {
+                                               vortex_charge_movingavg = (1 - autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate) * vortex_charge_movingavg + autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate * oknex_charge_;
+                                               ring_inner_value = bound(0, autocvar_crosshair_ring_vortex_currentcharge_scale * (oknex_charge_ - vortex_charge_movingavg), 1);
+                                       }
+
+                                       ring_inner_alpha = autocvar_crosshair_ring_vortex_inner_alpha;
+                                       ring_inner_rgb = eX * autocvar_crosshair_ring_vortex_inner_color_red + eY * autocvar_crosshair_ring_vortex_inner_color_green + eZ * autocvar_crosshair_ring_vortex_inner_color_blue;
+                                       ring_inner_image = "gfx/crosshair_ring_inner.tga";
+
+                                       // draw the outer ring to show the current charge of the weapon
+                                       ring_value = oknex_charge_;
+                                       ring_alpha = autocvar_crosshair_ring_vortex_alpha;
+                                       ring_rgb = wcross_color;
+                                       ring_image = "gfx/crosshair_ring_nexgun.tga";
+                               }
                                else if (autocvar_crosshair_ring && wepent.activeweapon == WEP_MINE_LAYER && WEP_CVAR(minelayer, limit) && autocvar_crosshair_ring_minelayer)
                                {
                                        ring_value = bound(0, wepent.minelayer_mines / WEP_CVAR(minelayer, limit), 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
@@ -1346,12 +1398,8 @@ void HUD_Crosshair(entity this)
                wcross_scale_goal_prev = 0;
                wcross_alpha_goal_prev = 0;
                wcross_changedonetime = 0;
-               if(wcross_name_goal_prev)
-                       strunzone(wcross_name_goal_prev);
-               wcross_name_goal_prev = string_null;
-               if(wcross_name_goal_prev_prev)
-                       strunzone(wcross_name_goal_prev_prev);
-               wcross_name_goal_prev_prev = string_null;
+               strfree(wcross_name_goal_prev);
+               strfree(wcross_name_goal_prev_prev);
                wcross_name_changestarttime = 0;
                wcross_name_changedonetime = 0;
                wcross_name_alpha_goal_prev = 0;
@@ -1512,12 +1560,9 @@ float oldr_novis;
 float oldr_useportalculling;
 float oldr_useinfinitefarclip;
 
-void cl_notice_run();
-
 float prev_myteam;
 int lasthud;
 float vh_notice_time;
-void WaypointSprite_Load();
 void CSQC_UpdateView(entity this, float w, float h)
 {
     TC(int, w); TC(int, h);
@@ -1866,6 +1911,7 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        TargetMusic_Advance();
        Fog_Force();
+       fpscounter_update();
 
        if(drawtime == 0)
                drawframetime = 0.01666667; // when we don't know fps yet, we assume 60fps
index 0a2c5c0c7066263f5a893538c5c26c152490f342..93af4255e2b95570cd5ab278b22af71110b8368e 100644 (file)
@@ -4,6 +4,14 @@
 
 vector crosshair_getcolor(entity this, float health_stat);
 
+void calc_followmodel_ofs(entity view);
+
+void Porto_Draw(entity this);
+
+void CSQC_Demo_Camera();
+
+void TrueAim_Init();
+
 entity viewmodels[MAX_WEAPONSLOTS];
 
 vector viewloc_mousepos;
diff --git a/qcsrc/client/wall.qc b/qcsrc/client/wall.qc
deleted file mode 100644 (file)
index b572809..0000000
+++ /dev/null
@@ -1,230 +0,0 @@
-#include "wall.qh"
-
-#include "autocvars.qh"
-#include "main.qh"
-#include "bgmscript.qh"
-
-
-#include "../lib/csqcmodel/interpolate.qh"
-
-.float alpha;
-.float scale;
-.vector movedir;
-
-void Ent_Wall_PreDraw(entity this)
-{
-       if (this.inactive)
-       {
-               this.alpha = 0;
-       }
-       else
-       {
-               vector org = getpropertyvec(VF_ORIGIN);
-               if(!checkpvs(org, this))
-                       this.alpha = 0;
-               else if(this.fade_start || this.fade_end) {
-                       vector offset = '0 0 0';
-                       offset_z = this.fade_vertical_offset;
-                       float player_dist = vlen(org - this.origin - 0.5 * (this.mins + this.maxs) + offset);
-                       if (this.fade_end == this.fade_start)
-                       {
-                               if (player_dist >= this.fade_start)
-                                       this.alpha = 0;
-                               else
-                                       this.alpha = 1;
-                       }
-                       else
-                       {
-                               this.alpha = (this.alpha_min + this.alpha_max * bound(0,
-                                                          (this.fade_end - player_dist)
-                                                          / (this.fade_end - this.fade_start), 1)) / 100.0;
-                       }
-               }
-               else
-               {
-                       this.alpha = 1;
-               }
-       }
-       if(this.alpha <= 0)
-               this.drawmask = 0;
-       else
-               this.drawmask = MASK_NORMAL;
-}
-
-void Ent_Wall_Draw(entity this)
-{
-       float f;
-       var .vector fld;
-
-       if(this.bgmscriptangular)
-               fld = angles;
-       else
-               fld = origin;
-       this.(fld) = this.saved;
-
-       if(this.lodmodelindex1)
-       {
-               if(autocvar_cl_modeldetailreduction <= 0)
-               {
-                       if(this.lodmodelindex2 && autocvar_cl_modeldetailreduction <= -2)
-                               this.modelindex = this.lodmodelindex2;
-                       else if(autocvar_cl_modeldetailreduction <= -1)
-                               this.modelindex = this.lodmodelindex1;
-                       else
-                               this.modelindex = this.lodmodelindex0;
-               }
-               else
-               {
-                       float distance = vlen(NearestPointOnBox(this, view_origin) - view_origin);
-                       f = (distance * current_viewzoom + 100.0) * autocvar_cl_modeldetailreduction;
-                       f *= 1.0 / bound(0.01, view_quality, 1);
-                       if(this.lodmodelindex2 && f > this.loddistance2)
-                               this.modelindex = this.lodmodelindex2;
-                       else if(f > this.loddistance1)
-                               this.modelindex = this.lodmodelindex1;
-                       else
-                               this.modelindex = this.lodmodelindex0;
-               }
-       }
-
-       InterpolateOrigin_Do(this);
-
-       this.saved = this.(fld);
-
-       f = doBGMScript(this);
-       if(f >= 0)
-       {
-               if(this.lip < 0) // < 0: alpha goes from 1 to 1-|lip| when toggled (toggling subtracts lip)
-                       this.alpha = 1 + this.lip * f;
-               else // > 0: alpha goes from 1-|lip| to 1 when toggled (toggling adds lip)
-                       this.alpha = 1 - this.lip * (1 - f);
-               this.(fld) = this.(fld) + this.movedir * f;
-       }
-       else
-               this.alpha = 1;
-
-       if(this.alpha >= ALPHA_MIN_VISIBLE)
-               this.drawmask = MASK_NORMAL;
-       else
-               this.drawmask = 0;
-}
-
-void Ent_Wall_Remove(entity this)
-{
-       if(this.bgmscript)
-               strunzone(this.bgmscript);
-       this.bgmscript = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
-{
-       int f;
-       var .vector fld;
-
-       InterpolateOrigin_Undo(this);
-       this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
-
-       if(this.bgmscriptangular)
-               fld = angles;
-       else
-               fld = origin;
-       this.(fld) = this.saved;
-
-       f = ReadByte();
-
-       if(f & 1)
-       {
-               if(f & 0x40)
-                       this.colormap = ReadShort();
-               else
-                       this.colormap = 0;
-               this.skin = ReadByte();
-       }
-
-       if(f & 2)
-       {
-               this.origin = ReadVector();
-               setorigin(this, this.origin);
-       }
-
-       if(f & 4)
-       {
-               if(f & 0x10)
-               {
-                       this.angles_x = ReadAngle();
-                       this.angles_y = ReadAngle();
-                       this.angles_z = ReadAngle();
-               }
-               else
-                       this.angles = '0 0 0';
-       }
-
-       if(f & 8)
-       {
-               if(f & 0x80)
-               {
-                       this.lodmodelindex0 = ReadShort();
-                       this.loddistance1 = ReadShort();
-                       this.lodmodelindex1 = ReadShort();
-                       this.loddistance2 = ReadShort();
-                       this.lodmodelindex2 = ReadShort();
-               }
-               else
-               {
-                       this.modelindex = ReadShort();
-                       this.loddistance1 = 0;
-                       this.loddistance2 = 0;
-               }
-               this.solid = ReadByte();
-               this.scale = ReadShort() / 256.0;
-               if(f & 0x20)
-               {
-                       this.mins = ReadVector();
-                       this.maxs = ReadVector();
-               }
-               else
-                       this.mins = this.maxs = '0 0 0';
-               setsize(this, this.mins, this.maxs);
-
-               if(this.bgmscript)
-                       strunzone(this.bgmscript);
-               this.bgmscript = ReadString();
-               if(substring(this.bgmscript, 0, 1) == "<")
-               {
-                       this.bgmscript = strzone(substring(this.bgmscript, 1, -1));
-                       this.bgmscriptangular = 1;
-               }
-               else
-               {
-                       this.bgmscript = strzone(this.bgmscript);
-                       this.bgmscriptangular = 0;
-               }
-               if(this.bgmscript != "")
-               {
-                       this.bgmscriptattack = ReadByte() / 64.0;
-                       this.bgmscriptdecay = ReadByte() / 64.0;
-                       this.bgmscriptsustain = ReadByte() / 255.0;
-                       this.bgmscriptrelease = ReadByte() / 64.0;
-                       this.movedir = ReadVector();
-                       this.lip = ReadByte() / 255.0;
-               }
-               this.fade_start = ReadByte();
-               this.fade_end = ReadByte();
-               this.alpha_max = ReadByte();
-               this.alpha_min = ReadByte();
-               this.inactive = ReadByte();
-               this.fade_vertical_offset = ReadShort();
-               BGMScript_InitEntity(this);
-       }
-
-       return = true;
-
-       InterpolateOrigin_Note(this);
-
-       this.saved = this.(fld);
-
-       this.entremove = Ent_Wall_Remove;
-       this.draw = Ent_Wall_Draw;
-       if (isnew) IL_PUSH(g_drawables, this);
-       setpredraw(this, Ent_Wall_PreDraw);
-}
diff --git a/qcsrc/client/wall.qh b/qcsrc/client/wall.qh
deleted file mode 100644 (file)
index 11aebd0..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#pragma once
-
-entityclass(Wall);
-class(Wall) .float lip;
-class(Wall) .float bgmscriptangular;
-class(Wall) .int lodmodelindex0, lodmodelindex1, lodmodelindex2;
-class(Wall) .float loddistance1, loddistance2;
-class(Wall) .vector saved;
-
-// Needed for interactive clientwalls
-.float inactive; // Clientwall disappears when inactive
-.float alpha_max, alpha_min;
-// If fade_start > fade_end, fadeout will be inverted
-// fade_vertical_offset is a vertival offset for player position
-.float fade_start, fade_end, fade_vertical_offset;
-.float default_solid;
-
-void Ent_Wall_Draw(entity this);
-
-void Ent_Wall_Remove(entity this);
index 089c7df11fd326f0598f0243c59933a50a8a03a5..41b97694496616fa4de17b8f73aa2c163cb2fa6d 100644 (file)
@@ -3,7 +3,7 @@
 #include "../autocvars.qh"
 #include "../defs.qh"
 #include "../main.qh"
-#include "../mutators/events.qh"
+#include <client/mutators/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/effects/effect.qh>
@@ -11,6 +11,8 @@
 #include <common/net_linked.qh>
 #include <common/physics/movetypes/movetypes.qh>
 
+#include <common/mutators/mutator/nades/nades.qh>
+
 #include <lib/csqcmodel/interpolate.qh>
 
 #include <lib/warpzone/anglestransform.qh>
@@ -50,8 +52,6 @@ void Projectile_DrawTrail(entity this, vector to)
        }
 }
 
-bool Projectile_isnade(int proj); // TODO: remove
-
 void Projectile_Draw(entity this)
 {
        vector rot;
index a6ae463477d51162d7364c55e35a4646d1ce20a5..eaa80d05f0a6ae2b9b6d5ebefb0c6041473b6488 100644 (file)
@@ -3,20 +3,20 @@
 #include <common/sounds/sound.qh>
 
 entityclass(Projectile);
-class(Projectile).int traileffect;
-
-class(Projectile).vector iorigin1, iorigin2;
-class(Projectile).float spawntime;
-class(Projectile).vector trail_oldorigin;
-class(Projectile).float trail_oldtime;
-class(Projectile).float fade_time, fade_rate;
-
-class(Projectile).float alphamod;
-class(Projectile).int count; // set if clientside projectile
-class(Projectile).int cnt;   // sound index
-class(Projectile).float gravity;
-class(Projectile).int snd_looping;
-class(Projectile).bool silent;
+classfield(Projectile).int traileffect;
+
+classfield(Projectile).vector iorigin1, iorigin2;
+classfield(Projectile).float spawntime;
+classfield(Projectile).vector trail_oldorigin;
+classfield(Projectile).float trail_oldtime;
+classfield(Projectile).float fade_time, fade_rate;
+
+classfield(Projectile).float alphamod;
+classfield(Projectile).int count; // set if clientside projectile
+classfield(Projectile).int cnt;   // sound index
+classfield(Projectile).float gravity;
+classfield(Projectile).int snd_looping;
+classfield(Projectile).bool silent;
 
 void SUB_Stop(entity this, entity toucher);
 
index 32dbf5208ff23a278196f70ad4d9156a1e0f9d55..9d7c68a8eea3f58bdfb771e62b0df73e34bd20c6 100644 (file)
@@ -22,7 +22,7 @@ noref float autocvar_net_connecttimeout = 30;
 
 #ifdef GAMEQC
 #include "physics/all.inc"
-#include "triggers/include.qc"
+#include "mapobjects/_mod.inc"
 #include "viewloc.qc"
 #endif
 
index d3efe77e844a498365a55ce6c264c5a554df0dd7..bc26203399bf44aace75bcff27b303f2caa738b0 100644 (file)
@@ -88,16 +88,15 @@ void CampaignFile_Unload()
 {
        if(campaign_title)
        {
-               strunzone(campaign_title);
+               strfree(campaign_title);
                for(int i = 0; i < campaign_entries; ++i)
                {
-                       strunzone(campaign_gametype[i]);
-                       strunzone(campaign_mapname[i]);
-                       strunzone(campaign_mutators[i]);
-                       strunzone(campaign_shortdesc[i]);
-                       strunzone(campaign_longdesc[i]);
+                       strfree(campaign_gametype[i]);
+                       strfree(campaign_mapname[i]);
+                       strfree(campaign_mutators[i]);
+                       strfree(campaign_shortdesc[i]);
+                       strfree(campaign_longdesc[i]);
                }
                campaign_entries = 0;
-               campaign_title = string_null;
        }
 }
index 18ea6d7d16f6204d2b3e6df82e40b851d865af53..675b75c0a4a0fc4ae21e39bc4fbbe67415e8bb3c 100644 (file)
@@ -1,6 +1,6 @@
 #pragma once
 
-const int RANKINGS_CNT = 15;
+const int RANKINGS_CNT = 99;
 
 ///////////////////////////
 // keys pressed
index 836c3983ccb0581703d2ff9a0de2df119a28a5c8..7c5a218b21f15e34ba6ba43ee0d13b4a2b0a801f 100644 (file)
@@ -56,7 +56,7 @@
        CSQCMODEL_ENDIF \
        CSQCMODEL_PROPERTY(BIT(10), float, ReadAngle, WriteAngle, v_angle_x) \
        CSQCMODEL_PROPERTY(BIT(11), int, ReadByte, WriteByte, traileffect) \
-       CSQCMODEL_PROPERTY_SCALED(BIT(12), float, ReadByte, WriteByte, scale, 16, 0, 255) \
+       CSQCMODEL_PROPERTY(BIT(12), float, ReadCoord, WriteCoord, scale) \
        CSQCMODEL_PROPERTY(BIT(13), int, ReadInt24_t, WriteInt24_t, dphitcontentsmask) \
        CSQCMODEL_PROPERTY(BIT(14), TAG_VIEWLOC_TYPE, ReadShort, WriteEntity, TAG_VIEWLOC_NAME) \
        CSQCMODEL_PROPERTY(BIT(16), int, ReadByte, WriteByte, multijump_count) \
index b489a56e4db151ffbea7f70cd7e4326a5c72a822..beb8e3e912221911705429fe210042762ed51cb0 100644 (file)
@@ -25,10 +25,10 @@ const int HITTYPE_SECONDARY = BITS(1) << 8;
 /** automatically set by RadiusDamage */
 const int HITTYPE_SPLASH = BITS(1) << 9;
 const int HITTYPE_BOUNCE = BITS(1) << 10;
+const int HITTYPE_ARMORPIERCE = BITS(1) << 11;
 // unused yet
-const int HITTYPE_RESERVED = BITS(1) << 11;
-const int HITTYPE_RESERVED2 = BITS(1) << 12;
-const int DEATH_HITTYPEMASK = HITTYPE_SECONDARY | HITTYPE_SPLASH | HITTYPE_BOUNCE | HITTYPE_RESERVED | HITTYPE_RESERVED2;
+const int HITTYPE_RESERVED = BITS(1) << 12;
+const int DEATH_HITTYPEMASK = HITTYPE_SECONDARY | HITTYPE_SPLASH | HITTYPE_BOUNCE | HITTYPE_ARMORPIERCE | HITTYPE_RESERVED;
 // normal deaths begin
 const int DT_FIRST = BIT(13);
 
index 7144bf3da5ed6bb4166c3cc5b3f8f4895d416a7f..983b073b406c8cfb93de92a31002d5dd1359fa56 100644 (file)
@@ -411,7 +411,7 @@ CLASS(DebugText3d, Object)
        }
 
        DESTRUCTOR(DebugText3d) {
-               strunzone(this.message);
+               strfree(this.message);
        }
 
        void DebugText3d_draw2d(DebugText3d this) {
@@ -459,13 +459,13 @@ NET_HANDLE(debug_text_3d, bool is_new) {
 #define debug_text_3d_5(pos, msg, align, dur, vel) debug_text_3d_fn(pos, msg, align, dur, vel)
 
 ERASEABLE
-void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector velocity) {
+void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector vel) {
        WriteHeader(MSG_BROADCAST, debug_text_3d);
        WriteVector(MSG_BROADCAST, pos);
        WriteString(MSG_BROADCAST, msg);
        WriteFloat(MSG_BROADCAST, align);
        WriteFloat(MSG_BROADCAST, duration);
-       WriteVector(MSG_BROADCAST, velocity);
+       WriteVector(MSG_BROADCAST, vel);
 }
 
 #endif // SVQC
index 252f913379a02be272548bcf60162b693e82e4be..9732be2e3bf65e82f125b176f8ed2f709d2879d6 100644 (file)
@@ -75,7 +75,7 @@ void Send_Effect_(string eff_name, vector eff_loc, vector eff_vel, int eff_cnt)
                Send_Effect(it, eff_loc, eff_vel, eff_cnt);
                return;
        });
-       // revert to engine handling
+       // revert to engine handling TODO: send the effect name and draw it on the client side? not as light on networking, but resolves the use of server side effects
        __pointparticles(_particleeffectnum(eff_name), eff_loc, eff_vel, eff_cnt);
 }
 #endif
index 56303a44ffa93f36443bf4a3131baa015f361e82..b659e8a8517a83755718d93ea06c03c9a9989db8 100644 (file)
@@ -8529,6 +8529,22 @@ SUB(arc_lightning) {
        MY(velocityjitter) = '250.0 250.0 250.0';
        MY(velocitymultiplier) = 20;
 }
+// impact smoke
+SUB(arc_lightning) {
+       MY(alpha_min) = 40;
+       MY(alpha_max) = 40;
+       MY(alpha_fade) = 350;
+       MY(color_min) = "0x80C0FF";
+       MY(color_max) = "0x80C0FF";
+       MY(countabsolute) = 1;
+       MY(sizeincrease) = 400;
+       MY(size_min) = 4;
+       MY(size_max) = 4;
+       MY(tex_min) = 38;
+       MY(tex_max) = 38;
+       MY(type) = "smoke";
+       MY(velocitymultiplier) = 100;
+}
 
 DEF(arc_beam);
 // sparks on beam
index 71260eb3d04fa49ae2ffaeaca9c5b001ec8f8070..a1b27873053917e1ba6613d9939bc36d39f0395d 100644 (file)
@@ -327,7 +327,7 @@ REGISTRY(EffectInfos, BITS(9))
 #define EffectInfos_from(i) _EffectInfos_from(i, NULL)
 REGISTER_REGISTRY(EffectInfos)
 #define EFFECTINFO(name) \
-    [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
+    ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { } \
     REGISTER(EffectInfos, EFFECTINFO, name, m_id, NEW(EffectInfoGroup)) { \
         effectinfo_##name(this, NULL); \
     }
@@ -335,8 +335,8 @@ REGISTER_REGISTRY(EffectInfos)
 #define MY(f) this.effectinfo_##f
 #define DEF(name) EFFECTINFO(name)
 #define SUB(name) \
-    [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { parent = EFFECTINFO_##name; parent.children[parent.children_count++] = this = NEW(EffectInfo, #name); } \
-    [[accumulate]] void effectinfo_##name(EffectInfoGroup parent, EffectInfo this)
+    ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this) { parent = EFFECTINFO_##name; parent.children[parent.children_count++] = this = NEW(EffectInfo, #name); } \
+    ACCUMULATE void effectinfo_##name(EffectInfoGroup parent, EffectInfo this)
 #include "effectinfo.inc"
 #undef MY
 #undef DEF
index 2abf2122c26553b86634a85eb7be3bd3ef1a5a3f..d225b337bc70bfd46d5dd55445d2ba6668b3bd7e 100644 (file)
@@ -30,10 +30,10 @@ void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float ran
 
 #ifdef CSQC
 entityclass(Casing);
-class(Casing) .float alpha;
-class(Casing) .bool silent;
-class(Casing) .int state;
-class(Casing) .float cnt;
+classfield(Casing) .float alpha;
+classfield(Casing) .bool silent;
+classfield(Casing) .int state;
+classfield(Casing) .float cnt;
 
 void Casing_Delete(entity this)
 {
index 2a1d587ca497d3ee57680684ad5c88b547568149..68b43b17608094c8cdddcd2725a3f607765940e4 100644 (file)
@@ -3,7 +3,7 @@
 #ifdef CSQC
 #include <common/deathtypes/all.qh>
 #include <common/physics/movetypes/movetypes.qh>
-#include <client/mutators/events.qh>
+#include <client/mutators/_mod.qh>
 #include <common/vehicles/all.qh>
 #include <common/weapons/_all.qh>
 #endif
index 4875a40ee98c4682b1d7cdf4f4c8818bce87ca39..8c0dfd5080312fda7d1ed4d10a66a108bdd34075 100644 (file)
                                .string fld = it.m_playersoundfld;
                                if (this.(fld))
                                {
-                                       strunzone(this.(fld));
-                                       this.(fld) = string_null;
+                                       strfree(this.(fld));
                                }
                        });
                }
                                }
                                string file = argv(1);
                                string variants = argv(2);
-                               if (this.(field)) strunzone(this.(field));
-                               this.(field) = strzone(strcat(file, " ", variants));
+                               strcpy(this.(field), strcat(file, " ", variants));
                        }
                        fclose(fh);
                        return true;
                void UpdatePlayerSounds(entity this)
                {
                        if (this.model == this.model_for_playersound && this.skin == this.skin_for_playersound) return;
-                       if (this.model_for_playersound) strunzone(this.model_for_playersound);
-                       this.model_for_playersound = strzone(this.model);
+                       strcpy(this.model_for_playersound, this.model);
                        this.skin_for_playersound = this.skin;
                        ClearPlayerSounds(this);
                        LoadPlayerSounds(this, "sound/player/default.sounds", true);
index 26b3ec9f5285744b9f21d72abd82cab86669c5c0..9849b5be73f8ebf3d1aef3ff5b1e61ec4dfea2d0 100644 (file)
@@ -80,10 +80,10 @@ void modeleffect_spawn(string m, float s, float f, vector o, vector v, vector an
 #ifdef CSQC
 
 entityclass(ModelEffect);
-class(ModelEffect) .float frame1time;
-class(ModelEffect) .float lifetime, fadetime;
-class(ModelEffect) .float teleport_time;
-class(ModelEffect) .float scale1, scale2;
+classfield(ModelEffect) .float frame1time;
+classfield(ModelEffect) .float lifetime, fadetime;
+classfield(ModelEffect) .float teleport_time;
+classfield(ModelEffect) .float scale1, scale2;
 
 .float cnt;
 .float scale;
index dd3785b68ea2cf65af3fb5ecc5c77f86c0b102e0..6eda9b15ef29d2b5c60a7b48e3651fcb5a538485 100644 (file)
@@ -3,7 +3,7 @@
 #ifdef CSQC
 
 entityclass(Rubble);
-class(Rubble).float creationtime;
+classfield(Rubble).float creationtime;
 
 IntrusiveList g_rubble;
 STATIC_INIT(g_rubble) { g_rubble = IL_NEW(); }
index 12abc21b18a255a29821912a00f8968ac1588ff9..bbca691add0423059b1e6e86ee729725776fce17 100644 (file)
@@ -1,4 +1,5 @@
 #include "ent_cs.qh"
+#include <common/gamemodes/_mod.qh>
 
 REGISTRY(EntCSProps, BITS(16) - 1)
 #define EntCSProps_from(i) _EntCSProps_from(i, NULL)
@@ -39,8 +40,7 @@ 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); \
+       strcpy(var, x); \
 MACRO_END
 
 ENTCS_PROP(ENTNUM, false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */
@@ -63,11 +63,11 @@ ENTCS_PROP(ARMOR, false, armorvalue, ENTCS_SET_NORMAL,
 
 ENTCS_PROP(NAME, true, netname, ENTCS_SET_MUTABLE_STRING,
        { WriteString(chan, ent.netname); },
-       { if (ent.netname) strunzone(ent.netname); ent.netname = strzone(ReadString()); })
+       { strcpy(ent.netname, ReadString()); })
 
 ENTCS_PROP(MODEL, true, model, ENTCS_SET_NORMAL,
        { WriteString(chan, ent.model); },
-       { if (ent.model) strunzone(ent.model); ent.model = strzone(ReadString()); })
+       { strcpy(ent.model, ReadString()); })
 
 ENTCS_PROP(SKIN, true, skin, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.skin); },
@@ -168,10 +168,8 @@ ENTCS_PROP(FRAGS, true, frags, ENTCS_SET_NORMAL,
                int n = this.sv_entnum;
                entity e = entcs_receiver(n);
                entcs_receiver(n, NULL);
-               if (e.netname) strunzone(e.netname);
-               e.netname = string_null;
-               if (e.model) strunzone(e.model);
-               e.model = string_null;
+               strfree(e.netname);
+               strfree(e.model);
                if (e != this) delete(e);
        }
 
@@ -188,8 +186,7 @@ ENTCS_PROP(FRAGS, true, frags, ENTCS_SET_NORMAL,
                // `cl_forceplayermodels 1` sounds will be wrong until the player has been in the PVS, but so be it
                if (this.model != e.model)
                {
-                       if (this.model) strunzone(this.model);
-                       this.model = strzone(e.model);
+                       strcpy(this.model, e.model);
                }
        }
 
index 2fc2c404678883117dcd9205365e36317f5e997e..c4cd002c782221fe420d38415c25fed570909a4d 100644 (file)
@@ -1,4 +1,17 @@
 // generated file; do not modify
 
+#include <common/gamemodes/gamemode/assault/_mod.inc>
+#include <common/gamemodes/gamemode/clanarena/_mod.inc>
+#include <common/gamemodes/gamemode/ctf/_mod.inc>
+#include <common/gamemodes/gamemode/cts/_mod.inc>
+#include <common/gamemodes/gamemode/deathmatch/_mod.inc>
+#include <common/gamemodes/gamemode/domination/_mod.inc>
+#include <common/gamemodes/gamemode/freezetag/_mod.inc>
+#include <common/gamemodes/gamemode/invasion/_mod.inc>
+#include <common/gamemodes/gamemode/keepaway/_mod.inc>
+#include <common/gamemodes/gamemode/keyhunt/_mod.inc>
+#include <common/gamemodes/gamemode/lms/_mod.inc>
 #include <common/gamemodes/gamemode/nexball/_mod.inc>
 #include <common/gamemodes/gamemode/onslaught/_mod.inc>
+#include <common/gamemodes/gamemode/race/_mod.inc>
+#include <common/gamemodes/gamemode/tdm/_mod.inc>
index d79957012609493478bdf9e0a03ea2116fec63c3..d7c1aa66cc35f6f3f8143031123542abf134a33c 100644 (file)
@@ -1,4 +1,17 @@
 // generated file; do not modify
 
+#include <common/gamemodes/gamemode/assault/_mod.qh>
+#include <common/gamemodes/gamemode/clanarena/_mod.qh>
+#include <common/gamemodes/gamemode/ctf/_mod.qh>
+#include <common/gamemodes/gamemode/cts/_mod.qh>
+#include <common/gamemodes/gamemode/deathmatch/_mod.qh>
+#include <common/gamemodes/gamemode/domination/_mod.qh>
+#include <common/gamemodes/gamemode/freezetag/_mod.qh>
+#include <common/gamemodes/gamemode/invasion/_mod.qh>
+#include <common/gamemodes/gamemode/keepaway/_mod.qh>
+#include <common/gamemodes/gamemode/keyhunt/_mod.qh>
+#include <common/gamemodes/gamemode/lms/_mod.qh>
 #include <common/gamemodes/gamemode/nexball/_mod.qh>
 #include <common/gamemodes/gamemode/onslaught/_mod.qh>
+#include <common/gamemodes/gamemode/race/_mod.qh>
+#include <common/gamemodes/gamemode/tdm/_mod.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/assault/_mod.inc b/qcsrc/common/gamemodes/gamemode/assault/_mod.inc
new file mode 100644 (file)
index 0000000..1deb031
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/assault/assault.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/assault/_mod.qh b/qcsrc/common/gamemodes/gamemode/assault/_mod.qh
new file mode 100644 (file)
index 0000000..38b426d
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/assault/assault.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/assault/assault.qc b/qcsrc/common/gamemodes/gamemode/assault/assault.qc
new file mode 100644 (file)
index 0000000..ba3d996
--- /dev/null
@@ -0,0 +1,628 @@
+#include "assault.qh"
+
+// TODO: split into sv_assault
+#ifdef SVQC
+.entity sprite;
+#define AS_ROUND_DELAY 5
+
+IntrusiveList g_assault_destructibles;
+IntrusiveList g_assault_objectivedecreasers;
+IntrusiveList g_assault_objectives;
+STATIC_INIT(g_assault)
+{
+       g_assault_destructibles = IL_NEW();
+       g_assault_objectivedecreasers = IL_NEW();
+       g_assault_objectives = IL_NEW();
+}
+
+// random functions
+void assault_objective_use(entity this, entity actor, entity trigger)
+{
+       // activate objective
+       this.health = 100;
+       //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
+       //print("Activator is ", actor.classname, "\n");
+
+       IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
+       {
+               target_objective_decrease_activate(it);
+       });
+}
+
+vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
+{
+       if(this.health < 0 || this.health >= ASSAULT_VALUE_INACTIVE)
+               return '-1 0 0';
+       return current;
+}
+
+// reset this objective. Used when spawning an objective
+// and when a new round starts
+void assault_objective_reset(entity this)
+{
+       this.health = ASSAULT_VALUE_INACTIVE;
+}
+
+// decrease the health of targeted objectives
+void assault_objective_decrease_use(entity this, entity actor, entity trigger)
+{
+       if(actor.team != assault_attacker_team)
+       {
+               // wrong team triggered decrease
+               return;
+       }
+
+       if(trigger.assault_sprite)
+       {
+               WaypointSprite_Disown(trigger.assault_sprite, waypointsprite_deadlifetime);
+               if(trigger.classname == "func_assault_destructible")
+                       trigger.sprite = NULL; // TODO: just unsetting it?!
+       }
+       else
+               return; // already activated! cannot activate again!
+
+       if(this.enemy.health < ASSAULT_VALUE_INACTIVE)
+       {
+               if(this.enemy.health - this.dmg > 0.5)
+               {
+                       GameRules_scoring_add_team(actor, SCORE, this.dmg);
+                       this.enemy.health = this.enemy.health - this.dmg;
+               }
+               else
+               {
+                       GameRules_scoring_add_team(actor, SCORE, this.enemy.health);
+                       GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
+                       this.enemy.health = -1;
+
+                       if(this.enemy.message)
+                               FOREACH_CLIENT(IS_PLAYER(it), { centerprint(it, this.enemy.message); });
+
+                       SUB_UseTargets(this.enemy, this, trigger);
+               }
+       }
+}
+
+void assault_setenemytoobjective(entity this)
+{
+       IL_EACH(g_assault_objectives, it.targetname == this.target,
+       {
+               if(this.enemy == NULL)
+                       this.enemy = it;
+               else
+                       objerror(this, "more than one objective as target - fix the map!");
+               break;
+       });
+
+       if(this.enemy == NULL)
+               objerror(this, "no objective as target - fix the map!");
+}
+
+bool assault_decreaser_sprite_visible(entity this, entity player, entity view)
+{
+       if(this.assault_decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
+               return false;
+
+       return true;
+}
+
+void target_objective_decrease_activate(entity this)
+{
+       entity spr;
+       this.owner = NULL;
+       FOREACH_ENTITY_STRING(target, this.targetname,
+       {
+               if(it.assault_sprite != NULL)
+               {
+                       WaypointSprite_Disown(it.assault_sprite, waypointsprite_deadlifetime);
+                       if(it.classname == "func_assault_destructible")
+                               it.sprite = NULL; // TODO: just unsetting it?!
+               }
+
+               spr = WaypointSprite_SpawnFixed(WP_AssaultDefend, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
+               spr.assault_decreaser = this;
+               spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
+               spr.classname = "sprite_waypoint";
+               WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
+               if(it.classname == "func_assault_destructible")
+               {
+                       WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
+                       WaypointSprite_UpdateMaxHealth(spr, it.max_health);
+                       WaypointSprite_UpdateHealth(spr, it.health);
+                       it.sprite = spr;
+               }
+               else
+                       WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultPush, WP_AssaultPush);
+       });
+}
+
+void target_objective_decrease_findtarget(entity this)
+{
+       assault_setenemytoobjective(this);
+}
+
+void target_assault_roundend_reset(entity this)
+{
+       //print("round end reset\n");
+       ++this.cnt; // up round counter
+       this.winning = false; // up round
+}
+
+void target_assault_roundend_use(entity this, entity actor, entity trigger)
+{
+       this.winning = 1; // round has been won by attackers
+}
+
+void assault_roundstart_use(entity this, entity actor, entity trigger)
+{
+       SUB_UseTargets(this, this, trigger);
+
+       //(Re)spawn all turrets
+       IL_EACH(g_turrets, true,
+       {
+               // Swap turret teams
+               if(it.team == NUM_TEAM_1)
+                       it.team = NUM_TEAM_2;
+               else
+                       it.team = NUM_TEAM_1;
+
+               // Doubles as teamchange
+               turret_respawn(it);
+       });
+}
+void assault_roundstart_use_this(entity this)
+{
+       assault_roundstart_use(this, NULL, NULL);
+}
+
+void assault_wall_think(entity this)
+{
+       if(this.enemy.health < 0)
+       {
+               this.model = "";
+               this.solid = SOLID_NOT;
+       }
+       else
+       {
+               this.model = this.mdl;
+               this.solid = SOLID_BSP;
+       }
+
+       this.nextthink = time + 0.2;
+}
+
+// trigger new round
+// reset objectives, toggle spawnpoints, reset triggers, ...
+void assault_new_round(entity this)
+{
+       //bprint("ASSAULT: new round\n");
+
+       // up round counter
+       this.winning = this.winning + 1;
+
+       // swap attacker/defender roles
+       if(assault_attacker_team == NUM_TEAM_1)
+               assault_attacker_team = NUM_TEAM_2;
+       else
+               assault_attacker_team = NUM_TEAM_1;
+
+       IL_EACH(g_saved_team, !IS_CLIENT(it),
+       {
+               if(it.team_saved == NUM_TEAM_1)
+                       it.team_saved = NUM_TEAM_2;
+               else if(it.team_saved == NUM_TEAM_2)
+                       it.team_saved = NUM_TEAM_1;
+       });
+
+       // reset the level with a countdown
+       cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
+       ReadyRestart_force(); // sets game_starttime
+}
+
+entity as_round;
+.entity ent_winning;
+void as_round_think()
+{
+       game_stopped = false;
+       assault_new_round(as_round.ent_winning);
+       delete(as_round);
+       as_round = NULL;
+}
+
+// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
+// they win. Otherwise the defending team wins once the timelimit passes.
+int WinningCondition_Assault()
+{
+       if(as_round)
+               return WINNING_NO;
+
+       WinningConditionHelper(NULL); // set worldstatus
+
+       int status = WINNING_NO;
+       // as the timelimit has not yet passed just assume the defending team will win
+       if(assault_attacker_team == NUM_TEAM_1)
+       {
+               SetWinners(team, NUM_TEAM_2);
+       }
+       else
+       {
+               SetWinners(team, NUM_TEAM_1);
+       }
+
+       entity ent;
+       ent = find(NULL, classname, "target_assault_roundend");
+       if(ent)
+       {
+               if(ent.winning) // round end has been triggered by attacking team
+               {
+                       bprint("Assault: round completed.\n");
+                       SetWinners(team, assault_attacker_team);
+
+                       TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
+
+                       if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round
+                       {
+                               status = WINNING_YES;
+                       }
+                       else
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
+                               as_round = new(as_round);
+                               as_round.think = as_round_think;
+                               as_round.ent_winning = ent;
+                               as_round.nextthink = time + AS_ROUND_DELAY;
+                               game_stopped = true;
+
+                               // make sure timelimit isn't hit while the game is blocked
+                               if(autocvar_timelimit > 0)
+                               if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
+                                       cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
+                       }
+               }
+       }
+
+       return status;
+}
+
+// spawnfuncs
+spawnfunc(info_player_attacker)
+{
+       if (!g_assault) { delete(this); return; }
+
+       this.team = NUM_TEAM_1; // red, gets swapped every round
+       spawnfunc_info_player_deathmatch(this);
+}
+
+spawnfunc(info_player_defender)
+{
+       if (!g_assault) { delete(this); return; }
+
+       this.team = NUM_TEAM_2; // blue, gets swapped every round
+       spawnfunc_info_player_deathmatch(this);
+}
+
+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);
+       this.spawn_evalfunc = target_objective_spawn_evalfunc;
+}
+
+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;
+
+       this.use = assault_objective_decrease_use;
+       this.health = ASSAULT_VALUE_INACTIVE;
+       this.max_health = ASSAULT_VALUE_INACTIVE;
+       this.enemy = NULL;
+
+       InitializeEntity(this, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+spawnfunc(func_breakable);
+spawnfunc(func_assault_destructible)
+{
+       if (!g_assault) { delete(this); return; }
+
+       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;
+       else
+               this.team = NUM_TEAM_1;
+
+       spawnfunc_func_breakable(this);
+}
+
+spawnfunc(func_assault_wall)
+{
+       if (!g_assault) { delete(this); return; }
+
+       this.classname = "func_assault_wall";
+       this.mdl = this.model;
+       _setmodel(this, this.mdl);
+       this.solid = SOLID_BSP;
+       setthink(this, assault_wall_think);
+       this.nextthink = time;
+       InitializeEntity(this, assault_setenemytoobjective, INITPRIO_FINDTARGET);
+}
+
+spawnfunc(target_assault_roundend)
+{
+       if (!g_assault) { delete(this); return; }
+
+       this.winning = 0; // round not yet won by attackers
+       this.classname = "target_assault_roundend";
+       this.use = target_assault_roundend_use;
+       this.cnt = 0; // first round
+       this.reset = target_assault_roundend_reset;
+}
+
+spawnfunc(target_assault_roundstart)
+{
+       if (!g_assault) { delete(this); return; }
+
+       assault_attacker_team = NUM_TEAM_1;
+       this.classname = "target_assault_roundstart";
+       this.use = assault_roundstart_use;
+       this.reset2 = assault_roundstart_use_this;
+       InitializeEntity(this, assault_roundstart_use_this, INITPRIO_FINDTARGET);
+}
+
+// legacy bot code
+void havocbot_goalrating_ast_targets(entity this, float ratingscale)
+{
+       IL_EACH(g_assault_destructibles, it.bot_attack,
+       {
+               if (it.target == "")
+                       continue;
+
+               bool found = false;
+               entity destr = it;
+               IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
+               {
+                       if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
+                       {
+                               found = true;
+                               break;
+                       }
+               });
+
+               if(!found)
+                       continue;
+
+               vector p = 0.5 * (it.absmin + it.absmax);
+
+               // Find and rate waypoints around it
+               found = false;
+               entity best = NULL;
+               float bestvalue = 99999999999;
+               entity des = it;
+               for(float radius = 0; radius < 1500 && !found; radius += 500)
+               {
+                       FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
+                       {
+                               if(checkpvs(it.origin, des))
+                               {
+                                       found = true;
+                                       if(it.cnt < bestvalue)
+                                       {
+                                               best = it;
+                                               bestvalue = it.cnt;
+                                       }
+                               }
+                       });
+               }
+
+               if(best)
+               {
+               ///     dprint("waypoints around target were found\n");
+               //      te_lightning2(NULL, '0 0 0', best.origin);
+               //      te_knightspike(best.origin);
+
+                       navigation_routerating(this, best, ratingscale, 4000);
+                       best.cnt += 1;
+
+                       this.havocbot_attack_time = 0;
+
+                       if(checkpvs(this.origin + this.view_ofs, it))
+                       if(checkpvs(this.origin + this.view_ofs, best))
+                       {
+                       //      dprint("increasing attack time for this target\n");
+                               this.havocbot_attack_time = time + 2;
+                       }
+               }
+       });
+}
+
+void havocbot_role_ast_offense(entity this)
+{
+       if(IS_DEAD(this))
+       {
+               this.havocbot_attack_time = 0;
+               havocbot_ast_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_ast_reset_role(this);
+               return;
+       }
+
+       if(this.havocbot_attack_time>time)
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
+               havocbot_goalrating_ast_targets(this, 20000);
+               havocbot_goalrating_items(this, 15000, this.origin, 10000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ast_defense(entity this)
+{
+       if(IS_DEAD(this))
+       {
+               this.havocbot_attack_time = 0;
+               havocbot_ast_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_ast_reset_role(this);
+               return;
+       }
+
+       if(this.havocbot_attack_time>time)
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 3000);
+               havocbot_goalrating_ast_targets(this, 20000);
+               havocbot_goalrating_items(this, 15000, this.origin, 10000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ast_setrole(entity this, float role)
+{
+       switch(role)
+       {
+               case HAVOCBOT_AST_ROLE_DEFENSE:
+                       this.havocbot_role = havocbot_role_ast_defense;
+                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
+                       this.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_AST_ROLE_OFFENSE:
+                       this.havocbot_role = havocbot_role_ast_offense;
+                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
+                       this.havocbot_role_timeout = 0;
+                       break;
+       }
+}
+
+void havocbot_ast_reset_role(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if(this.team == assault_attacker_team)
+               havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_OFFENSE);
+       else
+               havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_DEFENSE);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(as, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.team == assault_attacker_team)
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
+       else
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
+}
+
+MUTATOR_HOOKFUNCTION(as, TurretSpawn)
+{
+       entity turret = M_ARGV(0, entity);
+
+       if(!turret.team || turret.team == FLOAT_MAX)
+               turret.team = 5; // this gets reversed when match starts?
+}
+
+MUTATOR_HOOKFUNCTION(as, VehicleInit)
+{
+       entity veh = M_ARGV(0, entity);
+
+       veh.nextthink = time + 0.5;
+}
+
+MUTATOR_HOOKFUNCTION(as, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       havocbot_ast_reset_role(bot);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, PlayHitsound)
+{
+       entity frag_victim = M_ARGV(0, entity);
+
+       return (frag_victim.classname == "func_assault_destructible");
+}
+
+MUTATOR_HOOKFUNCTION(as, CheckAllowedTeams)
+{
+       // assault always has 2 teams
+       c1 = c2 = 0;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, CheckRules_World)
+{
+       M_ARGV(0, float) = WinningCondition_Assault();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, ReadLevelCvars)
+{
+       // incompatible
+       warmup_stage = 0;
+       sv_ready_restart_after_countdown = 0;
+}
+
+MUTATOR_HOOKFUNCTION(as, OnEntityPreSpawn)
+{
+    entity ent = M_ARGV(0, entity);
+
+       switch(ent.classname)
+       {
+               case "info_player_team1":
+               case "info_player_team2":
+               case "info_player_team3":
+               case "info_player_team4":
+                       return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
+{
+       // readyrestart not supported (yet)
+       return true;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/assault/assault.qh b/qcsrc/common/gamemodes/gamemode/assault/assault.qh
new file mode 100644 (file)
index 0000000..d949f18
--- /dev/null
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#include <common/scores.qh>
+
+const int ASSAULT_VALUE_INACTIVE = 1000;
+
+const int ST_ASSAULT_OBJECTIVES = 1;
+
+REGISTER_MUTATOR(as, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+        GameRules_teams(true);
+        int teams = BITS(2); // always red vs blue
+        GameRules_scoring(teams, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, {
+            field_team(ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+            field(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
+        });
+       }
+       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_ast_defense;
+void(entity this) havocbot_role_ast_offense;
+
+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;
+
+// predefined spawnfuncs
+void target_objective_decrease_activate(entity this);
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/clanarena/_mod.inc b/qcsrc/common/gamemodes/gamemode/clanarena/_mod.inc
new file mode 100644 (file)
index 0000000..57dc9b3
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/clanarena/clanarena.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/clanarena/_mod.qh b/qcsrc/common/gamemodes/gamemode/clanarena/_mod.qh
new file mode 100644 (file)
index 0000000..66f2374
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/clanarena/clanarena.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qc b/qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qc
new file mode 100644 (file)
index 0000000..561129c
--- /dev/null
@@ -0,0 +1,491 @@
+#include "clanarena.qh"
+
+// TODO: split into sv_clanarena
+#ifdef SVQC
+float autocvar_g_ca_damage2score_multiplier;
+bool autocvar_g_ca_spectate_enemies;
+
+void CA_count_alive_players()
+{
+       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               switch(it.team)
+               {
+                       case NUM_TEAM_1: ++total_players; if(!IS_DEAD(it)) ++redalive; break;
+                       case NUM_TEAM_2: ++total_players; if(!IS_DEAD(it)) ++bluealive; break;
+                       case NUM_TEAM_3: ++total_players; if(!IS_DEAD(it)) ++yellowalive; break;
+                       case NUM_TEAM_4: ++total_players; if(!IS_DEAD(it)) ++pinkalive; break;
+               }
+       });
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               STAT(REDALIVE, it) = redalive;
+               STAT(BLUEALIVE, it) = bluealive;
+               STAT(YELLOWALIVE, it) = yellowalive;
+               STAT(PINKALIVE, it) = pinkalive;
+       });
+}
+
+float CA_GetWinnerTeam()
+{
+       float winner_team = 0;
+       if(redalive >= 1)
+               winner_team = NUM_TEAM_1;
+       if(bluealive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no player left
+}
+
+void nades_Clear(entity player);
+
+#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
+float CA_CheckWinner()
+{
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
+
+               allowed_to_spawn = false;
+               game_stopped = true;
+               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+               return 1;
+       }
+
+       CA_count_alive_players();
+       if(CA_ALIVE_TEAMS() > 1)
+               return 0;
+
+       int winner_team = CA_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_CA_ROUNDS, +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);
+       }
+
+       allowed_to_spawn = false;
+       game_stopped = true;
+       round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+
+       FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
+
+       return 1;
+}
+
+void CA_RoundStart()
+{
+    allowed_to_spawn = boolean(warmup_stage);
+}
+
+bool CA_CheckTeams()
+{
+       static int prev_missing_teams_mask;
+       allowed_to_spawn = true;
+       CA_count_alive_players();
+       if(CA_ALIVE_TEAMS_OK())
+       {
+               if(prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               return true;
+       }
+       if(total_players == 0)
+       {
+               if(prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               return false;
+       }
+       int missing_teams_mask = 0;
+       if(ca_teams & BIT(0))
+               missing_teams_mask += (!redalive) * 1;
+       if(ca_teams & BIT(1))
+               missing_teams_mask += (!bluealive) * 2;
+       if(ca_teams & BIT(2))
+               missing_teams_mask += (!yellowalive) * 4;
+       if(ca_teams & BIT(3))
+               missing_teams_mask += (!pinkalive) * 8;
+       if(prev_missing_teams_mask != missing_teams_mask)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
+               prev_missing_teams_mask = missing_teams_mask;
+       }
+       return false;
+}
+
+bool ca_isEliminated(entity e)
+{
+       if(e.caplayer == 1 && (IS_DEAD(e) || e.frags == FRAGS_LMS_LOSER))
+               return true;
+       if(e.caplayer == 0.5)
+               return true;
+       return false;
+}
+
+/** Returns next available player to spectate if g_ca_spectate_enemies == 0 */
+entity CA_SpectateNext(entity player, entity start)
+{
+       if (SAME_TEAM(start, player)) return start;
+       // continue from current player
+       for (entity e = start; (e = find(e, classname, STR_PLAYER)); )
+       {
+               if (SAME_TEAM(player, e)) return e;
+       }
+       // restart from begining
+       for (entity e = NULL; (e = find(e, classname, STR_PLAYER)); )
+       {
+               if (SAME_TEAM(player, e)) return e;
+       }
+       return start;
+}
+
+
+MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
+{
+    entity player = M_ARGV(0, entity);
+
+       player.caplayer = 1;
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ForbidSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       // spectators / observers that weren't playing can join; they are
+       // immediately forced to observe in the PutClientInServer hook
+       // this way they are put in a team and can play in the next round
+       if (!allowed_to_spawn && player.caplayer)
+               return true;
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
+       {
+               TRANSMUTE(Observer, player);
+               if (CS(player).jointime != time && !player.caplayer) // not when connecting
+               {
+                       player.caplayer = 0.5;
+                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ca, reset_map_players)
+{
+       FOREACH_CLIENT(true, {
+               CS(it).killcount = 0;
+               if (!it.caplayer && IS_BOT_CLIENT(it))
+               {
+                       it.team = -1;
+                       it.caplayer = 1;
+               }
+               if (it.caplayer)
+               {
+                       TRANSMUTE(Player, it);
+                       it.caplayer = 1;
+                       PutClientInServer(it);
+               }
+       });
+       bot_relinkplayerlist();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ClientConnect)
+{
+    entity player = M_ARGV(0, entity);
+
+       TRANSMUTE(Observer, player);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, reset_map_global)
+{
+       allowed_to_spawn = true;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(0, float) = ca_teams;
+}
+
+entity ca_LastPlayerForTeam(entity this)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+               if (!IS_DEAD(it))
+               if (SAME_TEAM(this, it))
+               if (!last_pl)
+                       last_pl = it;
+               else
+                       return NULL;
+       });
+       return last_pl;
+}
+
+void ca_LastPlayerForTeam_Notify(entity this)
+{
+       if (round_handler_IsActive())
+       if (round_handler_IsRoundStarted())
+       {
+               entity pl = ca_LastPlayerForTeam(this);
+               if (pl)
+                       Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       ca_LastPlayerForTeam_Notify(frag_target);
+       if (!allowed_to_spawn)
+       {
+               frag_target.respawn_flags = RESPAWN_SILENT;
+               // prevent unwanted sudden rejoin as spectator and movement of spectator camera
+               frag_target.respawn_time = time + 2;
+       }
+       frag_target.respawn_flags |= RESPAWN_FORCE;
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
+       if(IS_BOT_CLIENT(frag_target))
+               bot_clear(frag_target);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
+{
+    entity player = M_ARGV(0, entity);
+
+       if (player.caplayer == 1)
+               ca_LastPlayerForTeam_Notify(player);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
+{
+    entity player = M_ARGV(0, entity);
+
+       if (!IS_DEAD(player))
+               ca_LastPlayerForTeam_Notify(player);
+       if (player.killindicator_teamchange == -2) // player wants to spectate
+               player.caplayer = 0;
+       if (player.caplayer)
+               player.frags = FRAGS_LMS_LOSER;
+       if (!warmup_stage)
+               eliminatedPlayers.SendFlags |= 1;
+       if (!player.caplayer)
+               return false;  // allow team reset
+       return true;  // prevent team reset
+}
+
+MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SetStartItems)
+{
+       start_items       &= ~IT_UNLIMITED_AMMO;
+       start_health       = warmup_start_health       = cvar("g_lms_start_health");
+       start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
+       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
+       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
+       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
+       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
+}
+
+MUTATOR_HOOKFUNCTION(ca, Damage_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);
+
+       if (IS_PLAYER(frag_target))
+       if (!IS_DEAD(frag_target))
+       if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
+               frag_damage = 0;
+
+       frag_mirrordamage = 0;
+
+       M_ARGV(4, float) = frag_damage;
+       M_ARGV(5, float) = frag_mirrordamage;
+}
+
+MUTATOR_HOOKFUNCTION(ca, FilterItem)
+{
+    entity item = M_ARGV(0, entity);
+
+       if (autocvar_g_powerups <= 0)
+       if (item.flags & FL_POWERUP)
+               return true;
+
+       if (autocvar_g_pickup_items <= 0)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_damage = M_ARGV(7, float);
+       float damage_take = M_ARGV(4, float);
+       float damage_save = M_ARGV(5, float);
+
+       float excess = max(0, frag_damage - damage_take - damage_save);
+
+       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
+               GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
+}
+
+MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
+{
+       // no respawn calculations needed, player is forced to spectate anyway
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
+{
+       // no regeneration in CA
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectateSet)
+{
+    entity client = M_ARGV(0, entity);
+    entity targ = M_ARGV(1, entity);
+
+       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+       if (DIFF_TEAM(targ, client))
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectateNext)
+{
+    entity client = M_ARGV(0, entity);
+
+       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+       {
+               entity targ = M_ARGV(1, entity);
+               M_ARGV(1, entity) = CA_SpectateNext(client, targ);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
+{
+    entity client = M_ARGV(0, entity);
+    entity targ = M_ARGV(1, entity);
+    entity first = M_ARGV(2, entity);
+
+       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+       {
+               do { targ = targ.chain; }
+               while(targ && DIFF_TEAM(targ, client));
+
+               if (!targ)
+               {
+                       for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain);
+
+                       if (targ == client.enemy)
+                               return MUT_SPECPREV_RETURN;
+               }
+       }
+
+       M_ARGV(1, entity) = targ;
+
+       return MUT_SPECPREV_FOUND;
+}
+
+MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
+{
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               if (IS_PLAYER(it) || it.caplayer == 1)
+                       ++M_ARGV(0, int);
+               ++M_ARGV(1, int);
+       });
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
+{
+    entity player = M_ARGV(0, entity);
+
+       if (player.caplayer)
+       {
+               // they're going to spec, we can do other checks
+               if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
+                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
+               return MUT_SPECCMD_FORCE;
+       }
+
+       return MUT_SPECCMD_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(ca, WantWeapon)
+{
+       M_ARGV(2, bool) = true; // all weapons
+}
+
+MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
+{
+       return true; // doesn't work well with the whole spectator as player thing
+}
+
+MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus)
+{
+       entity player = M_ARGV(0, entity);
+
+       return player.caplayer == 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
+{
+       // most weapons arena
+       if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qh b/qcsrc/common/gamemodes/gamemode/clanarena/clanarena.qh
new file mode 100644 (file)
index 0000000..8a94acd
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#include <server/round_handler.qh>
+#include <server/miscfunctions.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);
+
+REGISTER_MUTATOR(ca, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_ca_team_spawns);
+        GameRules_limit_score(autocvar_g_ca_point_limit);
+        GameRules_limit_lead(autocvar_g_ca_point_leadlimit);
+
+               ca_teams = autocvar_g_ca_teams_override;
+               if (ca_teams < 2)
+                       ca_teams = cvar("g_ca_teams"); // read the cvar directly as it gets written earlier in the same frame
+
+               ca_teams = BITS(bound(2, ca_teams, 4));
+        GameRules_scoring(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, {
+            field_team(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
+        });
+
+               allowed_to_spawn = true;
+               round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
+               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
+               EliminatedPlayers_Init(ca_isEliminated);
+       }
+       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
diff --git a/qcsrc/common/gamemodes/gamemode/ctf/_mod.inc b/qcsrc/common/gamemodes/gamemode/ctf/_mod.inc
new file mode 100644 (file)
index 0000000..dcd8135
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/ctf/ctf.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/ctf/_mod.qh b/qcsrc/common/gamemodes/gamemode/ctf/_mod.qh
new file mode 100644 (file)
index 0000000..c1ddd97
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/ctf/ctf.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/ctf/ctf.qc b/qcsrc/common/gamemodes/gamemode/ctf/ctf.qc
new file mode 100644 (file)
index 0000000..c7ade84
--- /dev/null
@@ -0,0 +1,2779 @@
+#include "ctf.qh"
+
+// TODO: split into sv_ctf
+#ifdef SVQC
+#include <common/effects/all.qh>
+#include <common/vehicles/all.qh>
+#include <server/teamplay.qh>
+
+#include <lib/warpzone/common.qh>
+
+bool autocvar_g_ctf_allow_vehicle_carry;
+bool autocvar_g_ctf_allow_vehicle_touch;
+bool autocvar_g_ctf_allow_monster_touch;
+bool autocvar_g_ctf_throw;
+float autocvar_g_ctf_throw_angle_max;
+float autocvar_g_ctf_throw_angle_min;
+int autocvar_g_ctf_throw_punish_count;
+float autocvar_g_ctf_throw_punish_delay;
+float autocvar_g_ctf_throw_punish_time;
+float autocvar_g_ctf_throw_strengthmultiplier;
+float autocvar_g_ctf_throw_velocity_forward;
+float autocvar_g_ctf_throw_velocity_up;
+float autocvar_g_ctf_drop_velocity_up;
+float autocvar_g_ctf_drop_velocity_side;
+bool autocvar_g_ctf_oneflag_reverse;
+bool autocvar_g_ctf_portalteleport;
+bool autocvar_g_ctf_pass;
+float autocvar_g_ctf_pass_arc;
+float autocvar_g_ctf_pass_arc_max;
+float autocvar_g_ctf_pass_directional_max;
+float autocvar_g_ctf_pass_directional_min;
+float autocvar_g_ctf_pass_radius;
+float autocvar_g_ctf_pass_wait;
+bool autocvar_g_ctf_pass_request;
+float autocvar_g_ctf_pass_turnrate;
+float autocvar_g_ctf_pass_timelimit;
+float autocvar_g_ctf_pass_velocity;
+bool autocvar_g_ctf_dynamiclights;
+float autocvar_g_ctf_flag_collect_delay;
+float autocvar_g_ctf_flag_damageforcescale;
+bool autocvar_g_ctf_flag_dropped_waypoint;
+bool autocvar_g_ctf_flag_dropped_floatinwater;
+bool autocvar_g_ctf_flag_glowtrails;
+int autocvar_g_ctf_flag_health;
+bool autocvar_g_ctf_flag_return;
+bool autocvar_g_ctf_flag_return_carrying;
+float autocvar_g_ctf_flag_return_carried_radius;
+float autocvar_g_ctf_flag_return_time;
+bool autocvar_g_ctf_flag_return_when_unreachable;
+float autocvar_g_ctf_flag_return_damage;
+float autocvar_g_ctf_flag_return_damage_delay;
+float autocvar_g_ctf_flag_return_dropped;
+float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
+float autocvar_g_ctf_flagcarrier_auto_helpme_time;
+float autocvar_g_ctf_flagcarrier_selfdamagefactor;
+float autocvar_g_ctf_flagcarrier_selfforcefactor;
+float autocvar_g_ctf_flagcarrier_damagefactor;
+float autocvar_g_ctf_flagcarrier_forcefactor;
+//float autocvar_g_ctf_flagcarrier_waypointforenemy_spotting;
+bool autocvar_g_ctf_fullbrightflags;
+bool autocvar_g_ctf_ignore_frags;
+bool autocvar_g_ctf_score_ignore_fields;
+int autocvar_g_ctf_score_capture;
+int autocvar_g_ctf_score_capture_assist;
+int autocvar_g_ctf_score_kill;
+int autocvar_g_ctf_score_penalty_drop;
+int autocvar_g_ctf_score_penalty_returned;
+int autocvar_g_ctf_score_pickup_base;
+int autocvar_g_ctf_score_pickup_dropped_early;
+int autocvar_g_ctf_score_pickup_dropped_late;
+int autocvar_g_ctf_score_return;
+float autocvar_g_ctf_shield_force;
+float autocvar_g_ctf_shield_max_ratio;
+int autocvar_g_ctf_shield_min_negscore;
+bool autocvar_g_ctf_stalemate;
+int autocvar_g_ctf_stalemate_endcondition;
+float autocvar_g_ctf_stalemate_time;
+bool autocvar_g_ctf_reverse;
+float autocvar_g_ctf_dropped_capture_delay;
+float autocvar_g_ctf_dropped_capture_radius;
+
+void ctf_FakeTimeLimit(entity e, float t)
+{
+       msg_entity = e;
+       WriteByte(MSG_ONE, 3); // svc_updatestat
+       WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
+       if(t < 0)
+               WriteCoord(MSG_ONE, autocvar_timelimit);
+       else
+               WriteCoord(MSG_ONE, (t + 1) / 60);
+}
+
+void ctf_EventLog(string mode, int flagteam, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(sprintf(":ctf:%s:%d:%d:%s", mode, flagteam, actor.team, ((actor != NULL) ? ftos(actor.playerid) : "")));
+               //GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+void ctf_CaptureRecord(entity flag, entity player)
+{
+       float cap_record = ctf_captimerecord;
+       float cap_time = (time - flag.ctf_pickuptime);
+       string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
+
+       // notify about shit
+       if(ctf_oneflag)
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname);
+       else if(!ctf_captimerecord)
+               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, TIME_ENCODE(cap_time));
+       else if(cap_time < cap_record)
+               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
+       else
+               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
+
+       // write that shit in the database
+       if(!ctf_oneflag) // but not in 1-flag mode
+       if((!ctf_captimerecord) || (cap_time < cap_record))
+       {
+               ctf_captimerecord = cap_time;
+               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
+               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
+               write_recordmarker(player, flag.ctf_pickuptime, cap_time);
+       }
+
+       if(autocvar_g_ctf_leaderboard && !ctf_oneflag)
+               race_setTime(GetMapname(), TIME_ENCODE(cap_time), player.crypto_idfp, player.netname, player, false);
+}
+
+bool ctf_Immediate_Return_Allowed(entity flag, entity toucher)
+{
+       int num_perteam = 0;
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), { ++num_perteam; });
+
+       // automatically return if there's only 1 player on the team
+       return ((autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried))
+               && flag.team);
+}
+
+bool ctf_Return_Customize(entity this, entity client)
+{
+       // only to the carrier
+       return boolean(client == this.owner);
+}
+
+void ctf_FlagcarrierWaypoints(entity player)
+{
+       WaypointSprite_Spawn(WP_FlagCarrier, 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_flagcarrier, true, RADARICON_FLAG);
+       WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
+       WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+       WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
+
+       if(player.flagcarried && CTF_SAMETEAM(player, player.flagcarried))
+       {
+               if(!player.wps_enemyflagcarrier)
+               {
+                       entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, 0, player, wps_enemyflagcarrier, true, RADARICON_FLAG);
+                       wp.colormod = WPCOLOR_ENEMYFC(player.team);
+                       setcefc(wp, ctf_Stalemate_Customize);
+
+                       if(IS_REAL_CLIENT(player) && !ctf_stalemate)
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_VISIBLE);
+               }
+
+               if(!player.wps_flagreturn)
+               {
+                       entity owp = WaypointSprite_SpawnFixed(WP_FlagReturn, player.flagcarried.ctf_spawnorigin + FLAG_WAYPOINT_OFFSET, player, wps_flagreturn, RADARICON_FLAG);
+                       owp.colormod = '0 0.8 0.8';
+                       //WaypointSprite_UpdateTeamRadar(player.wps_flagreturn, RADARICON_FLAG, ((player.team) ? colormapPaletteColor(player.team - 1, false) : '1 1 1'));
+                       setcefc(owp, ctf_Return_Customize);
+               }
+       }
+}
+
+void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
+{
+       float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
+       float initial_height = min(autocvar_g_ctf_pass_arc_max, (flag.pass_distance * tanh(autocvar_g_ctf_pass_arc)));
+       float current_height = (initial_height * min(1, (current_distance / flag.pass_distance)));
+       //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
+
+       vector targpos;
+       if(current_height) // make sure we can actually do this arcing path
+       {
+               targpos = (to + ('0 0 1' * current_height));
+               WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+               if(trace_fraction < 1)
+               {
+                       //print("normal arc line failed, trying to find new pos...");
+                       WarpZone_TraceLine(to, targpos, MOVE_NOMONSTERS, flag);
+                       targpos = (trace_endpos + FLAG_PASS_ARC_OFFSET);
+                       WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+                       if(trace_fraction < 1) { targpos = to; /* print(" ^1FAILURE^7, reverting to original direction.\n"); */ }
+                       /*else { print(" ^3SUCCESS^7, using new arc line.\n"); } */
+               }
+       }
+       else { targpos = to; }
+
+       //flag.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
+
+       vector desired_direction = normalize(targpos - from);
+       if(turnrate) { flag.velocity = (normalize(normalize(flag.velocity) + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); }
+       else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
+}
+
+bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
+{
+       if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
+       {
+               // directional tracing only
+               float spreadlimit;
+               makevectors(passer_angle);
+
+               // find the closest point on the enemy to the center of the attack
+               float h; // hypotenuse, which is the distance between attacker to head
+               float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
+
+               h = vlen(head_center - passer_center);
+               a = h * (normalize(head_center - passer_center) * v_forward);
+
+               vector nearest_on_line = (passer_center + a * v_forward);
+               float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
+
+               spreadlimit = (autocvar_g_ctf_pass_radius ? min(1, (vlen(passer_center - nearest_on_line) / autocvar_g_ctf_pass_radius)) : 1);
+               spreadlimit = (autocvar_g_ctf_pass_directional_min * (1 - spreadlimit) + autocvar_g_ctf_pass_directional_max * spreadlimit);
+
+               if(spreadlimit && (distance_from_line <= spreadlimit) && ((vlen(normalize(head_center - passer_center) - v_forward) * RAD2DEG) <= 90))
+                       { return true; }
+               else
+                       { return false; }
+       }
+       else { return true; }
+}
+
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+bool ctf_CaptureShield_CheckStatus(entity p)
+{
+       int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
+       int players_worseeq, players_total;
+
+       if(ctf_captureshield_max_ratio <= 0)
+               return false;
+
+       s  = GameRules_scoring_add(p, CTF_CAPS, 0);
+       s2 = GameRules_scoring_add(p, CTF_PICKUPS, 0);
+       s3 = GameRules_scoring_add(p, CTF_RETURNS, 0);
+       s4 = GameRules_scoring_add(p, CTF_FCKILLS, 0);
+
+       sr = ((s - s2) + (s3 + s4));
+
+       if(sr >= -ctf_captureshield_min_negscore)
+               return false;
+
+       players_total = players_worseeq = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               if(DIFF_TEAM(it, p))
+                       continue;
+               se  = GameRules_scoring_add(it, CTF_CAPS, 0);
+               se2 = GameRules_scoring_add(it, CTF_PICKUPS, 0);
+               se3 = GameRules_scoring_add(it, CTF_RETURNS, 0);
+               se4 = GameRules_scoring_add(it, CTF_FCKILLS, 0);
+
+               ser = ((se - se2) + (se3 + se4));
+
+               if(ser <= sr)
+                       ++players_worseeq;
+               ++players_total;
+       });
+
+       // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
+       // use this rule here
+
+       if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
+               return false;
+
+       return true;
+}
+
+void ctf_CaptureShield_Update(entity player, bool wanted_status)
+{
+       bool updated_status = ctf_CaptureShield_CheckStatus(player);
+       if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
+       {
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
+               player.ctf_captureshielded = updated_status;
+       }
+}
+
+bool ctf_CaptureShield_Customize(entity this, entity client)
+{
+       if(!client.ctf_captureshielded) { return false; }
+       if(CTF_SAMETEAM(this, client)) { return false; }
+
+       return true;
+}
+
+void ctf_CaptureShield_Touch(entity this, entity toucher)
+{
+       if(!toucher.ctf_captureshielded) { return; }
+       if(CTF_SAMETEAM(this, toucher)) { 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, DMG_NOWEP, mymid, normalize(theirmid - mymid) * ctf_captureshield_force);
+       if(IS_REAL_CLIENT(toucher)) { Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
+}
+
+void ctf_CaptureShield_Spawn(entity flag)
+{
+       entity shield = new(ctf_captureshield);
+
+       shield.enemy = flag;
+       shield.team = flag.team;
+       settouch(shield, ctf_CaptureShield_Touch);
+       setcefc(shield, ctf_CaptureShield_Customize);
+       shield.effects = EF_ADDITIVE;
+       set_movetype(shield, MOVETYPE_NOCLIP);
+       shield.solid = SOLID_TRIGGER;
+       shield.avelocity = '7 0 11';
+       shield.scale = 0.5;
+
+       setorigin(shield, flag.origin);
+       setmodel(shield, MDL_CTF_SHIELD);
+       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
+}
+
+
+// ====================
+// Drop/Pass/Throw Code
+// ====================
+
+void ctf_Handle_Drop(entity flag, entity player, int droptype)
+{
+       // declarations
+       player = (player ? player : flag.pass_sender);
+
+       // main
+       set_movetype(flag, MOVETYPE_TOSS);
+       flag.takedamage = DAMAGE_YES;
+       flag.angles = '0 0 0';
+       flag.health = flag.max_flag_health;
+       flag.ctf_droptime = time;
+       flag.ctf_dropper = player;
+       flag.ctf_status = FLAG_DROPPED;
+
+       // messages and sounds
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname);
+       _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
+       ctf_EventLog("dropped", player.team, player);
+
+       // scoring
+       GameRules_scoring_add_team(player, SCORE, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
+       GameRules_scoring_add(player, CTF_DROPS, 1);
+
+       // waypoints
+       if(autocvar_g_ctf_flag_dropped_waypoint) {
+               entity wp = WaypointSprite_Spawn(WP_FlagDropped, 0, 0, flag, FLAG_WAYPOINT_OFFSET, NULL, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG);
+               wp.colormod = WPCOLOR_DROPPEDFLAG(flag.team);
+       }
+
+       if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
+       {
+               WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
+               WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
+       }
+
+       player.throw_antispam = time + autocvar_g_ctf_pass_wait;
+
+       if(droptype == DROP_PASS)
+       {
+               flag.pass_distance = 0;
+               flag.pass_sender = NULL;
+               flag.pass_target = NULL;
+       }
+}
+
+void ctf_Handle_Retrieve(entity flag, entity player)
+{
+       entity sender = flag.pass_sender;
+
+       // transfer flag to player
+       flag.owner = player;
+       flag.owner.flagcarried = flag;
+       GameRules_scoring_vip(player, true);
+
+       // reset flag
+       if(player.vehicle)
+       {
+               setattachment(flag, player.vehicle, "");
+               setorigin(flag, VEHICLE_FLAG_OFFSET);
+               flag.scale = VEHICLE_FLAG_SCALE;
+       }
+       else
+       {
+               setattachment(flag, player, "");
+               setorigin(flag, FLAG_CARRY_OFFSET);
+       }
+       set_movetype(flag, MOVETYPE_NONE);
+       flag.takedamage = DAMAGE_NO;
+       flag.solid = SOLID_NOT;
+       flag.angles = '0 0 0';
+       flag.ctf_status = FLAG_CARRY;
+
+       // messages and sounds
+       _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
+       ctf_EventLog("receive", flag.team, player);
+
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
+               if(it == sender)
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
+               else if(it == player)
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
+               else if(SAME_TEAM(it, sender))
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
+       });
+
+       // create new waypoint
+       ctf_FlagcarrierWaypoints(player);
+
+       sender.throw_antispam = time + autocvar_g_ctf_pass_wait;
+       player.throw_antispam = sender.throw_antispam;
+
+       flag.pass_distance = 0;
+       flag.pass_sender = NULL;
+       flag.pass_target = NULL;
+}
+
+void ctf_Handle_Throw(entity player, entity receiver, int droptype)
+{
+       entity flag = player.flagcarried;
+       vector targ_origin, flag_velocity;
+
+       if(!flag) { return; }
+       if((droptype == DROP_PASS) && !receiver) { return; }
+
+       if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
+
+       // reset the flag
+       setattachment(flag, NULL, "");
+       setorigin(flag, player.origin + FLAG_DROP_OFFSET);
+       flag.owner.flagcarried = NULL;
+       GameRules_scoring_vip(flag.owner, false);
+       flag.owner = NULL;
+       flag.solid = SOLID_TRIGGER;
+       flag.ctf_dropper = player;
+       flag.ctf_droptime = time;
+       navigation_dynamicgoal_set(flag);
+
+       flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
+
+       switch(droptype)
+       {
+               case DROP_PASS:
+               {
+                       // warpzone support:
+                       // for the examples, we assume player -> wz1 -> ... -> wzn -> receiver
+                       // findradius has already put wzn ... wz1 into receiver's warpzone parameters!
+                       WarpZone_RefSys_Copy(flag, receiver);
+                       WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
+                       targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
+
+                       flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' *  player.origin.x) + ('0 1 0' *  player.origin.y))); // for the sake of this check, exclude Z axis
+                       ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
+
+                       // main
+                       set_movetype(flag, MOVETYPE_FLY);
+                       flag.takedamage = DAMAGE_NO;
+                       flag.pass_sender = player;
+                       flag.pass_target = receiver;
+                       flag.ctf_status = FLAG_PASSING;
+
+                       // other
+                       _sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+                       WarpZone_TrailParticles(NULL, _particleeffectnum(flag.passeffect), player.origin, targ_origin);
+                       ctf_EventLog("pass", flag.team, player);
+                       break;
+               }
+
+               case DROP_THROW:
+               {
+                       makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
+
+                       flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
+                       flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
+                       ctf_Handle_Drop(flag, player, droptype);
+                       break;
+               }
+
+               case DROP_RESET:
+               {
+                       flag.velocity = '0 0 0'; // do nothing
+                       break;
+               }
+
+               default:
+               case DROP_NORMAL:
+               {
+                       flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
+                       ctf_Handle_Drop(flag, player, droptype);
+                       break;
+               }
+       }
+
+       // kill old waypointsprite
+       WaypointSprite_Ping(player.wps_flagcarrier);
+       WaypointSprite_Kill(player.wps_flagcarrier);
+
+       if(player.wps_enemyflagcarrier)
+               WaypointSprite_Kill(player.wps_enemyflagcarrier);
+
+       if(player.wps_flagreturn)
+               WaypointSprite_Kill(player.wps_flagreturn);
+
+       // captureshield
+       ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
+}
+
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
+{
+       return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
+}
+
+// ==============
+// Event Handlers
+// ==============
+
+void nades_GiveBonus(entity player, float score);
+
+void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
+{
+       entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
+       entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
+       entity player_team_flag = NULL, tmp_entity;
+       float old_time, new_time;
+
+       if(!player) { return; } // without someone to give the reward to, we can't possibly cap
+       if(CTF_DIFFTEAM(player, flag)) { return; }
+       if((flag.cnt || enemy_flag.cnt) && flag.cnt != enemy_flag.cnt) { return; } // this should catch some edge cases (capturing grouped flag at ungrouped flag disallowed etc)
+
+       if (toucher.goalentity == flag.bot_basewaypoint)
+               toucher.goalentity_lock_timeout = 0;
+
+       if(ctf_oneflag)
+       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+       if(SAME_TEAM(tmp_entity, player))
+       {
+               player_team_flag = tmp_entity;
+               break;
+       }
+
+       nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
+
+       player.throw_prevtime = time;
+       player.throw_count = 0;
+
+       // messages and sounds
+       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE));
+       ctf_CaptureRecord(enemy_flag, player);
+       _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
+
+       switch(capturetype)
+       {
+               case CAPTURE_NORMAL: ctf_EventLog("capture", enemy_flag.team, player); break;
+               case CAPTURE_DROPPED: ctf_EventLog("droppedcapture", enemy_flag.team, player); break;
+               default: break;
+       }
+
+       // scoring
+       float pscore = 0;
+       if(enemy_flag.score_capture || flag.score_capture)
+               pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5);
+       GameRules_scoring_add_team(player, SCORE, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
+       float capscore = 0;
+       if(enemy_flag.score_team_capture || flag.score_team_capture)
+               capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5);
+       GameRules_scoring_add_team(player, CTF_CAPS, ((capscore) ? capscore : 1));
+
+       old_time = GameRules_scoring_add(player, CTF_CAPTIME, 0);
+       new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
+       if(!old_time || new_time < old_time)
+               GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
+
+       // effects
+       Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
+       //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
+
+       // other
+       if(capturetype == CAPTURE_NORMAL)
+       {
+               WaypointSprite_Kill(player.wps_flagcarrier);
+               if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
+
+               if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
+                       { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
+       }
+
+       flag.enemy = toucher;
+
+       // reset the flag
+       player.next_take_time = time + autocvar_g_ctf_flag_collect_delay;
+       ctf_RespawnFlag(enemy_flag);
+}
+
+void ctf_Handle_Return(entity flag, entity player)
+{
+       // messages and sounds
+       if(IS_MONSTER(player))
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name);
+       }
+       else if(flag.team)
+       {
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
+       }
+       _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
+       ctf_EventLog("return", flag.team, player);
+
+       // scoring
+       if(IS_PLAYER(player))
+       {
+               GameRules_scoring_add_team(player, SCORE, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
+               GameRules_scoring_add(player, CTF_RETURNS, 1); // add to count of returns
+
+               nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
+       }
+
+       TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
+
+       if(flag.ctf_dropper)
+       {
+               GameRules_scoring_add(flag.ctf_dropper, SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
+               ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag
+               flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
+       }
+
+       // other
+       if(player.flagcarried == flag)
+               WaypointSprite_Kill(player.wps_flagcarrier);
+
+       flag.enemy = player;
+
+       // reset the flag
+       ctf_RespawnFlag(flag);
+}
+
+void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
+{
+       // declarations
+       float pickup_dropped_score; // used to calculate dropped pickup score
+
+       // attach the flag to the player
+       flag.owner = player;
+       player.flagcarried = flag;
+       GameRules_scoring_vip(player, true);
+       if(player.vehicle)
+       {
+               setattachment(flag, player.vehicle, "");
+               setorigin(flag, VEHICLE_FLAG_OFFSET);
+               flag.scale = VEHICLE_FLAG_SCALE;
+       }
+       else
+       {
+               setattachment(flag, player, "");
+               setorigin(flag, FLAG_CARRY_OFFSET);
+       }
+
+       // flag setup
+       set_movetype(flag, MOVETYPE_NONE);
+       flag.takedamage = DAMAGE_NO;
+       flag.solid = SOLID_NOT;
+       flag.angles = '0 0 0';
+       flag.ctf_status = FLAG_CARRY;
+
+       switch(pickuptype)
+       {
+               case PICKUP_BASE: flag.ctf_pickuptime = time; break; // used for timing runs
+               case PICKUP_DROPPED: flag.health = flag.max_flag_health; break; // reset health/return timelimit
+               default: break;
+       }
+
+       // messages and sounds
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
+       if(ctf_stalemate)
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
+       if(!flag.team)
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
+       else if(CTF_DIFFTEAM(player, flag))
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
+       else
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
+
+       Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+
+       if(!flag.team)
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
+
+       if(flag.team)
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
+                       if(CTF_SAMETEAM(flag, it))
+                       if(SAME_TEAM(player, it))
+                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+                       else
+                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+               });
+
+       _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
+
+       // scoring
+       GameRules_scoring_add(player, CTF_PICKUPS, 1);
+       nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
+       switch(pickuptype)
+       {
+               case PICKUP_BASE:
+               {
+                       GameRules_scoring_add_team(player, SCORE, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
+                       ctf_EventLog("steal", flag.team, player);
+                       break;
+               }
+
+               case PICKUP_DROPPED:
+               {
+                       pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
+                       pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
+                       LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
+                       GameRules_scoring_add_team(player, SCORE, pickup_dropped_score);
+                       ctf_EventLog("pickup", flag.team, player);
+                       break;
+               }
+
+               default: break;
+       }
+
+       // speedrunning
+       if(pickuptype == PICKUP_BASE)
+       {
+               flag.speedrunning = player.speedrunning; // if speedrunning, flag will flag-return and teleport the owner back after the record
+               if((player.speedrunning) && (ctf_captimerecord))
+                       ctf_FakeTimeLimit(player, time + ctf_captimerecord);
+       }
+
+       // effects
+       Send_Effect_(flag.toucheffect, player.origin, '0 0 0', 1);
+
+       // waypoints
+       if(pickuptype == PICKUP_DROPPED) { WaypointSprite_Kill(flag.wps_flagdropped); }
+       ctf_FlagcarrierWaypoints(player);
+       WaypointSprite_Ping(player.wps_flagcarrier);
+}
+
+
+// ===================
+// Main Flag Functions
+// ===================
+
+void ctf_CheckFlagReturn(entity flag, int returntype)
+{
+       if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
+       {
+               if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
+
+               if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
+               {
+                       switch(returntype)
+                       {
+                               case RETURN_DROPPED:
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break;
+                               case RETURN_DAMAGE:
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
+                               case RETURN_SPEEDRUN:
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), TIME_ENCODE(ctf_captimerecord)); break;
+                               case RETURN_NEEDKILL:
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
+                               default:
+                               case RETURN_TIMEOUT:
+                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break;
+                       }
+                       _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
+                       ctf_EventLog("returned", flag.team, NULL);
+                       flag.enemy = NULL;
+                       ctf_RespawnFlag(flag);
+               }
+       }
+}
+
+bool ctf_Stalemate_Customize(entity this, entity client)
+{
+       // make spectators see what the player would see
+       entity e = WaypointSprite_getviewentity(client);
+       entity wp_owner = this.owner;
+
+       // team waypoints
+       //if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
+       if(SAME_TEAM(wp_owner, e)) { return false; }
+       if(!IS_PLAYER(e)) { return false; }
+
+       return true;
+}
+
+void ctf_CheckStalemate()
+{
+       // declarations
+       int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
+       entity tmp_entity;
+
+       entity ctf_staleflaglist = NULL; // reset the list, we need to build the list each time this function runs
+
+       // build list of stale flags
+       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+       {
+               if(autocvar_g_ctf_stalemate)
+               if(tmp_entity.ctf_status != FLAG_BASE)
+               if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time || !tmp_entity.team) // instant stalemate in oneflag
+               {
+                       tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist
+                       ctf_staleflaglist = tmp_entity;
+
+                       switch(tmp_entity.team)
+                       {
+                               case NUM_TEAM_1: ++stale_red_flags; break;
+                               case NUM_TEAM_2: ++stale_blue_flags; break;
+                               case NUM_TEAM_3: ++stale_yellow_flags; break;
+                               case NUM_TEAM_4: ++stale_pink_flags; break;
+                               default: ++stale_neutral_flags; break;
+                       }
+               }
+       }
+
+       if(ctf_oneflag)
+               stale_flags = (stale_neutral_flags >= 1);
+       else
+               stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
+
+       if(ctf_oneflag && stale_flags == 1)
+               ctf_stalemate = true;
+       else if(stale_flags >= 2)
+               ctf_stalemate = true;
+       else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
+               { ctf_stalemate = false; wpforenemy_announced = false; }
+       else if(stale_flags < 2 && autocvar_g_ctf_stalemate_endcondition == 1)
+               { ctf_stalemate = false; wpforenemy_announced = false; }
+
+       // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
+       if(ctf_stalemate)
+       {
+               for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
+               {
+                       if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
+                       {
+                               entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, NULL, 0, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG);
+                               wp.colormod = WPCOLOR_ENEMYFC(tmp_entity.owner.team);
+                               setcefc(tmp_entity.owner.wps_enemyflagcarrier, ctf_Stalemate_Customize);
+                       }
+               }
+
+               if (!wpforenemy_announced)
+               {
+                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); });
+
+                       wpforenemy_announced = true;
+               }
+       }
+}
+
+void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               if(autocvar_g_ctf_flag_return_damage_delay)
+                       this.ctf_flagdamaged_byworld = true;
+               else
+               {
+                       this.health = 0;
+                       ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
+               }
+               return;
+       }
+       if(autocvar_g_ctf_flag_return_damage)
+       {
+               // reduce health and check if it should be returned
+               this.health = this.health - damage;
+               ctf_CheckFlagReturn(this, RETURN_DAMAGE);
+               return;
+       }
+}
+
+void ctf_FlagThink(entity this)
+{
+       // declarations
+       entity tmp_entity;
+
+       this.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
+
+       // captureshield
+       if(this == ctf_worldflaglist) // only for the first flag
+               FOREACH_CLIENT(true, { ctf_CaptureShield_Update(it, 1); }); // release shield only
+
+       // sanity checks
+       if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
+               LOG_TRACE("wtf the flag got squashed?");
+               tracebox(this.origin, this.m_mins, this.m_maxs, this.origin, MOVE_NOMONSTERS, this);
+               if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
+                       setsize(this, this.m_mins, this.m_maxs);
+       }
+
+       // main think method
+       switch(this.ctf_status)
+       {
+               case FLAG_BASE:
+               {
+                       if(autocvar_g_ctf_dropped_capture_radius)
+                       {
+                               for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+                                       if(tmp_entity.ctf_status == FLAG_DROPPED)
+                                       if(vdist(this.origin - tmp_entity.origin, <, autocvar_g_ctf_dropped_capture_radius))
+                                       if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
+                                               ctf_Handle_Capture(this, tmp_entity, CAPTURE_DROPPED);
+                       }
+                       return;
+               }
+
+               case FLAG_DROPPED:
+               {
+                       this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
+
+                       if(autocvar_g_ctf_flag_dropped_floatinwater)
+                       {
+                               vector midpoint = ((this.absmin + this.absmax) * 0.5);
+                               if(pointcontents(midpoint) == CONTENT_WATER)
+                               {
+                                       this.velocity = this.velocity * 0.5;
+
+                                       if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
+                                               { this.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
+                                       else
+                                               { set_movetype(this, MOVETYPE_FLY); }
+                               }
+                               else if(this.move_movetype == MOVETYPE_FLY) { set_movetype(this, MOVETYPE_TOSS); }
+                       }
+                       if(autocvar_g_ctf_flag_return_dropped)
+                       {
+                               if((vdist(this.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_dropped)) || (autocvar_g_ctf_flag_return_dropped == -1))
+                               {
+                                       this.health = 0;
+                                       ctf_CheckFlagReturn(this, RETURN_DROPPED);
+                                       return;
+                               }
+                       }
+                       if(this.ctf_flagdamaged_byworld)
+                       {
+                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
+                               ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
+                               return;
+                       }
+                       else if(autocvar_g_ctf_flag_return_time)
+                       {
+                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
+                               ctf_CheckFlagReturn(this, RETURN_TIMEOUT);
+                               return;
+                       }
+                       return;
+               }
+
+               case FLAG_CARRY:
+               {
+                       if(this.speedrunning && ctf_captimerecord && (time >= this.ctf_pickuptime + ctf_captimerecord))
+                       {
+                               this.health = 0;
+                               ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
+
+                               CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
+                               ImpulseCommands(this.owner);
+                       }
+                       if(autocvar_g_ctf_stalemate)
+                       {
+                               if(time >= wpforenemy_nextthink)
+                               {
+                                       ctf_CheckStalemate();
+                                       wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
+                               }
+                       }
+                       if(CTF_SAMETEAM(this, this.owner) && this.team)
+                       {
+                               if(autocvar_g_ctf_flag_return) // drop the flag if reverse status has changed
+                                       ctf_Handle_Throw(this.owner, NULL, DROP_THROW);
+                               else if(vdist(this.owner.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_carried_radius))
+                                       ctf_Handle_Return(this, this.owner);
+                       }
+                       return;
+               }
+
+               case FLAG_PASSING:
+               {
+                       vector targ_origin = ((this.pass_target.absmin + this.pass_target.absmax) * 0.5);
+                       targ_origin = WarpZone_RefSys_TransformOrigin(this.pass_target, this, targ_origin); // origin of target as seen by the flag (us)
+                       WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
+
+                       if((this.pass_target == NULL)
+                               || (IS_DEAD(this.pass_target))
+                               || (this.pass_target.flagcarried)
+                               || (vdist(this.origin - targ_origin, >, autocvar_g_ctf_pass_radius))
+                               || ((trace_fraction < 1) && (trace_ent != this.pass_target))
+                               || (time > this.ctf_droptime + autocvar_g_ctf_pass_timelimit))
+                       {
+                               // give up, pass failed
+                               ctf_Handle_Drop(this, NULL, DROP_PASS);
+                       }
+                       else
+                       {
+                               // still a viable target, go for it
+                               ctf_CalculatePassVelocity(this, targ_origin, this.origin, true);
+                       }
+                       return;
+               }
+
+               default: // this should never happen
+               {
+                       LOG_TRACE("ctf_FlagThink(): Flag exists with no status?");
+                       return;
+               }
+       }
+}
+
+METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
+{
+       return = false;
+       if(game_stopped) return;
+       if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
+
+       bool is_not_monster = (!IS_MONSTER(toucher));
+
+       // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
+       if(ITEM_TOUCH_NEEDKILL())
+       {
+               if(!autocvar_g_ctf_flag_return_damage_delay)
+               {
+                       flag.health = 0;
+                       ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
+               }
+               if(!flag.ctf_flagdamaged_byworld) { return; }
+       }
+
+       // special touch behaviors
+       if(STAT(FROZEN, toucher)) { return; }
+       else if(IS_VEHICLE(toucher))
+       {
+               if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
+                       toucher = toucher.owner; // the player is actually the vehicle owner, not other
+               else
+                       return; // do nothing
+       }
+       else if(IS_MONSTER(toucher))
+       {
+               if(!autocvar_g_ctf_allow_monster_touch)
+                       return; // do nothing
+       }
+       else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
+       {
+               if(time > flag.wait) // if we haven't in a while, play a sound/effect
+               {
+                       Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
+                       _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+                       flag.wait = time + FLAG_TOUCHRATE;
+               }
+               return;
+       }
+       else if(IS_DEAD(toucher)) { return; }
+
+       switch(flag.ctf_status)
+       {
+               case FLAG_BASE:
+               {
+                       if(ctf_oneflag)
+                       {
+                               if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
+                                       ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
+                               else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+                                       ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
+                       }
+                       else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
+                               ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+                       else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
+                       {
+                               ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
+                               ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // now pickup the flag
+                       }
+                       else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+                               ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
+                       break;
+               }
+
+               case FLAG_DROPPED:
+               {
+                       if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
+                               ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+                       else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+                               ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
+                       break;
+               }
+
+               case FLAG_CARRY:
+               {
+                       LOG_TRACE("Someone touched a flag even though it was being carried?");
+                       break;
+               }
+
+               case FLAG_PASSING:
+               {
+                       if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
+                       {
+                               if(DIFF_TEAM(toucher, flag.pass_sender))
+                               {
+                                       if(ctf_Immediate_Return_Allowed(flag, toucher))
+                                               ctf_Handle_Return(flag, toucher);
+                                       else if(is_not_monster && (!toucher.flagcarried))
+                                               ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
+                               }
+                               else if(!toucher.flagcarried)
+                                       ctf_Handle_Retrieve(flag, toucher);
+                       }
+                       break;
+               }
+       }
+}
+
+.float last_respawn;
+void ctf_RespawnFlag(entity flag)
+{
+       // check for flag respawn being called twice in a row
+       if(flag.last_respawn > time - 0.5)
+               { backtrace("flag respawn called twice quickly! please notify Samual about this..."); }
+
+       flag.last_respawn = time;
+
+       // reset the player (if there is one)
+       if((flag.owner) && (flag.owner.flagcarried == flag))
+       {
+               WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
+               WaypointSprite_Kill(flag.owner.wps_flagreturn);
+               WaypointSprite_Kill(flag.wps_flagcarrier);
+
+               flag.owner.flagcarried = NULL;
+               GameRules_scoring_vip(flag.owner, false);
+
+               if(flag.speedrunning)
+                       ctf_FakeTimeLimit(flag.owner, -1);
+       }
+
+       if((flag.owner) && (flag.owner.vehicle))
+               flag.scale = FLAG_SCALE;
+
+       if(flag.ctf_status == FLAG_DROPPED)
+               { WaypointSprite_Kill(flag.wps_flagdropped); }
+
+       // reset the flag
+       setattachment(flag, NULL, "");
+       setorigin(flag, flag.ctf_spawnorigin);
+
+       set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
+       flag.takedamage = DAMAGE_NO;
+       flag.health = flag.max_flag_health;
+       flag.solid = SOLID_TRIGGER;
+       flag.velocity = '0 0 0';
+       flag.angles = flag.mangle;
+       flag.flags = FL_ITEM | FL_NOTARGET;
+
+       flag.ctf_status = FLAG_BASE;
+       flag.owner = NULL;
+       flag.pass_distance = 0;
+       flag.pass_sender = NULL;
+       flag.pass_target = NULL;
+       flag.ctf_dropper = NULL;
+       flag.ctf_pickuptime = 0;
+       flag.ctf_droptime = 0;
+       flag.ctf_flagdamaged_byworld = false;
+       navigation_dynamicgoal_unset(flag);
+
+       ctf_CheckStalemate();
+}
+
+void ctf_Reset(entity this)
+{
+       if(this.owner && IS_PLAYER(this.owner))
+               ctf_Handle_Throw(this.owner, NULL, DROP_RESET);
+
+       this.enemy = NULL;
+       ctf_RespawnFlag(this);
+}
+
+bool ctf_FlagBase_Customize(entity this, entity client)
+{
+       entity e = WaypointSprite_getviewentity(client);
+       entity wp_owner = this.owner;
+       entity flag = e.flagcarried;
+       if(flag && CTF_SAMETEAM(e, flag))
+               return false;
+       if(flag && (flag.cnt || wp_owner.cnt) && wp_owner.cnt != flag.cnt)
+               return false;
+       return true;
+}
+
+void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map by ctf_FlagSetup()
+{
+       // bot waypoints
+       waypoint_spawnforitem_force(this, this.origin);
+       navigation_dynamicgoal_init(this, true);
+
+       // waypointsprites
+       entity basename;
+       switch (this.team)
+       {
+               case NUM_TEAM_1: basename = WP_FlagBaseRed; break;
+               case NUM_TEAM_2: basename = WP_FlagBaseBlue; break;
+               case NUM_TEAM_3: basename = WP_FlagBaseYellow; break;
+               case NUM_TEAM_4: basename = WP_FlagBasePink; break;
+               default: basename = WP_FlagBaseNeutral; break;
+       }
+
+       entity wp = WaypointSprite_SpawnFixed(basename, this.origin + FLAG_WAYPOINT_OFFSET, this, wps_flagbase, RADARICON_FLAG);
+       wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 1 1');
+       WaypointSprite_UpdateTeamRadar(this.wps_flagbase, RADARICON_FLAG, ((this.team) ? colormapPaletteColor(this.team - 1, false) : '1 1 1'));
+       setcefc(wp, ctf_FlagBase_Customize);
+
+       // captureshield setup
+       ctf_CaptureShield_Spawn(this);
+}
+
+.bool pushable;
+
+void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
+{
+       // main setup
+       flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist
+       ctf_worldflaglist = flag;
+
+       setattachment(flag, NULL, "");
+
+       flag.netname = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
+       flag.team = teamnumber;
+       flag.classname = "item_flag_team";
+       flag.target = "###item###"; // wut?
+       flag.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;
+       flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
+       flag.health = flag.max_flag_health;
+       flag.event_damage = ctf_FlagDamage;
+       flag.pushable = true;
+       flag.teleportable = TELEPORT_NORMAL;
+       flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
+       flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
+       flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
+       if(flag.damagedbycontents)
+               IL_PUSH(g_damagedbycontents, flag);
+       flag.velocity = '0 0 0';
+       flag.mangle = flag.angles;
+       flag.reset = ctf_Reset;
+       settouch(flag, ctf_FlagTouch);
+       setthink(flag, ctf_FlagThink);
+       flag.nextthink = time + FLAG_THINKRATE;
+       flag.ctf_status = FLAG_BASE;
+
+       // crudely force them all to 0
+       if(autocvar_g_ctf_score_ignore_fields)
+               flag.cnt = flag.score_assist = flag.score_team_capture = flag.score_capture = flag.score_drop = flag.score_pickup = flag.score_return = 0;
+
+       string teamname = Static_Team_ColorName_Lower(teamnumber);
+       // appearence
+       if(!flag.scale)                         { flag.scale = FLAG_SCALE; }
+       if(flag.skin == 0)                      { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
+       if(flag.model == "")            { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
+       if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
+       if (flag.passeffect == "")      { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
+       if (flag.capeffect == "")       { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
+
+       // sounds
+#define X(s,b) \
+               if(flag.s == "") flag.s = b; \
+               precache_sound(flag.s);
+
+       X(snd_flag_taken,               strzone(SND(CTF_TAKEN(teamnumber))))
+       X(snd_flag_returned,    strzone(SND(CTF_RETURNED(teamnumber))))
+       X(snd_flag_capture,     strzone(SND(CTF_CAPTURE(teamnumber))))
+       X(snd_flag_dropped,     strzone(SND(CTF_DROPPED(teamnumber))))
+       X(snd_flag_respawn,     strzone(SND(CTF_RESPAWN)))
+       X(snd_flag_touch,               strzone(SND(CTF_TOUCH)))
+       X(snd_flag_pass,                strzone(SND(CTF_PASS)))
+#undef X
+
+       // precache
+       precache_model(flag.model);
+
+       // appearence
+       _setmodel(flag, flag.model); // precision set below
+       setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
+       flag.m_mins = flag.mins; // store these for squash checks
+       flag.m_maxs = flag.maxs;
+       setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
+
+       if(autocvar_g_ctf_flag_glowtrails)
+       {
+               switch(teamnumber)
+               {
+                       case NUM_TEAM_1: flag.glow_color = 251; break;
+                       case NUM_TEAM_2: flag.glow_color = 210; break;
+                       case NUM_TEAM_3: flag.glow_color = 110; break;
+                       case NUM_TEAM_4: flag.glow_color = 145; break;
+                       default:                 flag.glow_color = 254; break;
+               }
+               flag.glow_size = 25;
+               flag.glow_trail = 1;
+       }
+
+       flag.effects |= EF_LOWPRECISION;
+       if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
+       if(autocvar_g_ctf_dynamiclights)
+       {
+               switch(teamnumber)
+               {
+                       case NUM_TEAM_1: flag.effects |= EF_RED; break;
+                       case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
+                       case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
+                       case NUM_TEAM_4: flag.effects |= EF_RED; break;
+                       default:                 flag.effects |= EF_DIMLIGHT; break;
+               }
+       }
+
+       // flag placement
+       if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
+       {
+               flag.dropped_origin = flag.origin;
+               flag.noalign = true;
+               set_movetype(flag, MOVETYPE_NONE);
+       }
+       else // drop to floor, automatically find a platform and set that as spawn origin
+       {
+               flag.noalign = false;
+               droptofloor(flag);
+               set_movetype(flag, MOVETYPE_NONE);
+       }
+
+       InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+// NOTE: LEGACY CODE, needs to be re-written!
+
+void havocbot_ctf_calculate_middlepoint()
+{
+       entity f;
+       vector s = '0 0 0';
+       vector fo = '0 0 0';
+       int n = 0;
+
+       f = ctf_worldflaglist;
+       while (f)
+       {
+               fo = f.origin;
+               s = s + fo;
+               f = f.ctf_worldflagnext;
+               n++;
+       }
+       if(!n)
+               return;
+
+       havocbot_middlepoint = s / n;
+       havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
+
+       havocbot_symmetry_axis_m = 0;
+       havocbot_symmetry_axis_q = 0;
+       if(n == 2)
+       {
+               // for symmetrical editing of waypoints
+               entity f1 = ctf_worldflaglist;
+               entity f2 = f1.ctf_worldflagnext;
+               float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
+               float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
+               havocbot_symmetry_axis_m = m;
+               havocbot_symmetry_axis_q = q;
+       }
+       havocbot_symmetry_origin_order = n;
+}
+
+
+entity havocbot_ctf_find_flag(entity bot)
+{
+       entity f;
+       f = ctf_worldflaglist;
+       while (f)
+       {
+               if (CTF_SAMETEAM(bot, f))
+                       return f;
+               f = f.ctf_worldflagnext;
+       }
+       return NULL;
+}
+
+entity havocbot_ctf_find_enemy_flag(entity bot)
+{
+       entity f;
+       f = ctf_worldflaglist;
+       while (f)
+       {
+               if(ctf_oneflag)
+               {
+                       if(CTF_DIFFTEAM(bot, f))
+                       {
+                               if(f.team)
+                               {
+                                       if(bot.flagcarried)
+                                               return f;
+                               }
+                               else if(!bot.flagcarried)
+                                       return f;
+                       }
+               }
+               else if (CTF_DIFFTEAM(bot, f))
+                       return f;
+               f = f.ctf_worldflagnext;
+       }
+       return NULL;
+}
+
+int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
+{
+       if (!teamplay)
+               return 0;
+
+       int c = 0;
+
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
+                       continue;
+
+               if(vdist(it.origin - org, <, tc_radius))
+                       ++c;
+       });
+
+       return c;
+}
+
+// unused
+#if 0
+void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale)
+{
+       entity head;
+       head = ctf_worldflaglist;
+       while (head)
+       {
+               if (CTF_SAMETEAM(this, head))
+                       break;
+               head = head.ctf_worldflagnext;
+       }
+       if (head)
+               navigation_routerating(this, head, ratingscale, 10000);
+}
+#endif
+
+void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale)
+{
+       entity head;
+       head = ctf_worldflaglist;
+       while (head)
+       {
+               if (CTF_SAMETEAM(this, head))
+               {
+                       if (this.flagcarried)
+                       if ((this.flagcarried.cnt || head.cnt) && this.flagcarried.cnt != head.cnt)
+                       {
+                               head = head.ctf_worldflagnext; // skip base if it has a different group
+                               continue;
+                       }
+                       break;
+               }
+               head = head.ctf_worldflagnext;
+       }
+       if (!head)
+               return;
+
+       navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale)
+{
+       entity head;
+       head = ctf_worldflaglist;
+       while (head)
+       {
+               if(ctf_oneflag)
+               {
+                       if(CTF_DIFFTEAM(this, head))
+                       {
+                               if(head.team)
+                               {
+                                       if(this.flagcarried)
+                                               break;
+                               }
+                               else if(!this.flagcarried)
+                                       break;
+                       }
+               }
+               else if(CTF_DIFFTEAM(this, head))
+                       break;
+               head = head.ctf_worldflagnext;
+       }
+       if (head)
+               navigation_routerating(this, head, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_enemybase(entity this, float ratingscale)
+{
+       if (!bot_waypoints_for_items)
+       {
+               havocbot_goalrating_ctf_enemyflag(this, ratingscale);
+               return;
+       }
+
+       entity head;
+
+       head = havocbot_ctf_find_enemy_flag(this);
+
+       if (!head)
+               return;
+
+       navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_ourstolenflag(entity this, float ratingscale)
+{
+       entity mf;
+
+       mf = havocbot_ctf_find_flag(this);
+
+       if(mf.ctf_status == FLAG_BASE)
+               return;
+
+       if(mf.tag_entity)
+               navigation_routerating(this, mf.tag_entity, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector org, float df_radius)
+{
+       entity head;
+       head = ctf_worldflaglist;
+       while (head)
+       {
+               // flag is out in the field
+               if(head.ctf_status != FLAG_BASE)
+               if(head.tag_entity==NULL)       // dropped
+               {
+                       if(df_radius)
+                       {
+                               if(vdist(org - head.origin, <, df_radius))
+                                       navigation_routerating(this, head, ratingscale, 10000);
+                       }
+                       else
+                               navigation_routerating(this, head, ratingscale, 10000);
+               }
+
+               head = head.ctf_worldflagnext;
+       }
+}
+
+void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
+{
+       IL_EACH(g_items, it.bot_pickup,
+       {
+               // gather health and armor only
+               if (it.solid)
+               if (it.health || it.armorvalue)
+               if (vdist(it.origin - org, <, sradius))
+               {
+                       // get the value of the item
+                       float t = it.bot_pickupevalfunc(this, it) * 0.0001;
+                       if (t > 0)
+                               navigation_routerating(this, it, t * ratingscale, 500);
+               }
+       });
+}
+
+void havocbot_ctf_reset_role(entity this)
+{
+       float cdefense, cmiddle, coffense;
+       entity mf, ef;
+       float c;
+
+       if(IS_DEAD(this))
+               return;
+
+       // Check ctf flags
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       mf = havocbot_ctf_find_flag(this);
+       ef = havocbot_ctf_find_enemy_flag(this);
+
+       // Retrieve stolen flag
+       if(mf.ctf_status!=FLAG_BASE)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+               return;
+       }
+
+       // If enemy flag is taken go to the middle to intercept pursuers
+       if(ef.ctf_status!=FLAG_BASE)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+               return;
+       }
+
+       // if there is only me on the team switch to offense
+       c = 0;
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
+
+       if(c==1)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
+               return;
+       }
+
+       // Evaluate best position to take
+       // Count mates on middle position
+       cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
+
+       // Count mates on defense position
+       cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
+
+       // Count mates on offense position
+       coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
+
+       if(cdefense<=coffense)
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
+       else if(coffense<=cmiddle)
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
+       else
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+}
+
+void havocbot_role_ctf_carrier(entity this)
+{
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried == NULL)
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               if(ctf_oneflag)
+                       havocbot_goalrating_ctf_enemybase(this, 50000);
+               else
+                       havocbot_goalrating_ctf_ourbase(this, 50000);
+
+               if(this.health<100)
+                       havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+
+               entity head = ctf_worldflaglist;
+               while (head)
+               {
+                       if (this.goalentity == head.bot_basewaypoint)
+                       {
+                               this.goalentity_lock_timeout = time + 5;
+                               break;
+                       }
+                       head = head.ctf_worldflagnext;
+               }
+
+               if (this.goalentity)
+                       this.havocbot_cantfindflag = time + 10;
+               else if (time > this.havocbot_cantfindflag)
+               {
+                       // Can't navigate to my own base, suicide!
+                       // TODO: drop it and wander around
+                       Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
+                       return;
+               }
+       }
+}
+
+void havocbot_role_ctf_escort(entity this)
+{
+       entity mf, ef;
+
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       // If enemy flag is back on the base switch to previous role
+       ef = havocbot_ctf_find_enemy_flag(this);
+       if(ef.ctf_status==FLAG_BASE)
+       {
+               this.havocbot_role = this.havocbot_previous_role;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       // If the flag carrier reached the base switch to defense
+       mf = havocbot_ctf_find_flag(this);
+       if(mf.ctf_status!=FLAG_BASE)
+       if(vdist(ef.origin - mf.dropped_origin, <, 300))
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!this.havocbot_role_timeout)
+       {
+               this.havocbot_role_timeout = time + random() * 30 + 60;
+       }
+
+       // If nothing happened just switch to previous role
+       if (time > this.havocbot_role_timeout)
+       {
+               this.havocbot_role = this.havocbot_previous_role;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       // Chase the flag carrier
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               havocbot_goalrating_ctf_enemyflag(this, 30000);
+               havocbot_goalrating_ctf_ourstolenflag(this, 40000);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ctf_offense(entity this)
+{
+       entity mf, ef;
+       vector pos;
+
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       // Check flags
+       mf = havocbot_ctf_find_flag(this);
+       ef = havocbot_ctf_find_enemy_flag(this);
+
+       // Own flag stolen
+       if(mf.ctf_status!=FLAG_BASE)
+       {
+               if(mf.tag_entity)
+                       pos = mf.tag_entity.origin;
+               else
+                       pos = mf.origin;
+
+               // Try to get it if closer than the enemy base
+               if(vlen2(this.origin-ef.dropped_origin)>vlen2(this.origin-pos))
+               {
+                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+                       return;
+               }
+       }
+
+       // Escort flag carrier
+       if(ef.ctf_status!=FLAG_BASE)
+       {
+               if(ef.tag_entity)
+                       pos = ef.tag_entity.origin;
+               else
+                       pos = ef.origin;
+
+               if(vdist(pos - mf.dropped_origin, >, 700))
+               {
+                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_ESCORT);
+                       return;
+               }
+       }
+
+       // About to fail, switch to middlefield
+       if(this.health<50)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 120;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+               havocbot_goalrating_ctf_enemybase(this, 20000);
+               havocbot_goalrating_items(this, 5000, this.origin, 1000);
+               havocbot_goalrating_items(this, 1000, this.origin, 10000);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+// Retriever (temporary role):
+void havocbot_role_ctf_retriever(entity this)
+{
+       entity mf;
+
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       // If flag is back on the base switch to previous role
+       mf = havocbot_ctf_find_flag(this);
+       if(mf.ctf_status==FLAG_BASE)
+       {
+               if (mf.enemy == this) // did this bot return the flag?
+                       navigation_goalrating_timeout_force(this);
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 20;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               float rt_radius;
+               rt_radius = 10000;
+
+               navigation_goalrating_start(this);
+
+               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+               havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
+               havocbot_goalrating_ctf_enemybase(this, 30000);
+               havocbot_goalrating_items(this, 500, this.origin, rt_radius);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ctf_middle(entity this)
+{
+       entity mf;
+
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       mf = havocbot_ctf_find_flag(this);
+       if(mf.ctf_status!=FLAG_BASE)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 10;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               vector org;
+
+               org = havocbot_middlepoint;
+               org.z = this.origin.z;
+
+               navigation_goalrating_start(this);
+
+               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+               havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
+               havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
+               havocbot_goalrating_items(this, 2500, this.origin, 10000);
+               havocbot_goalrating_ctf_enemybase(this, 2500);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ctf_defense(entity this)
+{
+       entity mf;
+
+       if(IS_DEAD(this))
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+
+       if (this.flagcarried)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+               return;
+       }
+
+       // If own flag was captured
+       mf = havocbot_ctf_find_flag(this);
+       if(mf.ctf_status!=FLAG_BASE)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 30;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               havocbot_ctf_reset_role(this);
+               return;
+       }
+       if (navigation_goalrating_timeout(this))
+       {
+               vector org = mf.dropped_origin;
+
+               navigation_goalrating_start(this);
+
+               // if enemies are closer to our base, go there
+               entity closestplayer = NULL;
+               float distance, bestdistance = 10000;
+               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
+                       distance = vlen(org - it.origin);
+                       if(distance<bestdistance)
+                       {
+                               closestplayer = it;
+                               bestdistance = distance;
+                       }
+               });
+
+               if(closestplayer)
+               if(DIFF_TEAM(closestplayer, this))
+               if(vdist(org - this.origin, >, 1000))
+               if(checkpvs(this.origin,closestplayer)||random()<0.5)
+                       havocbot_goalrating_ctf_ourbase(this, 30000);
+
+               havocbot_goalrating_ctf_ourstolenflag(this, 20000);
+               havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
+               havocbot_goalrating_items(this, 5000, this.origin, 10000);
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ctf_setrole(entity bot, int role)
+{
+       string s = "(null)";
+       switch(role)
+       {
+               case HAVOCBOT_CTF_ROLE_CARRIER:
+                       s = "carrier";
+                       bot.havocbot_role = havocbot_role_ctf_carrier;
+                       bot.havocbot_role_timeout = 0;
+                       bot.havocbot_cantfindflag = time + 10;
+                       if (bot.havocbot_previous_role != bot.havocbot_role)
+                               navigation_goalrating_timeout_force(bot);
+                       break;
+               case HAVOCBOT_CTF_ROLE_DEFENSE:
+                       s = "defense";
+                       bot.havocbot_role = havocbot_role_ctf_defense;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_CTF_ROLE_MIDDLE:
+                       s = "middle";
+                       bot.havocbot_role = havocbot_role_ctf_middle;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_CTF_ROLE_OFFENSE:
+                       s = "offense";
+                       bot.havocbot_role = havocbot_role_ctf_offense;
+                       bot.havocbot_role_timeout = 0;
+                       break;
+               case HAVOCBOT_CTF_ROLE_RETRIEVER:
+                       s = "retriever";
+                       bot.havocbot_previous_role = bot.havocbot_role;
+                       bot.havocbot_role = havocbot_role_ctf_retriever;
+                       bot.havocbot_role_timeout = time + 10;
+                       if (bot.havocbot_previous_role != bot.havocbot_role)
+                               navigation_goalrating_timeout_expire(bot, 2);
+                       break;
+               case HAVOCBOT_CTF_ROLE_ESCORT:
+                       s = "escort";
+                       bot.havocbot_previous_role = bot.havocbot_role;
+                       bot.havocbot_role = havocbot_role_ctf_escort;
+                       bot.havocbot_role_timeout = time + 30;
+                       if (bot.havocbot_previous_role != bot.havocbot_role)
+                               navigation_goalrating_timeout_expire(bot, 2);
+                       break;
+       }
+       LOG_TRACE(bot.netname, " switched to ", s);
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       int t = 0, t2 = 0, t3 = 0;
+       bool b1 = false, b2 = false, b3 = false, b4 = false, b5 = false; // TODO: kill this, we WANT to show the other flags, somehow! (note: also means you don't see if you're FC)
+
+       // initially clear items so they can be set as necessary later.
+       STAT(CTF_FLAGSTATUS, player) &= ~(CTF_RED_FLAG_CARRYING         | CTF_RED_FLAG_TAKEN            | CTF_RED_FLAG_LOST
+                                                  | CTF_BLUE_FLAG_CARRYING             | CTF_BLUE_FLAG_TAKEN           | CTF_BLUE_FLAG_LOST
+                                                  | CTF_YELLOW_FLAG_CARRYING   | CTF_YELLOW_FLAG_TAKEN         | CTF_YELLOW_FLAG_LOST
+                                                  | CTF_PINK_FLAG_CARRYING     | CTF_PINK_FLAG_TAKEN           | CTF_PINK_FLAG_LOST
+                                                  | CTF_NEUTRAL_FLAG_CARRYING  | CTF_NEUTRAL_FLAG_TAKEN        | CTF_NEUTRAL_FLAG_LOST
+                                                  | CTF_FLAG_NEUTRAL | CTF_SHIELDED | CTF_STALEMATE);
+
+       // scan through all the flags and notify the client about them
+       for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+       {
+               if(flag.team == NUM_TEAM_1 && !b1) { b1 = true; t = CTF_RED_FLAG_CARRYING;              t2 = CTF_RED_FLAG_TAKEN;                t3 = CTF_RED_FLAG_LOST; }
+               if(flag.team == NUM_TEAM_2 && !b2) { b2 = true; t = CTF_BLUE_FLAG_CARRYING;             t2 = CTF_BLUE_FLAG_TAKEN;               t3 = CTF_BLUE_FLAG_LOST; }
+               if(flag.team == NUM_TEAM_3 && !b3) { b3 = true; t = CTF_YELLOW_FLAG_CARRYING;   t2 = CTF_YELLOW_FLAG_TAKEN;             t3 = CTF_YELLOW_FLAG_LOST; }
+               if(flag.team == NUM_TEAM_4 && !b4) { b4 = true; t = CTF_PINK_FLAG_CARRYING;             t2 = CTF_PINK_FLAG_TAKEN;               t3 = CTF_PINK_FLAG_LOST; }
+               if(flag.team == 0 && !b5)                  { b5 = true; t = CTF_NEUTRAL_FLAG_CARRYING;  t2 = CTF_NEUTRAL_FLAG_TAKEN;    t3 = CTF_NEUTRAL_FLAG_LOST; STAT(CTF_FLAGSTATUS, player) |= CTF_FLAG_NEUTRAL; }
+
+               switch(flag.ctf_status)
+               {
+                       case FLAG_PASSING:
+                       case FLAG_CARRY:
+                       {
+                               if((flag.owner == player) || (flag.pass_sender == player))
+                                       STAT(CTF_FLAGSTATUS, player) |= t; // carrying: player is currently carrying the flag
+                               else
+                                       STAT(CTF_FLAGSTATUS, player) |= t2; // taken: someone else is carrying the flag
+                               break;
+                       }
+                       case FLAG_DROPPED:
+                       {
+                               STAT(CTF_FLAGSTATUS, player) |= t3; // lost: the flag is dropped somewhere on the map
+                               break;
+                       }
+               }
+       }
+
+       // item for stopping players from capturing the flag too often
+       if(player.ctf_captureshielded)
+               STAT(CTF_FLAGSTATUS, player) |= CTF_SHIELDED;
+
+       if(ctf_stalemate)
+               STAT(CTF_FLAGSTATUS, player) |= CTF_STALEMATE;
+
+       // update the health of the flag carrier waypointsprite
+       if(player.wps_flagcarrier)
+               WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+}
+
+MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
+       {
+               if(frag_target == frag_attacker) // damage done to yourself
+               {
+                       frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor;
+                       frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor;
+               }
+               else // damage done to everyone else
+               {
+                       frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor;
+                       frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
+               }
+
+               M_ARGV(4, float) = frag_damage;
+               M_ARGV(6, vector) = frag_force;
+       }
+       else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
+       {
+               if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
+               if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
+               {
+                       frag_target.wps_helpme_time = time;
+                       WaypointSprite_HelpMePing(frag_target.wps_flagcarrier);
+               }
+               // todo: add notification for when flag carrier needs help?
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
+       {
+               GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
+               GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+       }
+
+       if(frag_target.flagcarried)
+       {
+               entity tmp_entity = frag_target.flagcarried;
+               ctf_Handle_Throw(frag_target, NULL, DROP_NORMAL);
+               tmp_entity.ctf_dropper = NULL;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
+{
+       M_ARGV(2, float) = 0; // frag score
+       return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true
+}
+
+void ctf_RemovePlayer(entity player)
+{
+       if(player.flagcarried)
+               { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
+
+       for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+       {
+               if(flag.pass_sender == player) { flag.pass_sender = NULL; }
+               if(flag.pass_target == player) { flag.pass_target = NULL; }
+               if(flag.ctf_dropper == player) { flag.ctf_dropper = NULL; }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       ctf_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       ctf_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, ClientConnect)
+{
+       if(!autocvar_g_ctf_leaderboard)
+               return;
+
+       entity player = M_ARGV(0, entity);
+
+       if(IS_REAL_CLIENT(player))
+       {
+               int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+               race_send_rankings_cnt(MSG_ONE);
+               for (int i = 1; i <= m; ++i)
+               {
+                       race_SendRankings(i, 0, 0, MSG_ONE);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GetPressedKeys)
+{
+       if(!autocvar_g_ctf_leaderboard)
+               return;
+
+       entity player = M_ARGV(0, entity);
+
+       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
+       {
+               if (!player.stored_netname)
+                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
+               if(player.stored_netname != player.netname)
+               {
+                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
+                       strcpy(player.stored_netname, player.netname);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.flagcarried)
+       if(!autocvar_g_ctf_portalteleport)
+               { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
+{
+       if(MUTATOR_RETURNVALUE || game_stopped) return;
+
+       entity player = M_ARGV(0, entity);
+
+       if((time > player.throw_antispam) && !IS_DEAD(player) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
+       {
+               // pass the flag to a team mate
+               if(autocvar_g_ctf_pass)
+               {
+                       entity head, closest_target = NULL;
+                       head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
+
+                       while(head) // find the closest acceptable target to pass to
+                       {
+                               if(IS_PLAYER(head) && !IS_DEAD(head))
+                               if(head != player && SAME_TEAM(head, player))
+                               if(!head.speedrunning && !head.vehicle)
+                               {
+                                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+                                       vector head_center = WarpZone_UnTransformOrigin(head, CENTER_OR_VIEWOFS(head));
+                                       vector passer_center = CENTER_OR_VIEWOFS(player);
+
+                                       if(ctf_CheckPassDirection(head_center, passer_center, player.v_angle, head.WarpZone_findradius_nearest))
+                                       {
+                                               if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried)
+                                               {
+                                                       if(IS_BOT_CLIENT(head))
+                                                       {
+                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
+                                                               ctf_Handle_Throw(head, player, DROP_PASS);
+                                                       }
+                                                       else
+                                                       {
+                                                               Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname);
+                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
+                                                       }
+                                                       player.throw_antispam = time + autocvar_g_ctf_pass_wait;
+                                                       return true;
+                                               }
+                                               else if(player.flagcarried && !head.flagcarried)
+                                               {
+                                                       if(closest_target)
+                                                       {
+                                                               vector closest_target_center = WarpZone_UnTransformOrigin(closest_target, CENTER_OR_VIEWOFS(closest_target));
+                                                               if(vlen2(passer_center - head_center) < vlen2(passer_center - closest_target_center))
+                                                                       { closest_target = head; }
+                                                       }
+                                                       else { closest_target = head; }
+                                               }
+                                       }
+                               }
+                               head = head.chain;
+                       }
+
+                       if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
+               }
+
+               // throw the flag in front of you
+               if(autocvar_g_ctf_throw && player.flagcarried)
+               {
+                       if(player.throw_count == -1)
+                       {
+                               if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_delay)
+                               {
+                                       player.throw_prevtime = time;
+                                       player.throw_count = 1;
+                                       ctf_Handle_Throw(player, NULL, DROP_THROW);
+                                       return true;
+                               }
+                               else
+                               {
+                                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
+                                       return false;
+                               }
+                       }
+                       else
+                       {
+                               if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_time) { player.throw_count = 1; }
+                               else { player.throw_count += 1; }
+                               if(player.throw_count >= autocvar_g_ctf_throw_punish_count) { player.throw_count = -1; }
+
+                               player.throw_prevtime = time;
+                               ctf_Handle_Throw(player, NULL, DROP_THROW);
+                               return true;
+                       }
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, HelpMePing)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
+       {
+               player.wps_helpme_time = time;
+               WaypointSprite_HelpMePing(player.wps_flagcarrier);
+       }
+       else // create a normal help me waypointsprite
+       {
+               WaypointSprite_Spawn(WP_Helpme, waypointsprite_deployed_lifetime, waypointsprite_limitedrange, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_helpme, false, RADARICON_HELPME);
+               WaypointSprite_Ping(player.wps_helpme);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, VehicleEnter)
+{
+       entity player = M_ARGV(0, entity);
+       entity veh = M_ARGV(1, entity);
+
+       if(player.flagcarried)
+       {
+               if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
+               {
+                       ctf_Handle_Throw(player, NULL, DROP_NORMAL);
+               }
+               else
+               {
+                       player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
+                       setattachment(player.flagcarried, veh, "");
+                       setorigin(player.flagcarried, VEHICLE_FLAG_OFFSET);
+                       player.flagcarried.scale = VEHICLE_FLAG_SCALE;
+                       //player.flagcarried.angles = '0 0 0';
+               }
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, VehicleExit)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.flagcarried)
+       {
+               setattachment(player.flagcarried, player, "");
+               setorigin(player.flagcarried, FLAG_CARRY_OFFSET);
+               player.flagcarried.scale = FLAG_SCALE;
+               player.flagcarried.angles = '0 0 0';
+               player.flagcarried.nodrawtoclient = NULL;
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.flagcarried)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN));
+               ctf_RespawnFlag(player.flagcarried);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, MatchEnd)
+{
+       entity flag; // temporary entity for the search method
+
+       for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+       {
+               switch(flag.ctf_status)
+               {
+                       case FLAG_DROPPED:
+                       case FLAG_PASSING:
+                       {
+                               // lock the flag, game is over
+                               set_movetype(flag, MOVETYPE_NONE);
+                               flag.takedamage = DAMAGE_NO;
+                               flag.solid = SOLID_NOT;
+                               flag.nextthink = false; // stop thinking
+
+                               //dprint("stopping the ", flag.netname, " from moving.\n");
+                               break;
+                       }
+
+                       default:
+                       case FLAG_BASE:
+                       case FLAG_CARRY:
+                       {
+                               // do nothing for these flags
+                               break;
+                       }
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       havocbot_ctf_reset_role(bot);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
+{
+       //M_ARGV(0, float) = ctf_teams;
+       M_ARGV(1, string) = "ctf_team";
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
+{
+       entity spectatee = M_ARGV(0, entity);
+       entity client = M_ARGV(1, entity);
+
+       STAT(CTF_FLAGSTATUS, client) = STAT(CTF_FLAGSTATUS, spectatee);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GetRecords)
+{
+       int record_page = M_ARGV(0, int);
+       string ret_string = M_ARGV(1, string);
+
+       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+       {
+               if (MapInfo_Get_ByID(i))
+               {
+                       float r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
+
+                       if(!r)
+                               continue;
+
+                       // TODO: uid2name
+                       string h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
+                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
+               }
+       }
+
+       M_ARGV(1, string) = ret_string;
+}
+
+bool superspec_Spectate(entity this, entity targ); // TODO
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel); // TODO
+MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
+{
+       entity player = M_ARGV(0, entity);
+       string cmd_name = M_ARGV(1, string);
+       int cmd_argc = M_ARGV(2, int);
+
+       if(IS_PLAYER(player) || MUTATOR_RETURNVALUE || !cvar("g_superspectate")) { return false; }
+
+       if(cmd_name == "followfc")
+       {
+               if(!g_ctf)
+                       return true;
+
+               int _team = 0;
+               bool found = false;
+
+               if(cmd_argc == 2)
+               {
+                       switch(argv(1))
+                       {
+                               case "red":    if(ctf_teams & BIT(0)) _team = NUM_TEAM_1; break;
+                               case "blue":   if(ctf_teams & BIT(1)) _team = NUM_TEAM_2; break;
+                               case "yellow": if(ctf_teams & BIT(2)) _team = NUM_TEAM_3; break;
+                               case "pink":   if(ctf_teams & BIT(3)) _team = NUM_TEAM_4; break;
+                       }
+               }
+
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(it.flagcarried && (it.team == _team || _team == 0))
+                       {
+                               found = true;
+                               if(_team == 0 && IS_SPEC(player) && player.enemy == it)
+                                       continue; // already spectating this fc, try another
+                               return superspec_Spectate(player, it);
+                       }
+               });
+
+               if(!found)
+                       superspec_msg("", "", player, "No active flag carrier\n", 1);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
+{
+       entity frag_target = M_ARGV(0, entity);
+
+       if(frag_target.flagcarried)
+               ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
+}
+
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team one (Red).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team1)
+{
+       if(!g_ctf) { delete(this); return; }
+
+       ctf_FlagSetup(NUM_TEAM_1, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team two (Blue).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team2)
+{
+       if(!g_ctf) { delete(this); return; }
+
+       ctf_FlagSetup(NUM_TEAM_2, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team3 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team three (Yellow).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team3)
+{
+       if(!g_ctf) { delete(this); return; }
+
+       ctf_FlagSetup(NUM_TEAM_3, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team4 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team four (Pink).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team4)
+{
+       if(!g_ctf) { delete(this); return; }
+
+       ctf_FlagSetup(NUM_TEAM_4, this);
+}
+
+/*QUAKED spawnfunc_item_flag_neutral (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag (Neutral).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_neutral)
+{
+       if(!g_ctf) { delete(this); return; }
+       if(!cvar("g_ctf_oneflag")) { delete(this); return; }
+
+       ctf_FlagSetup(0, this);
+}
+
+/*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
+Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
+Note: If you use spawnfunc_ctf_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
+Keys:
+"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
+"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
+spawnfunc(ctf_team)
+{
+       if(!g_ctf) { delete(this); return; }
+
+       this.classname = "ctf_team";
+       this.team = this.cnt + 1;
+}
+
+// compatibility for quake maps
+spawnfunc(team_CTF_redflag)    { spawnfunc_item_flag_team1(this);    }
+spawnfunc(team_CTF_blueflag)   { spawnfunc_item_flag_team2(this);    }
+spawnfunc(info_player_team1);
+spawnfunc(team_CTF_redplayer)  { spawnfunc_info_player_team1(this);  }
+spawnfunc(team_CTF_redspawn)   { spawnfunc_info_player_team1(this);  }
+spawnfunc(info_player_team2);
+spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this);  }
+spawnfunc(team_CTF_bluespawn)  { spawnfunc_info_player_team2(this);  }
+
+spawnfunc(team_CTF_neutralflag)        { spawnfunc_item_flag_neutral(this);  }
+spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this);  }
+
+// compatibility for wop maps
+spawnfunc(team_redplayer)      { spawnfunc_info_player_team1(this);  }
+spawnfunc(team_blueplayer)     { spawnfunc_info_player_team2(this);  }
+spawnfunc(team_ctl_redlolly)   { spawnfunc_item_flag_team1(this);    }
+spawnfunc(team_CTL_redlolly)   { spawnfunc_item_flag_team1(this);    }
+spawnfunc(team_ctl_bluelolly)  { spawnfunc_item_flag_team2(this);    }
+spawnfunc(team_CTL_bluelolly)  { spawnfunc_item_flag_team2(this);    }
+
+
+// ==============
+// Initialization
+// ==============
+
+// scoreboard setup
+void ctf_ScoreRules(int teams)
+{
+       CheckAllowedTeams(NULL);
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+        field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+        field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
+        field(SP_CTF_PICKUPS, "pickups", 0);
+        field(SP_CTF_FCKILLS, "fckills", 0);
+        field(SP_CTF_RETURNS, "returns", 0);
+        field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
+       });
+}
+
+// code from here on is just to support maps that don't have flag and team entities
+void ctf_SpawnTeam (string teamname, int teamcolor)
+{
+       entity this = new_pure(ctf_team);
+       this.netname = teamname;
+       this.cnt = teamcolor - 1;
+       this.spawnfunc_checked = true;
+       this.team = teamcolor;
+}
+
+void ctf_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+       ctf_teams = 0;
+
+       entity tmp_entity;
+       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+       {
+               //if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
+               //if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
+
+               switch(tmp_entity.team)
+               {
+                       case NUM_TEAM_1: BITSET_ASSIGN(ctf_teams, BIT(0)); break;
+                       case NUM_TEAM_2: BITSET_ASSIGN(ctf_teams, BIT(1)); break;
+                       case NUM_TEAM_3: BITSET_ASSIGN(ctf_teams, BIT(2)); break;
+                       case NUM_TEAM_4: BITSET_ASSIGN(ctf_teams, BIT(3)); break;
+               }
+               if(tmp_entity.team == 0) { ctf_oneflag = true; }
+       }
+
+       havocbot_ctf_calculate_middlepoint();
+
+       if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
+       {
+               ctf_teams = 0; // so set the default red and blue teams
+               BITSET_ASSIGN(ctf_teams, BIT(0));
+               BITSET_ASSIGN(ctf_teams, BIT(1));
+       }
+
+       //ctf_teams = bound(2, ctf_teams, 4);
+
+       // if no teams are found, spawn defaults
+       if(find(NULL, classname, "ctf_team") == NULL)
+       {
+               LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.");
+               if(ctf_teams & BIT(0))
+                       ctf_SpawnTeam("Red", NUM_TEAM_1);
+               if(ctf_teams & BIT(1))
+                       ctf_SpawnTeam("Blue", NUM_TEAM_2);
+               if(ctf_teams & BIT(2))
+                       ctf_SpawnTeam("Yellow", NUM_TEAM_3);
+               if(ctf_teams & BIT(3))
+                       ctf_SpawnTeam("Pink", NUM_TEAM_4);
+       }
+
+       ctf_ScoreRules(ctf_teams);
+}
+
+void ctf_Initialize()
+{
+       ctf_captimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
+
+       ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
+       ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
+       ctf_captureshield_force = autocvar_g_ctf_shield_force;
+
+       InitializeEntity(NULL, ctf_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/ctf/ctf.qh b/qcsrc/common/gamemodes/gamemode/ctf/ctf.qh
new file mode 100644 (file)
index 0000000..74a3993
--- /dev/null
@@ -0,0 +1,188 @@
+#pragma once
+
+#ifdef SVQC
+
+void ctf_Initialize();
+
+REGISTER_MUTATOR(ctf, false)
+{
+    MUTATOR_STATIC();
+    MUTATOR_ONADD
+    {
+        GameRules_teams(true);
+        GameRules_limit_score(autocvar_capturelimit_override);
+        GameRules_limit_lead(autocvar_captureleadlimit_override);
+
+        ctf_Initialize();
+    }
+    return 0;
+}
+
+// used in cheats.qc
+void ctf_RespawnFlag(entity flag);
+
+// score rule declarations
+const int ST_CTF_CAPS = 1;
+
+CLASS(Flag, Pickup)
+    ATTRIB(Flag, m_mins, vector, (PL_MIN_CONST + '0 0 -13') * 1.4); // scaling be damned
+    ATTRIB(Flag, m_maxs, vector, (PL_MAX_CONST + '0 0 -13') * 1.4);
+ENDCLASS(Flag)
+Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
+void ctf_FlagTouch(entity this, entity toucher) { ITEM_HANDLE(Pickup, CTF_FLAG, this, toucher); }
+
+// flag constants // for most of these, there is just one question to be asked: WHYYYYY?
+
+const float FLAG_SCALE = 0.6;
+
+const float FLAG_THINKRATE = 0.2;
+const float FLAG_TOUCHRATE = 0.5;
+const float WPFE_THINKRATE = 0.5;
+
+const vector FLAG_DROP_OFFSET = ('0 0 32');
+const vector FLAG_CARRY_OFFSET = ('-16 0 8');
+#define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
+const vector FLAG_WAYPOINT_OFFSET = ('0 0 64');
+const vector FLAG_FLOAT_OFFSET = ('0 0 32');
+const vector FLAG_PASS_ARC_OFFSET = ('0 0 -10');
+
+const vector VEHICLE_FLAG_OFFSET = ('0 0 96');
+const float VEHICLE_FLAG_SCALE = 1.0;
+
+// waypoint colors
+#define WPCOLOR_ENEMYFC(t) ((t) ? colormapPaletteColor(t - 1, false) * 0.75 : '1 1 1')
+#define WPCOLOR_FLAGCARRIER(t) (WP_FlagCarrier.m_color)
+#define WPCOLOR_DROPPEDFLAG(t) ((t) ? ('0.25 0.25 0.25' + colormapPaletteColor(t - 1, false)) * 0.5 : '1 1 1')
+
+// sounds
+#define snd_flag_taken noise
+#define snd_flag_returned noise1
+#define snd_flag_capture noise2
+#define snd_flag_respawn noise3
+.string snd_flag_dropped;
+.string snd_flag_touch;
+.string snd_flag_pass;
+
+// score fields
+.float score_assist;
+.float score_capture;
+.float score_drop; // note: negated
+.float score_pickup;
+.float score_return;
+.float score_team_capture; // shouldn't be too high
+
+// effects
+.string toucheffect;
+.string passeffect;
+.string capeffect;
+
+// list of flags on the map
+entity ctf_worldflaglist;
+.entity ctf_worldflagnext;
+.entity ctf_staleflagnext;
+
+// waypoint sprites
+.entity wps_helpme;
+.entity wps_flagbase;
+.entity wps_flagcarrier;
+.entity wps_flagdropped;
+.entity wps_flagreturn;
+.entity wps_enemyflagcarrier;
+.float wps_helpme_time;
+bool wpforenemy_announced;
+float wpforenemy_nextthink;
+
+// statuses
+const int FLAG_BASE = 1;
+const int FLAG_DROPPED = 2;
+const int FLAG_CARRY = 3;
+const int FLAG_PASSING = 4;
+
+const int DROP_NORMAL = 1;
+const int DROP_THROW = 2;
+const int DROP_PASS = 3;
+const int DROP_RESET = 4;
+
+const int PICKUP_BASE = 1;
+const int PICKUP_DROPPED = 2;
+
+const int CAPTURE_NORMAL = 1;
+const int CAPTURE_DROPPED = 2;
+
+const int RETURN_TIMEOUT = 1;
+const int RETURN_DROPPED = 2;
+const int RETURN_DAMAGE = 3;
+const int RETURN_SPEEDRUN = 4;
+const int RETURN_NEEDKILL = 5;
+
+bool ctf_Stalemate_Customize(entity this, entity client);
+
+void ctf_Handle_Throw(entity player, entity receiver, float droptype);
+
+// flag properties
+#define ctf_spawnorigin dropped_origin
+bool ctf_stalemate; // indicates that a stalemate is active
+float ctf_captimerecord; // record time for capturing the flag
+.float ctf_pickuptime;
+.float ctf_droptime;
+.int ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
+.entity ctf_dropper; // don't allow spam of dropping the flag
+.int max_flag_health;
+.float next_take_time;
+.bool ctf_flagdamaged_byworld;
+int ctf_teams;
+.entity enemy; // when flag is back in the base, it remembers last player who carried/touched the flag, useful to bots
+
+// passing/throwing properties
+.float pass_distance;
+.entity pass_sender;
+.entity pass_target;
+.float throw_antispam;
+.float throw_prevtime;
+.int throw_count;
+
+// CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
+.bool ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
+float ctf_captureshield_min_negscore; // punish at -20 points
+float ctf_captureshield_max_ratio; // punish at most 30% of each team
+float ctf_captureshield_force; // push force of the shield
+
+// 1 flag ctf
+bool ctf_oneflag; // indicates whether or not a neutral flag has been found
+
+// bot player logic
+const int HAVOCBOT_CTF_ROLE_NONE = 0;
+const int HAVOCBOT_CTF_ROLE_DEFENSE = 2;
+const int HAVOCBOT_CTF_ROLE_MIDDLE = 4;
+const int HAVOCBOT_CTF_ROLE_OFFENSE = 8;
+const int HAVOCBOT_CTF_ROLE_CARRIER = 16;
+const int HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
+const int HAVOCBOT_CTF_ROLE_ESCORT = 64;
+
+.bool havocbot_cantfindflag;
+
+void havocbot_role_ctf_setrole(entity bot, int role);
+
+// team checking
+#define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
+#define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
+#endif
+
+const int CTF_RED_FLAG_TAKEN                   = 1;
+const int CTF_RED_FLAG_LOST                            = 2;
+const int CTF_RED_FLAG_CARRYING                        = 3;
+const int CTF_BLUE_FLAG_TAKEN                  = 4;
+const int CTF_BLUE_FLAG_LOST                   = 8;
+const int CTF_BLUE_FLAG_CARRYING               = 12;
+const int CTF_YELLOW_FLAG_TAKEN                        = 16;
+const int CTF_YELLOW_FLAG_LOST                 = 32;
+const int CTF_YELLOW_FLAG_CARRYING             = 48;
+const int CTF_PINK_FLAG_TAKEN                  = 64;
+const int CTF_PINK_FLAG_LOST                   = 128;
+const int CTF_PINK_FLAG_CARRYING               = 192;
+const int CTF_NEUTRAL_FLAG_TAKEN               = 256;
+const int CTF_NEUTRAL_FLAG_LOST                        = 512;
+const int CTF_NEUTRAL_FLAG_CARRYING            = 768;
+const int CTF_FLAG_NEUTRAL                             = 2048;
+const int CTF_SHIELDED                                 = 4096;
+const int CTF_STALEMATE                                        = 8192;
diff --git a/qcsrc/common/gamemodes/gamemode/cts/_mod.inc b/qcsrc/common/gamemodes/gamemode/cts/_mod.inc
new file mode 100644 (file)
index 0000000..ab0d8a4
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/cts/cts.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/cts/_mod.qh b/qcsrc/common/gamemodes/gamemode/cts/_mod.qh
new file mode 100644 (file)
index 0000000..a20b5c3
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/cts/cts.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/cts/cts.qc b/qcsrc/common/gamemodes/gamemode/cts/cts.qc
new file mode 100644 (file)
index 0000000..12319c2
--- /dev/null
@@ -0,0 +1,435 @@
+#include "cts.qh"
+
+// TODO: split into sv_cts
+#ifdef SVQC
+#include <server/race.qh>
+#include <server/items.qh>
+
+float autocvar_g_cts_finish_kill_delay;
+bool autocvar_g_cts_selfdamage;
+
+// legacy bot roles
+.float race_checkpoint;
+void havocbot_role_cts(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               bool raw_touch_check = true;
+               int cp = this.race_checkpoint;
+
+               LABEL(search_racecheckpoints)
+               IL_EACH(g_racecheckpoints, true,
+               {
+                       if(it.cnt == cp || cp == -1)
+                       {
+                               // redirect bot to next goal if it touched the waypoint of an untouchable checkpoint
+                               // e.g. checkpoint in front of Stormkeep's warpzone
+                               // the same workaround is applied in Race game mode
+                               if (raw_touch_check && vdist(this.origin - it.nearestwaypoint.origin, <, 30))
+                               {
+                                       cp = race_NextCheckpoint(cp);
+                                       raw_touch_check = false;
+                                       goto search_racecheckpoints;
+                               }
+                               navigation_routerating(this, it, 1000000, 5000);
+                       }
+               });
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void cts_ScoreRules()
+{
+    GameRules_score_enabled(false);
+    GameRules_scoring(0, 0, 0, {
+        if (g_race_qualifying) {
+            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else {
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        }
+    });
+}
+
+void cts_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":cts:", mode, ":", ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+void KillIndicator_Think(entity this);
+void CTS_ClientKill(entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
+{
+    e.killindicator = spawn();
+    e.killindicator.owner = e;
+    setthink(e.killindicator, KillIndicator_Think);
+    e.killindicator.nextthink = time + (e.lip) * 0.05;
+    e.killindicator.cnt = ceil(autocvar_g_cts_finish_kill_delay);
+    e.killindicator.health = 1; // this is used to indicate that it should be silent
+    e.lip = 0;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerPhysics)
+{
+       entity player = M_ARGV(0, entity);
+       float dt = M_ARGV(1, float);
+
+       player.race_movetime_frac += dt;
+       float f = floor(player.race_movetime_frac);
+       player.race_movetime_frac -= f;
+       player.race_movetime_count += f;
+       player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
+
+#ifdef SVQC
+       if(IS_PLAYER(player))
+       {
+               if (player.race_penalty)
+                       if (time > player.race_penalty)
+                               player.race_penalty = 0;
+               if(player.race_penalty)
+               {
+                       player.velocity = '0 0 0';
+                       set_movetype(player, MOVETYPE_NONE);
+                       player.disableclientprediction = 2;
+               }
+       }
+#endif
+
+       // force kbd movement for fairness
+       float wishspeed;
+       vector wishvel;
+
+       // if record times matter
+       // ensure nothing EVIL is being done (i.e. div0_evade)
+       // this hinders joystick users though
+       // but it still gives SOME analog control
+       wishvel.x = fabs(CS(player).movement.x);
+       wishvel.y = fabs(CS(player).movement.y);
+       if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
+       {
+               wishvel.z = 0;
+               wishspeed = vlen(wishvel);
+               if(wishvel.x >= 2 * wishvel.y)
+               {
+                       // pure X motion
+                       if(CS(player).movement.x > 0)
+                               CS(player).movement_x = wishspeed;
+                       else
+                               CS(player).movement_x = -wishspeed;
+                       CS(player).movement_y = 0;
+               }
+               else if(wishvel.y >= 2 * wishvel.x)
+               {
+                       // pure Y motion
+                       CS(player).movement_x = 0;
+                       if(CS(player).movement.y > 0)
+                               CS(player).movement_y = wishspeed;
+                       else
+                               CS(player).movement_y = -wishspeed;
+               }
+               else
+               {
+                       // diagonal
+                       if(CS(player).movement.x > 0)
+                               CS(player).movement_x = M_SQRT1_2 * wishspeed;
+                       else
+                               CS(player).movement_x = -M_SQRT1_2 * wishspeed;
+                       if(CS(player).movement.y > 0)
+                               CS(player).movement_y = M_SQRT1_2 * wishspeed;
+                       else
+                               CS(player).movement_y = -M_SQRT1_2 * wishspeed;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, reset_map_global)
+{
+       float s;
+
+       Score_NicePrint(NULL);
+
+       race_ClearRecords();
+       PlayerScore_Sort(race_place, 0, 1, 0);
+
+       FOREACH_CLIENT(true, {
+               if(it.race_place)
+               {
+                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
+                       if(!s)
+                               it.race_place = 0;
+               }
+               cts_EventLog(ftos(it.race_place), it);
+       });
+
+       if(g_race_qualifying == 2)
+       {
+               g_race_qualifying = 0;
+               independent_players = 0;
+               cvar_set("fraglimit", ftos(race_fraglimit));
+               cvar_set("leadlimit", ftos(race_leadlimit));
+               cvar_set("timelimit", ftos(race_timelimit));
+               cts_ScoreRules();
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ClientConnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       race_PreparePlayer(player);
+       player.race_checkpoint = -1;
+
+       if(IS_REAL_CLIENT(player))
+       {
+               string rr = CTS_RECORD;
+
+               msg_entity = player;
+               race_send_recordtime(MSG_ONE);
+               race_send_speedaward(MSG_ONE);
+
+               speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+               speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+               race_send_speedaward_alltimebest(MSG_ONE);
+
+               float i;
+               int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+               race_send_rankings_cnt(MSG_ONE);
+               for (i = 1; i <= m; ++i)
+               {
+                       race_SendRankings(i, 0, 0, MSG_ONE);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, AbortSpeedrun)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(autocvar_g_allow_checkpoints)
+               race_PreparePlayer(player); // nice try
+}
+
+MUTATOR_HOOKFUNCTION(cts, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
+               player.frags = FRAGS_LMS_LOSER;
+       else
+               player.frags = FRAGS_SPECTATOR;
+
+       race_PreparePlayer(player);
+       player.race_checkpoint = -1;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+       entity spawn_spot = M_ARGV(1, entity);
+
+       if(spawn_spot.target == "")
+               // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+               race_PreparePlayer(player);
+
+       // if we need to respawn, do it right
+       player.race_respawn_checkpoint = player.race_checkpoint;
+       player.race_respawn_spotref = spawn_spot;
+
+       player.race_place = 0;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PutClientInServer)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(IS_PLAYER(player))
+       if(!game_stopped)
+       {
+               if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
+                       race_PreparePlayer(player);
+               else // respawn
+                       race_RetractPlayer(player);
+
+               race_AbandonRaceCheck(player);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       frag_target.respawn_flags |= RESPAWN_FORCE;
+       race_AbandonRaceCheck(frag_target);
+}
+
+MUTATOR_HOOKFUNCTION(cts, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       bot.havocbot_role = havocbot_role_cts;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, GetPressedKeys)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
+       {
+               if (!player.stored_netname)
+                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
+               if(player.stored_netname != player.netname)
+               {
+                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
+                       strcpy(player.stored_netname, player.netname);
+               }
+       }
+
+       if (!IS_OBSERVER(player))
+       {
+               if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
+               {
+                       speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
+                       speedaward_holder = player.netname;
+                       speedaward_uid = player.crypto_idfp;
+                       speedaward_lastupdate = time;
+               }
+               if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
+               {
+                       string rr = CTS_RECORD;
+                       race_send_speedaward(MSG_ALL);
+                       speedaward_lastsent = speedaward_speed;
+                       if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+                       {
+                               speedaward_alltimebest = speedaward_speed;
+                               speedaward_alltimebest_holder = speedaward_holder;
+                               speedaward_alltimebest_uid = speedaward_uid;
+                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
+                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
+                               race_send_speedaward_alltimebest(MSG_ALL);
+                       }
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidThrowCurrentWeapon)
+{
+       // no weapon dropping in CTS
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, FilterItem)
+{
+       entity item = M_ARGV(0, entity);
+
+       if (Item_IsLoot(item))
+       {
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, Damage_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);
+
+       if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL.m_id)
+       if(!autocvar_g_cts_selfdamage)
+       {
+               frag_damage = 0;
+               M_ARGV(4, float) = frag_damage;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidPlayerScore_Clear)
+{
+       return true; // in CTS, you don't lose score by observing
+}
+
+MUTATOR_HOOKFUNCTION(cts, GetRecords)
+{
+       int record_page = M_ARGV(0, int);
+       string ret_string = M_ARGV(1, string);
+
+       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+       {
+               if(MapInfo_Get_ByID(i))
+               {
+                       float r = race_readTime(MapInfo_Map_bspname, 1);
+
+                       if(!r)
+                               continue;
+
+                       string h = race_readName(MapInfo_Map_bspname, 1);
+                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
+               }
+       }
+
+       M_ARGV(1, string) = ret_string;
+}
+
+void ClientKill_Now(entity this);
+MUTATOR_HOOKFUNCTION(cts, ClientKill)
+{
+    entity player = M_ARGV(0, entity);
+
+       M_ARGV(1, float) = 0; // kill delay
+
+       if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
+       {
+               delete(player.killindicator);
+               player.killindicator = NULL;
+
+               ClientKill_Now(player); // allow instant kill in this case
+               return;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(autocvar_g_cts_finish_kill_delay)
+               CTS_ClientKill(player);
+}
+
+MUTATOR_HOOKFUNCTION(cts, HideTeamNagger)
+{
+       return true; // doesn't work so well (but isn't cts a teamless mode?)
+}
+
+MUTATOR_HOOKFUNCTION(cts, FixClientCvars)
+{
+       entity player = M_ARGV(0, entity);
+
+       stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
+}
+
+MUTATOR_HOOKFUNCTION(cts, WantWeapon)
+{
+       M_ARGV(1, float) = (M_ARGV(0, entity) == WEP_SHOTGUN); // want weapon = weapon info
+       M_ARGV(3, bool) = true; // want mutator blocked
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidDropCurrentWeapon)
+{
+       return true;
+}
+
+void cts_Initialize()
+{
+       cts_ScoreRules();
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/cts/cts.qh b/qcsrc/common/gamemodes/gamemode/cts/cts.qh
new file mode 100644 (file)
index 0000000..516e903
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#include <server/race.qh>
+
+void cts_Initialize();
+
+REGISTER_MUTATOR(cts, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               g_race_qualifying = true;
+               independent_players = 1;
+        GameRules_limit_score(0);
+        GameRules_limit_lead(0);
+
+               cts_Initialize();
+       }
+       return 0;
+}
+
+// scores
+const float ST_CTS_LAPS = 1;
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/deathmatch/_mod.inc b/qcsrc/common/gamemodes/gamemode/deathmatch/_mod.inc
new file mode 100644 (file)
index 0000000..2403aad
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/deathmatch/_mod.qh b/qcsrc/common/gamemodes/gamemode/deathmatch/_mod.qh
new file mode 100644 (file)
index 0000000..2135ec9
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qc b/qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qc
new file mode 100644 (file)
index 0000000..5cd7ca1
--- /dev/null
@@ -0,0 +1,10 @@
+#include "deathmatch.qh"
+
+// TODO: sv_deathmatch?
+#ifdef SVQC
+MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qh b/qcsrc/common/gamemodes/gamemode/deathmatch/deathmatch.qh
new file mode 100644 (file)
index 0000000..fdae278
--- /dev/null
@@ -0,0 +1,10 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+REGISTER_MUTATOR(dm, false)
+{
+    MUTATOR_STATIC();
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/domination/_mod.inc b/qcsrc/common/gamemodes/gamemode/domination/_mod.inc
new file mode 100644 (file)
index 0000000..95d00b3
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/domination/domination.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/domination/_mod.qh b/qcsrc/common/gamemodes/gamemode/domination/_mod.qh
new file mode 100644 (file)
index 0000000..e57c30e
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/domination/domination.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/domination/domination.qc b/qcsrc/common/gamemodes/gamemode/domination/domination.qc
new file mode 100644 (file)
index 0000000..3faa4a8
--- /dev/null
@@ -0,0 +1,673 @@
+#include "domination.qh"
+
+// TODO: sv_domination
+#ifdef SVQC
+#include <server/teamplay.qh>
+
+bool g_domination;
+
+int autocvar_g_domination_default_teams;
+bool autocvar_g_domination_disable_frags;
+int autocvar_g_domination_point_amt;
+bool autocvar_g_domination_point_fullbright;
+float autocvar_g_domination_round_timelimit;
+float autocvar_g_domination_warmup;
+float autocvar_g_domination_point_rate;
+int autocvar_g_domination_teams_override;
+
+void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":dom:", mode, ":", ftos(team_before), ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+void set_dom_state(entity e)
+{
+       STAT(DOM_TOTAL_PPS, e) = total_pps;
+       STAT(DOM_PPS_RED, e) = pps_red;
+       STAT(DOM_PPS_BLUE, e) = pps_blue;
+       if(domination_teams >= 3)
+               STAT(DOM_PPS_YELLOW, e) = pps_yellow;
+       if(domination_teams >= 4)
+               STAT(DOM_PPS_PINK, e) = pps_pink;
+}
+
+void dompoint_captured(entity this)
+{
+       float old_delay, old_team, real_team;
+
+       // now that the delay has expired, switch to the latest team to lay claim to this point
+       entity head = this.owner;
+
+       real_team = this.cnt;
+       this.cnt = -1;
+
+       dom_EventLog("taken", this.team, this.dmg_inflictor);
+       this.dmg_inflictor = NULL;
+
+       this.goalentity = head;
+       this.model = head.mdl;
+       this.modelindex = head.dmg;
+       this.skin = head.skin;
+
+       float points, wait_time;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = this.frags;
+       if (autocvar_g_domination_point_rate)
+               wait_time = autocvar_g_domination_point_rate;
+       else
+               wait_time = this.wait;
+
+       if(domination_roundbased)
+               bprint(sprintf("^3%s^3%s\n", head.netname, this.message));
+       else
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_DOMINATION_CAPTURE_TIME, head.netname, this.message, points, wait_time);
+
+       if(this.enemy.playerid == this.enemy_playerid)
+               GameRules_scoring_add(this.enemy, DOM_TAKES, 1);
+       else
+               this.enemy = NULL;
+
+       if (head.noise != "")
+               if(this.enemy)
+                       _sound(this.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
+               else
+                       _sound(this, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
+       if (head.noise1 != "")
+               play2all(head.noise1);
+
+       this.delay = time + wait_time;
+
+       // do trigger work
+       old_delay = this.delay;
+       old_team = this.team;
+       this.team = real_team;
+       this.delay = 0;
+       SUB_UseTargets (this, this, NULL);
+       this.delay = old_delay;
+       this.team = old_team;
+
+       entity msg = WP_DomNeut;
+       switch(real_team)
+       {
+               case NUM_TEAM_1: msg = WP_DomRed; break;
+               case NUM_TEAM_2: msg = WP_DomBlue; break;
+               case NUM_TEAM_3: msg = WP_DomYellow; break;
+               case NUM_TEAM_4: msg = WP_DomPink; break;
+       }
+
+       WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
+
+       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+       IL_EACH(g_dompoints, true,
+       {
+               if (autocvar_g_domination_point_amt)
+                       points = autocvar_g_domination_point_amt;
+               else
+                       points = it.frags;
+               if (autocvar_g_domination_point_rate)
+                       wait_time = autocvar_g_domination_point_rate;
+               else
+                       wait_time = it.wait;
+               switch(it.goalentity.team)
+               {
+                       case NUM_TEAM_1: pps_red += points/wait_time; break;
+                       case NUM_TEAM_2: pps_blue += points/wait_time; break;
+                       case NUM_TEAM_3: pps_yellow += points/wait_time; break;
+                       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);
+
+       this.captime = time;
+
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), { set_dom_state(it); });
+}
+
+void AnimateDomPoint(entity this)
+{
+       if(this.pain_finished > time)
+               return;
+       this.pain_finished = time + this.t_width;
+       if(this.nextthink > this.pain_finished)
+               this.nextthink = this.pain_finished;
+
+       this.frame = this.frame + 1;
+       if(this.frame > this.t_length)
+               this.frame = 0;
+}
+
+void dompointthink(entity this)
+{
+       float fragamt;
+
+       this.nextthink = time + 0.1;
+
+       //this.frame = this.frame + 1;
+       //if(this.frame > 119)
+       //      this.frame = 0;
+       AnimateDomPoint(this);
+
+       // give points
+
+       if (game_stopped || this.delay > time || time < game_starttime) // game has ended, don't keep giving points
+               return;
+
+       if(autocvar_g_domination_point_rate)
+               this.delay = time + autocvar_g_domination_point_rate;
+       else
+               this.delay = time + this.wait;
+
+       // give credit to the team
+       // NOTE: this defaults to 0
+       if (!domination_roundbased)
+       if (this.goalentity.netname != "")
+       {
+               if(autocvar_g_domination_point_amt)
+                       fragamt = autocvar_g_domination_point_amt;
+               else
+                       fragamt = this.frags;
+               TeamScore_AddToTeam(this.goalentity.team, ST_SCORE, fragamt);
+               TeamScore_AddToTeam(this.goalentity.team, ST_DOM_TICKS, fragamt);
+
+               // give credit to the individual player, if he is still there
+               if (this.enemy.playerid == this.enemy_playerid)
+               {
+                       GameRules_scoring_add(this.enemy, SCORE, fragamt);
+                       GameRules_scoring_add(this.enemy, DOM_TICKS, fragamt);
+               }
+               else
+                       this.enemy = NULL;
+       }
+}
+
+void dompointtouch(entity this, entity toucher)
+{
+       if (!IS_PLAYER(toucher))
+               return;
+       if (toucher.health < 1)
+               return;
+
+       if(round_handler_IsActive() && !round_handler_IsRoundStarted())
+               return;
+
+       if(time < this.captime + 0.3)
+               return;
+
+       // only valid teams can claim it
+       entity head = find(NULL, classname, "dom_team");
+       while (head && head.team != toucher.team)
+               head = find(head, classname, "dom_team");
+       if (!head || head.netname == "" || head == this.goalentity)
+               return;
+
+       // delay capture
+
+       this.team = this.goalentity.team; // this stores the PREVIOUS team!
+
+       this.cnt = toucher.team;
+       this.owner = head; // team to switch to after the delay
+       this.dmg_inflictor = toucher;
+
+       // this.state = 1;
+       // this.delay = time + cvar("g_domination_point_capturetime");
+       //this.nextthink = time + cvar("g_domination_point_capturetime");
+       //this.think = dompoint_captured;
+
+       // go to neutral team in the mean time
+       head = find(NULL, classname, "dom_team");
+       while (head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if(head == NULL)
+               return;
+
+       WaypointSprite_UpdateSprites(this.sprite, WP_DomNeut, WP_Null, WP_Null);
+       WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, '0 1 1');
+       WaypointSprite_Ping(this.sprite);
+
+       this.goalentity = head;
+       this.model = head.mdl;
+       this.modelindex = head.dmg;
+       this.skin = head.skin;
+
+       this.enemy = toucher; // individual player scoring
+       this.enemy_playerid = toucher.playerid;
+       dompoint_captured(this);
+}
+
+void dom_controlpoint_setup(entity this)
+{
+       entity head;
+       // find the spawnfunc_dom_team representing unclaimed points
+       head = find(NULL, classname, "dom_team");
+       while(head && head.netname != "")
+               head = find(head, classname, "dom_team");
+       if (!head)
+               objerror(this, "no spawnfunc_dom_team with netname \"\" found\n");
+
+       // copy important properties from spawnfunc_dom_team entity
+       this.goalentity = head;
+       _setmodel(this, head.mdl); // precision already set
+       this.skin = head.skin;
+
+       this.cnt = -1;
+
+       if(this.message == "")
+               this.message = " has captured a control point";
+
+       if(this.frags <= 0)
+               this.frags = 1;
+       if(this.wait <= 0)
+               this.wait = 5;
+
+       float points, waittime;
+       if (autocvar_g_domination_point_amt)
+               points = autocvar_g_domination_point_amt;
+       else
+               points = this.frags;
+       if (autocvar_g_domination_point_rate)
+               waittime = autocvar_g_domination_point_rate;
+       else
+               waittime = this.wait;
+
+       total_pps += points/waittime;
+
+       if(!this.t_width)
+               this.t_width = 0.02; // frame animation rate
+       if(!this.t_length)
+               this.t_length = 239; // maximum frame
+
+       setthink(this, dompointthink);
+       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');
+       droptofloor(this);
+
+       waypoint_spawnforitem(this);
+       WaypointSprite_SpawnFixed(WP_DomNeut, this.origin + '0 0 32', this, sprite, RADARICON_DOMPOINT);
+}
+
+float total_controlpoints;
+void Domination_count_controlpoints()
+{
+       total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
+       IL_EACH(g_dompoints, true,
+       {
+               ++total_controlpoints;
+               redowned += (it.goalentity.team == NUM_TEAM_1);
+               blueowned += (it.goalentity.team == NUM_TEAM_2);
+               yellowowned += (it.goalentity.team == NUM_TEAM_3);
+               pinkowned += (it.goalentity.team == NUM_TEAM_4);
+       });
+}
+
+float Domination_GetWinnerTeam()
+{
+       float winner_team = 0;
+       if(redowned == total_controlpoints)
+               winner_team = NUM_TEAM_1;
+       if(blueowned == total_controlpoints)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowowned == total_controlpoints)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkowned == total_controlpoints)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no control points left?
+}
+
+#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
+float Domination_CheckWinner()
+{
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+
+               game_stopped = true;
+               round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+               return 1;
+       }
+
+       Domination_count_controlpoints();
+
+       float winner_team = Domination_GetWinnerTeam();
+
+       if(winner_team == -1)
+               return 0;
+
+       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_DOM_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);
+       }
+
+       game_stopped = true;
+       round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+
+       return 1;
+}
+
+float Domination_CheckPlayers()
+{
+       return 1;
+}
+
+void Domination_RoundStart()
+{
+       FOREACH_CLIENT(IS_PLAYER(it), { it.player_blocked = false; });
+}
+
+//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))
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
+               havocbot_goalrating_items(this, 8000, this.origin, 8000);
+               //havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
+               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
+{
+       // fallback?
+       M_ARGV(0, float) = domination_teams;
+       string ret_string = "dom_team";
+
+       entity head = find(NULL, classname, ret_string);
+       while(head)
+       {
+               if(head.netname != "")
+               {
+                       switch(head.team)
+                       {
+                               case NUM_TEAM_1: c1 = 0; break;
+                               case NUM_TEAM_2: c2 = 0; break;
+                               case NUM_TEAM_3: c3 = 0; break;
+                               case NUM_TEAM_4: c4 = 0; break;
+                       }
+               }
+
+               head = find(head, classname, ret_string);
+       }
+
+       M_ARGV(1, string) = string_null;
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(dom, reset_map_players)
+{
+       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               PutClientInServer(it);
+               if(domination_roundbased)
+                       it.player_blocked = 1;
+               if(IS_REAL_CLIENT(it))
+                       set_dom_state(it);
+       });
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(dom, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(domination_roundbased)
+       if(!round_handler_IsRoundStarted())
+               player.player_blocked = 1;
+       else
+               player.player_blocked = 0;
+}
+
+MUTATOR_HOOKFUNCTION(dom, ClientConnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       set_dom_state(player);
+}
+
+MUTATOR_HOOKFUNCTION(dom, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       bot.havocbot_role = havocbot_role_dom;
+       return true;
+}
+
+/*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+Control point for Domination gameplay.
+*/
+spawnfunc(dom_controlpoint)
+{
+       if(!g_domination)
+       {
+               delete(this);
+               return;
+       }
+       setthink(this, dom_controlpoint_setup);
+       this.nextthink = time + 0.1;
+       this.reset = dom_controlpoint_setup;
+
+       if(!this.scale)
+               this.scale = 0.6;
+
+       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)
+Team declaration for Domination gameplay, this allows you to decide what team
+names and control point models are used in your map.
+
+Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+can have netname set!  The nameless team owns all control points at start.
+
+Keys:
+"netname"
+ Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+"cnt"
+ Scoreboard color of the team (for example 4 is red and 13 is blue)
+"model"
+ Model to use for control points owned by this team (for example
+ "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+ keycard)
+"skin"
+ Skin of the model to use (for team skins on a single model)
+"noise"
+ Sound to play when this team captures a point.
+ (this is a localized sound, like a small alarm or other effect)
+"noise1"
+ Narrator speech to play when this team captures a point.
+ (this is a global sound, like "Red team has captured a control point")
+*/
+
+spawnfunc(dom_team)
+{
+       if(!g_domination || autocvar_g_domination_teams_override >= 2)
+       {
+               delete(this);
+               return;
+       }
+       precache_model(this.model);
+       if (this.noise != "")
+               precache_sound(this.noise);
+       if (this.noise1 != "")
+               precache_sound(this.noise1);
+       this.classname = "dom_team";
+       _setmodel(this, this.model); // precision not needed
+       this.mdl = this.model;
+       this.dmg = this.modelindex;
+       this.model = "";
+       this.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       if(this.cnt)
+               this.team = this.cnt + 1; // WHY are these different anyway?
+}
+
+// scoreboard setup
+void ScoreRules_dom(int teams)
+{
+       if(domination_roundbased)
+       {
+           GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+            field_team(ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_DOM_TAKES, "takes", 0);
+           });
+       }
+       else
+       {
+               float sp_domticks, sp_score;
+               sp_score = sp_domticks = 0;
+               if(autocvar_g_domination_disable_frags)
+                       sp_domticks = SFL_SORT_PRIO_PRIMARY;
+               else
+                       sp_score = SFL_SORT_PRIO_PRIMARY;
+               GameRules_scoring(teams, sp_score, sp_score, {
+            field_team(ST_DOM_TICKS, "ticks", sp_domticks);
+            field(SP_DOM_TICKS, "ticks", sp_domticks);
+            field(SP_DOM_TAKES, "takes", 0);
+               });
+       }
+}
+
+// code from here on is just to support maps that don't have control point and team entities
+void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
+{
+    TC(Sound, capsound);
+    entity e = new_pure(dom_team);
+       e.netname = strzone(teamname);
+       e.cnt = teamcolor;
+       e.model = pointmodel;
+       e.skin = pointskin;
+       e.noise = strzone(Sound_fixpath(capsound));
+       e.noise1 = strzone(capnarration);
+       e.message = strzone(capmessage);
+
+       // this code is identical to spawnfunc_dom_team
+       _setmodel(e, e.model); // precision not needed
+       e.mdl = e.model;
+       e.dmg = e.modelindex;
+       e.model = "";
+       e.modelindex = 0;
+       // this would have to be changed if used in quakeworld
+       e.team = e.cnt + 1;
+
+       //eprint(e);
+}
+
+void dom_spawnpoint(vector org)
+{
+       entity e = spawn();
+       e.classname = "dom_controlpoint";
+       setthink(e, spawnfunc_dom_controlpoint);
+       e.nextthink = time;
+       setorigin(e, org);
+       spawnfunc_dom_controlpoint(e);
+}
+
+// spawn some default teams if the map is not set up for domination
+void dom_spawnteams(int teams)
+{
+    TC(int, teams);
+       dom_spawnteam(Team_ColoredFullName(NUM_TEAM_1), NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, SND_DOM_CLAIM, "", "Red team has captured a control point");
+       dom_spawnteam(Team_ColoredFullName(NUM_TEAM_2), NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, SND_DOM_CLAIM, "", "Blue team has captured a control point");
+       if(teams >= 3)
+               dom_spawnteam(Team_ColoredFullName(NUM_TEAM_3), NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, SND_DOM_CLAIM, "", "Yellow team has captured a control point");
+       if(teams >= 4)
+               dom_spawnteam(Team_ColoredFullName(NUM_TEAM_4), NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, SND_DOM_CLAIM, "", "Pink team has captured a control point");
+       dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, SND_Null, "", "");
+}
+
+void dom_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+       // if no teams are found, spawn defaults
+       if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
+       {
+               LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
+               domination_teams = autocvar_g_domination_teams_override;
+               if (domination_teams < 2)
+                       domination_teams = autocvar_g_domination_default_teams;
+               domination_teams = bound(2, domination_teams, 4);
+               dom_spawnteams(domination_teams);
+       }
+
+       CheckAllowedTeams(NULL);
+       //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
+
+       int teams = 0;
+       if(c1 >= 0) teams |= BIT(0);
+       if(c2 >= 0) teams |= BIT(1);
+       if(c3 >= 0) teams |= BIT(2);
+       if(c4 >= 0) teams |= BIT(3);
+       domination_teams = teams;
+
+       domination_roundbased = autocvar_g_domination_roundbased;
+
+       ScoreRules_dom(domination_teams);
+
+       if(domination_roundbased)
+       {
+               round_handler_Spawn(Domination_CheckPlayers, Domination_CheckWinner, Domination_RoundStart);
+               round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+       }
+}
+
+void dom_Initialize()
+{
+       g_domination = true;
+       InitializeEntity(NULL, dom_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/domination/domination.qh b/qcsrc/common/gamemodes/gamemode/domination/domination.qh
new file mode 100644 (file)
index 0000000..f4faf50
--- /dev/null
@@ -0,0 +1,54 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.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_STATIC();
+       MUTATOR_ONADD
+       {
+               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;
+
+               GameRules_teams(true);
+        GameRules_limit_score(fraglimit_override);
+        GameRules_limit_lead(autocvar_g_domination_point_leadlimit);
+
+               dom_Initialize();
+       }
+       return 0;
+}
+
+// score rule declarations
+const float ST_DOM_TICKS = 1;
+const float ST_DOM_CAPS = 1;
+
+// pps: points per second
+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(); }
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/freezetag/_mod.inc b/qcsrc/common/gamemodes/gamemode/freezetag/_mod.inc
new file mode 100644 (file)
index 0000000..aff5bf9
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/freezetag/freezetag.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/freezetag/_mod.qh b/qcsrc/common/gamemodes/gamemode/freezetag/_mod.qh
new file mode 100644 (file)
index 0000000..1bc2182
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/freezetag/freezetag.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc b/qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc
new file mode 100644 (file)
index 0000000..cceff48
--- /dev/null
@@ -0,0 +1,588 @@
+#include "freezetag.qh"
+
+// TODO: sv_freezetag
+#ifdef SVQC
+float autocvar_g_freezetag_frozen_maxtime;
+float autocvar_g_freezetag_revive_clearspeed;
+float autocvar_g_freezetag_round_timelimit;
+//int autocvar_g_freezetag_teams;
+int autocvar_g_freezetag_teams_override;
+float autocvar_g_freezetag_warmup;
+
+void freezetag_count_alive_players()
+{
+       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               switch(it.team)
+               {
+                       case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
+                       case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
+                       case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
+                       case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
+               }
+       });
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               STAT(REDALIVE, it) = redalive;
+               STAT(BLUEALIVE, it) = bluealive;
+               STAT(YELLOWALIVE, it) = yellowalive;
+               STAT(PINKALIVE, it) = pinkalive;
+       });
+
+       eliminatedPlayers.SendFlags |= 1;
+}
+#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
+
+float freezetag_CheckTeams()
+{
+       static float prev_missing_teams_mask;
+       if(FREEZETAG_ALIVE_TEAMS_OK())
+       {
+               if(prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               return 1;
+       }
+       if(total_players == 0)
+       {
+               if(prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               return 0;
+       }
+       int missing_teams_mask = 0;
+       if(freezetag_teams & BIT(0))
+               missing_teams_mask += (!redalive) * 1;
+       if(freezetag_teams & BIT(1))
+               missing_teams_mask += (!bluealive) * 2;
+       if(freezetag_teams & BIT(2))
+               missing_teams_mask += (!yellowalive) * 4;
+       if(freezetag_teams & BIT(3))
+               missing_teams_mask += (!pinkalive) * 8;
+       if(prev_missing_teams_mask != missing_teams_mask)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
+               prev_missing_teams_mask = missing_teams_mask;
+       }
+       return 0;
+}
+
+float freezetag_getWinnerTeam()
+{
+       float winner_team = 0;
+       if(redalive >= 1)
+               winner_team = NUM_TEAM_1;
+       if(bluealive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_2;
+       }
+       if(yellowalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_3;
+       }
+       if(pinkalive >= 1)
+       {
+               if(winner_team) return 0;
+               winner_team = NUM_TEAM_4;
+       }
+       if(winner_team)
+               return winner_team;
+       return -1; // no player left
+}
+
+void nades_Clear(entity);
+void nades_GiveBonus(entity player, float score);
+
+float freezetag_CheckWinner()
+{
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       it.freezetag_frozen_timeout = 0;
+                       nades_Clear(it);
+               });
+               game_stopped = true;
+               round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+               return 1;
+       }
+
+       if(FREEZETAG_ALIVE_TEAMS() > 1)
+               return 0;
+
+       int winner_team = freezetag_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_SCORE, +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);
+       }
+
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               it.freezetag_frozen_timeout = 0;
+               nades_Clear(it);
+       });
+
+       game_stopped = true;
+       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+       return 1;
+}
+
+entity freezetag_LastPlayerForTeam(entity this)
+{
+       entity last_pl = NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+               if(it.health >= 1)
+               if(!STAT(FROZEN, it))
+               if(SAME_TEAM(it, this))
+               if(!last_pl)
+                       last_pl = it;
+               else
+                       return NULL;
+       });
+       return last_pl;
+}
+
+void freezetag_LastPlayerForTeam_Notify(entity this)
+{
+       if(round_handler_IsActive())
+       if(round_handler_IsRoundStarted())
+       {
+               entity pl = freezetag_LastPlayerForTeam(this);
+               if(pl)
+                       Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+       }
+}
+
+void freezetag_Add_Score(entity targ, entity attacker)
+{
+       if(attacker == targ)
+       {
+               // you froze your own dumb targ
+               // counted as "suicide" already
+               GameRules_scoring_add(targ, SCORE, -1);
+       }
+       else if(IS_PLAYER(attacker))
+       {
+               // got frozen by an enemy
+               // counted as "kill" and "death" already
+               GameRules_scoring_add(targ, SCORE, -1);
+               GameRules_scoring_add(attacker, SCORE, +1);
+       }
+       // else nothing - got frozen by the game type rules themselves
+}
+
+void freezetag_Freeze(entity targ, entity attacker)
+{
+       if(STAT(FROZEN, targ))
+               return;
+
+       if(autocvar_g_freezetag_frozen_maxtime > 0)
+               targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
+
+       Freeze(targ, 0, 1, true);
+
+       freezetag_count_alive_players();
+
+       freezetag_Add_Score(targ, attacker);
+}
+
+void freezetag_Unfreeze(entity this)
+{
+       this.freezetag_frozen_time = 0;
+       this.freezetag_frozen_timeout = 0;
+
+       Unfreeze(this);
+}
+
+float freezetag_isEliminated(entity e)
+{
+       if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
+               return true;
+       return false;
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+void(entity this) havocbot_role_ft_freeing;
+void(entity this) havocbot_role_ft_offense;
+
+void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
+{
+       float t;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+               if (STAT(FROZEN, it) == 1)
+               {
+                       if(vdist(it.origin - org, >, sradius))
+                               continue;
+                       navigation_routerating(this, it, ratingscale, 2000);
+               }
+               else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
+               {
+                       // If teamate is not frozen still seek them out as fight better
+                       // in a group.
+                       t = 0.2 * 150 / (this.health + this.armorvalue);
+                       navigation_routerating(this, it, t * ratingscale, 2000);
+               }
+       });
+}
+
+void havocbot_role_ft_offense(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + random() * 10 + 20;
+
+       // Count how many players on team are unfrozen.
+       int unfrozen = 0;
+       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
+
+       // If only one left on team or if role has timed out then start trying to free players.
+       if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
+       {
+               LOG_TRACE("changing role to freeing");
+               this.havocbot_role = havocbot_role_ft_freeing;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
+               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_ft_freeing(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + random() * 10 + 20;
+
+       if (time > this.havocbot_role_timeout)
+       {
+               LOG_TRACE("changing role to offense");
+               this.havocbot_role = havocbot_role_ft_offense;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_items(this, 8000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
+               havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+void ft_RemovePlayer(entity this)
+{
+       this.health = 0; // neccessary to update correctly alive stats
+       if(!STAT(FROZEN, this))
+               freezetag_LastPlayerForTeam_Notify(this);
+       freezetag_Unfreeze(this);
+       freezetag_count_alive_players();
+}
+
+MUTATOR_HOOKFUNCTION(ft, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       ft_RemovePlayer(player);
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       ft_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_deathtype = M_ARGV(3, float);
+
+       if(round_handler_IsActive())
+       if(round_handler_CountdownRunning())
+       {
+               if(STAT(FROZEN, frag_target))
+                       freezetag_Unfreeze(frag_target);
+               freezetag_count_alive_players();
+               return true; // let the player die so that he can respawn whenever he wants
+       }
+
+       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+               || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
+       {
+               // let the player die, he will be automatically frozen when he respawns
+               if(STAT(FROZEN, frag_target) != 1)
+               {
+                       freezetag_Add_Score(frag_target, frag_attacker);
+                       freezetag_count_alive_players();
+                       freezetag_LastPlayerForTeam_Notify(frag_target);
+               }
+               else
+                       freezetag_Unfreeze(frag_target); // remove ice
+               frag_target.health = 0; // Unfreeze resets health
+               frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
+               return true;
+       }
+
+       if(STAT(FROZEN, frag_target))
+               return true;
+
+       freezetag_Freeze(frag_target, frag_attacker);
+       freezetag_LastPlayerForTeam_Notify(frag_target);
+
+       if(frag_attacker == frag_target || frag_attacker == NULL)
+       {
+               if(IS_PLAYER(frag_target))
+                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
+       }
+       else
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+               return true; // do nothing, round is starting right now
+
+       if(player.freezetag_frozen_timeout == -2) // player was dead
+       {
+               freezetag_Freeze(player, NULL);
+               return true;
+       }
+
+       freezetag_count_alive_players();
+
+       if(round_handler_IsActive())
+       if(round_handler_IsRoundStarted())
+       {
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
+               freezetag_Freeze(player, NULL);
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, reset_map_players)
+{
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               CS(it).killcount = 0;
+               it.freezetag_frozen_timeout = -1;
+               PutClientInServer(it);
+               it.freezetag_frozen_timeout = 0;
+       });
+       freezetag_count_alive_players();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       M_ARGV(2, float) = 0; // no frags counted in Freeze Tag
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
+{
+       if(game_stopped)
+               return true;
+
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+               return true;
+
+       int n;
+       entity o = NULL;
+       entity player = M_ARGV(0, entity);
+       //if(STAT(FROZEN, player))
+       //if(player.freezetag_frozen_timeout > 0 && time < player.freezetag_frozen_timeout)
+               //player.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (player.freezetag_frozen_timeout - time) / (player.freezetag_frozen_timeout - player.freezetag_frozen_time);
+
+       if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
+               n = -1;
+       else
+       {
+               vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+               n = 0;
+               FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
+                       if(STAT(FROZEN, it) == 0)
+                       if(!IS_DEAD(it))
+                       if(SAME_TEAM(it, player))
+                       if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
+                       {
+                               if(!o)
+                                       o = it;
+                               if(STAT(FROZEN, player) == 1)
+                                       it.reviving = true;
+                               ++n;
+                       }
+               });
+
+       }
+
+       if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
+       {
+               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+
+               if(STAT(REVIVE_PROGRESS, player) >= 1)
+               {
+                       freezetag_Unfreeze(player);
+                       freezetag_count_alive_players();
+
+                       if(n == -1)
+                       {
+                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
+                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
+                               return true;
+                       }
+
+                       // EVERY team mate nearby gets a point (even if multiple!)
+                       FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
+                               GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
+                               GameRules_scoring_add(it, SCORE, +1);
+                               nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
+                       });
+
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, o.netname);
+               }
+
+               FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
+                       STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
+                       it.reviving = false;
+               });
+       }
+       else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
+       {
+               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
+               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+       }
+       else if(!n && !STAT(FROZEN, player))
+       {
+               STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, SetStartItems)
+{
+       start_items &= ~IT_UNLIMITED_AMMO;
+       //start_health       = warmup_start_health       = cvar("g_lms_start_health");
+       //start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
+       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
+       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
+       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
+       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
+}
+
+MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       if (!IS_DEAD(bot))
+       {
+               if (random() < 0.5)
+                       bot.havocbot_role = havocbot_role_ft_freeing;
+               else
+                       bot.havocbot_role = havocbot_role_ft_offense;
+       }
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(0, float) = freezetag_teams;
+}
+
+MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
+{
+       // most weapons arena
+       if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+               M_ARGV(0, string) = "most";
+}
+
+MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
+{
+       entity frag_attacker = M_ARGV(0, entity);
+       entity frag_target = M_ARGV(1, entity);
+       //float frag_deathtype = M_ARGV(2, float);
+       int kill_count_to_attacker = M_ARGV(3, int);
+       int kill_count_to_target = M_ARGV(4, int);
+
+       if(STAT(FROZEN, frag_target))
+               return; // target was already frozen, so this is just pushing them off the cliff
+
+       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
+       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+
+       return true;
+}
+
+void freezetag_Initialize()
+{
+       freezetag_teams = autocvar_g_freezetag_teams_override;
+       if(freezetag_teams < 2)
+               freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
+
+       freezetag_teams = BITS(bound(2, freezetag_teams, 4));
+       GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+       });
+
+       round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
+       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+
+       EliminatedPlayers_Init(freezetag_isEliminated);
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qh b/qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qh
new file mode 100644 (file)
index 0000000..ed38ae5
--- /dev/null
@@ -0,0 +1,37 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.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_STATIC();
+       MUTATOR_ONADD
+       {
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_freezetag_team_spawns);
+        GameRules_limit_score(autocvar_g_freezetag_point_limit);
+        GameRules_limit_lead(autocvar_g_freezetag_point_leadlimit);
+
+               freezetag_Initialize();
+       }
+       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
diff --git a/qcsrc/common/gamemodes/gamemode/invasion/_mod.inc b/qcsrc/common/gamemodes/gamemode/invasion/_mod.inc
new file mode 100644 (file)
index 0000000..905aa06
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/invasion/invasion.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/invasion/_mod.qh b/qcsrc/common/gamemodes/gamemode/invasion/_mod.qh
new file mode 100644 (file)
index 0000000..d8e8d22
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/invasion/invasion.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/invasion/invasion.qc b/qcsrc/common/gamemodes/gamemode/invasion/invasion.qc
new file mode 100644 (file)
index 0000000..d6f9860
--- /dev/null
@@ -0,0 +1,606 @@
+#include "invasion.qh"
+
+// TODO: sv_invasion
+#ifdef SVQC
+#include <common/monsters/sv_spawn.qh>
+#include <common/monsters/sv_spawner.qh>
+#include <common/monsters/sv_monsters.qh>
+
+#include <server/teamplay.qh>
+
+IntrusiveList g_invasion_roundends;
+IntrusiveList g_invasion_waves;
+IntrusiveList g_invasion_spawns;
+STATIC_INIT(g_invasion)
+{
+       g_invasion_roundends = IL_NEW();
+       g_invasion_waves = IL_NEW();
+       g_invasion_spawns = IL_NEW();
+}
+
+float autocvar_g_invasion_round_timelimit;
+float autocvar_g_invasion_spawnpoint_spawn_delay;
+float autocvar_g_invasion_warmup;
+int autocvar_g_invasion_monster_count;
+bool autocvar_g_invasion_zombies_only;
+float autocvar_g_invasion_spawn_delay;
+
+bool victent_present;
+.bool inv_endreached;
+
+bool inv_warning_shown; // spammy
+
+void target_invasion_roundend_use(entity this, entity actor, entity trigger)
+{
+       if(!IS_PLAYER(actor)) { return; }
+
+       actor.inv_endreached = true;
+
+       int plnum = 0;
+       int realplnum = 0;
+       // let's not count bots
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
+               ++realplnum;
+               if(it.inv_endreached)
+                       ++plnum;
+       });
+       if(plnum < ceil(realplnum * min(1, this.count))) // 70% of players
+               return;
+
+       this.winning = true;
+}
+
+spawnfunc(target_invasion_roundend)
+{
+       if(!g_invasion) { delete(this); return; }
+
+       victent_present = true; // a victory entity is present, we don't need to rely on monster count TODO: merge this with the intrusive list (can check empty)
+
+       if(!this.count) { this.count = 0.7; } // require at least 70% of the players to reach the end before triggering victory
+
+       this.use = target_invasion_roundend_use;
+
+       IL_PUSH(g_invasion_roundends, this);
+}
+
+spawnfunc(invasion_wave)
+{
+       if(!g_invasion) { delete(this); return; }
+
+       IL_PUSH(g_invasion_waves, this);
+}
+
+spawnfunc(invasion_spawnpoint)
+{
+       if(!g_invasion) { delete(this); return; }
+
+       this.classname = "invasion_spawnpoint";
+       IL_PUSH(g_invasion_spawns, this);
+}
+
+void ClearWinners();
+
+// Invasion stage mode winning condition: If the attackers triggered a round end (by fulfilling all objectives)
+// they win.
+int WinningCondition_Invasion()
+{
+       WinningConditionHelper(NULL); // set worldstatus
+
+       int status = WINNING_NO;
+
+       if(autocvar_g_invasion_type == INV_TYPE_STAGE)
+       {
+               SetWinners(inv_endreached, true);
+
+               int found = 0;
+               IL_EACH(g_invasion_roundends, true,
+               {
+                       ++found;
+                       if(it.winning)
+                       {
+                               bprint("Invasion: round completed.\n");
+                               // winners already set (TODO: teamplay support)
+
+                               status = WINNING_YES;
+                               break;
+                       }
+               });
+
+               if(!found)
+                       status = WINNING_YES; // just end it? TODO: should warn mapper!
+       }
+       else if(autocvar_g_invasion_type == INV_TYPE_HUNT)
+       {
+               ClearWinners();
+
+               int found = 0; // NOTE: this ends the round if no monsters are placed
+               IL_EACH(g_monsters, !(it.spawnflags & MONSTERFLAG_RESPAWNED),
+               {
+                       ++found;
+               });
+
+               if(found <= 0)
+               {
+                       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
+                       {
+                               it.winning = true;
+                       });
+                       status = WINNING_YES;
+               }
+       }
+
+       return status;
+}
+
+Monster invasion_PickMonster(int supermonster_count)
+{
+       RandomSelection_Init();
+
+       FOREACH(Monsters, it != MON_Null,
+       {
+               if((it.spawnflags & MON_FLAG_HIDDEN) || (it.spawnflags & MONSTER_TYPE_PASSIVE) || (it.spawnflags & MONSTER_TYPE_FLY) || (it.spawnflags & MONSTER_TYPE_SWIM) ||
+                       (it.spawnflags & MONSTER_SIZE_QUAKE) || ((it.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1))
+                       continue;
+               if(autocvar_g_invasion_zombies_only && !(it.spawnflags & MONSTER_TYPE_UNDEAD))
+                       continue;
+        RandomSelection_AddEnt(it, 1, 1);
+       });
+
+       return RandomSelection_chosen_ent;
+}
+
+entity invasion_PickSpawn()
+{
+       RandomSelection_Init();
+
+       IL_EACH(g_invasion_spawns, true,
+       {
+               RandomSelection_AddEnt(it, 1, ((time < it.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
+               it.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
+       });
+
+       return RandomSelection_chosen_ent;
+}
+
+entity invasion_GetWaveEntity(int wavenum)
+{
+       IL_EACH(g_invasion_waves, it.cnt == wavenum,
+       {
+               return it; // found one
+       });
+
+       // if no specific one is found, find the last existing wave ent
+       entity best = NULL;
+       IL_EACH(g_invasion_waves, it.cnt <= wavenum,
+       {
+               if(!best || it.cnt > best.cnt)
+                       best = it;
+       });
+
+       return best;
+}
+
+void invasion_SpawnChosenMonster(Monster mon)
+{
+       entity monster;
+       entity spawn_point = invasion_PickSpawn();
+       entity wave_ent = invasion_GetWaveEntity(inv_roundcnt);
+
+       string tospawn = "";
+       if(wave_ent && wave_ent.spawnmob && wave_ent.spawnmob != "")
+       {
+               RandomSelection_Init();
+               FOREACH_WORD(wave_ent.spawnmob, true,
+               {
+                       RandomSelection_AddString(it, 1, 1);
+               });
+
+               tospawn = RandomSelection_chosen_string;
+       }
+
+       if(spawn_point == NULL)
+       {
+               if(!inv_warning_shown)
+               {
+                       inv_warning_shown = true;
+                       LOG_TRACE("Warning: couldn't find any invasion_spawnpoint spawnpoints, attempting to spawn monsters in random locations");
+               }
+               entity e = spawn();
+               setsize(e, mon.m_mins, mon.m_maxs);
+
+               if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
+                       monster = spawnmonster(e, tospawn, mon.monsterid, NULL, NULL, e.origin, false, false, 2);
+               else
+               {
+                       delete(e);
+                       return;
+               }
+       }
+       else // if spawnmob field falls through (unset), fallback to mon (relying on spawnmonster for that behaviour)
+               monster = spawnmonster(spawn(), ((spawn_point.spawnmob && spawn_point.spawnmob != "") ? spawn_point.spawnmob : tospawn), mon.monsterid, spawn_point, spawn_point, spawn_point.origin, false, false, 2);
+
+       if(!monster)
+               return;
+
+       monster.spawnshieldtime = time;
+
+       if(spawn_point)
+       {
+               if(spawn_point.target_range)
+                       monster.target_range = spawn_point.target_range;
+               monster.target2 = spawn_point.target2;
+       }
+
+       if(teamplay)
+       {
+               if(spawn_point && spawn_point.team && inv_monsters_perteam[spawn_point.team] > 0)
+                       monster.team = spawn_point.team;
+               else
+               {
+                       RandomSelection_Init();
+                       if(inv_monsters_perteam[NUM_TEAM_1] > 0) RandomSelection_AddFloat(NUM_TEAM_1, 1, 1);
+                       if(inv_monsters_perteam[NUM_TEAM_2] > 0) RandomSelection_AddFloat(NUM_TEAM_2, 1, 1);
+                       if(invasion_teams >= 3) if(inv_monsters_perteam[NUM_TEAM_3] > 0) { RandomSelection_AddFloat(NUM_TEAM_3, 1, 1); }
+                       if(invasion_teams >= 4) if(inv_monsters_perteam[NUM_TEAM_4] > 0) { RandomSelection_AddFloat(NUM_TEAM_4, 1, 1); }
+
+                       monster.team = RandomSelection_chosen_float;
+               }
+
+               monster_setupcolors(monster);
+
+               if(monster.sprite)
+               {
+                       WaypointSprite_UpdateTeamRadar(monster.sprite, RADARICON_DANGER, ((monster.team) ? Team_ColorRGB(monster.team) : '1 0 0'));
+
+                       monster.sprite.team = 0;
+                       monster.sprite.SendFlags |= 1;
+               }
+       }
+
+       if(monster.monster_attack)
+               IL_REMOVE(g_monster_targets, monster);
+       monster.monster_attack = false; // it's the player's job to kill all the monsters
+
+       if(inv_roundcnt >= inv_maxrounds)
+               monster.spawnflags |= MONSTERFLAG_MINIBOSS; // last round spawns minibosses
+}
+
+void invasion_SpawnMonsters(int supermonster_count)
+{
+       Monster chosen_monster = invasion_PickMonster(supermonster_count);
+
+       invasion_SpawnChosenMonster(chosen_monster);
+}
+
+bool Invasion_CheckWinner()
+{
+       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+       {
+               IL_EACH(g_monsters, true,
+               {
+                       Monster_Remove(it);
+               });
+               IL_CLEAR(g_monsters);
+
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
+               return 1;
+       }
+
+       float total_alive_monsters = 0, supermonster_count = 0, red_alive = 0, blue_alive = 0, yellow_alive = 0, pink_alive = 0;
+
+       IL_EACH(g_monsters, it.health > 0,
+       {
+               if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
+                       ++supermonster_count;
+               ++total_alive_monsters;
+
+               if(teamplay)
+               switch(it.team)
+               {
+                       case NUM_TEAM_1: ++red_alive; break;
+                       case NUM_TEAM_2: ++blue_alive; break;
+                       case NUM_TEAM_3: ++yellow_alive; break;
+                       case NUM_TEAM_4: ++pink_alive; break;
+               }
+       });
+
+       if((total_alive_monsters + inv_numkilled) < inv_maxspawned && inv_maxcurrent < inv_maxspawned)
+       {
+               if(time >= inv_lastcheck)
+               {
+                       invasion_SpawnMonsters(supermonster_count);
+                       inv_lastcheck = time + autocvar_g_invasion_spawn_delay;
+               }
+
+               return 0;
+       }
+
+       if(inv_numspawned < 1)
+               return 0; // nothing has spawned yet
+
+       if(teamplay)
+       {
+               if(((red_alive > 0) + (blue_alive > 0) + (yellow_alive > 0) + (pink_alive > 0)) > 1)
+                       return 0;
+       }
+       else if(inv_numkilled < inv_maxspawned)
+               return 0;
+
+       entity winner = NULL;
+       float winning_score = 0, winner_team = 0;
+
+
+       if(teamplay)
+       {
+               if(red_alive > 0) { winner_team = NUM_TEAM_1; }
+               if(blue_alive > 0)
+               if(winner_team) { winner_team = 0; }
+               else { winner_team = NUM_TEAM_2; }
+               if(yellow_alive > 0)
+               if(winner_team) { winner_team = 0; }
+               else { winner_team = NUM_TEAM_3; }
+               if(pink_alive > 0)
+               if(winner_team) { winner_team = 0; }
+               else { winner_team = NUM_TEAM_4; }
+       }
+       else
+       {
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       float cs = GameRules_scoring_add(it, KILLS, 0);
+                       if(cs > winning_score)
+                       {
+                               winning_score = cs;
+                               winner = it;
+                       }
+               });
+       }
+
+       IL_EACH(g_monsters, true,
+       {
+               Monster_Remove(it);
+       });
+       IL_CLEAR(g_monsters);
+
+       if(teamplay)
+       {
+               if(winner_team)
+               {
+                       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));
+               }
+       }
+       else if(winner)
+       {
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, winner.netname);
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_PLAYER_WIN, winner.netname);
+       }
+
+       round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
+
+       return 1;
+}
+
+bool Invasion_CheckPlayers()
+{
+       return true;
+}
+
+void Invasion_RoundStart()
+{
+       int numplayers = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               it.player_blocked = false;
+               ++numplayers;
+       });
+
+       if(inv_roundcnt < inv_maxrounds)
+               inv_roundcnt += 1; // a limiter to stop crazy counts
+
+       inv_monsterskill = inv_roundcnt + max(1, numplayers * 0.3);
+
+       inv_maxcurrent = 0;
+       inv_numspawned = 0;
+       inv_numkilled = 0;
+
+       inv_maxspawned = rint(max(autocvar_g_invasion_monster_count, autocvar_g_invasion_monster_count * (inv_roundcnt * 0.5)));
+
+       if(teamplay)
+       {
+               DistributeEvenly_Init(inv_maxspawned, invasion_teams);
+               inv_monsters_perteam[NUM_TEAM_1] = DistributeEvenly_Get(1);
+               inv_monsters_perteam[NUM_TEAM_2] = DistributeEvenly_Get(1);
+               if(invasion_teams >= 3) inv_monsters_perteam[NUM_TEAM_3] = DistributeEvenly_Get(1);
+               if(invasion_teams >= 4) inv_monsters_perteam[NUM_TEAM_4] = DistributeEvenly_Get(1);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(inv, MonsterDies)
+{
+       entity frag_target = M_ARGV(0, entity);
+       entity frag_attacker = M_ARGV(1, entity);
+
+       if(!(frag_target.spawnflags & MONSTERFLAG_RESPAWNED))
+       {
+               if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+               {
+                       inv_numkilled += 1;
+                       inv_maxcurrent -= 1;
+               }
+               if(teamplay) { inv_monsters_perteam[frag_target.team] -= 1; }
+
+               if(IS_PLAYER(frag_attacker))
+               if(SAME_TEAM(frag_attacker, frag_target)) // in non-teamplay modes, same team = same player, so this works
+                       GameRules_scoring_add(frag_attacker, KILLS, -1);
+               else
+               {
+                       GameRules_scoring_add(frag_attacker, KILLS, +1);
+                       if(teamplay)
+                               TeamScore_AddToTeam(frag_attacker.team, ST_INV_KILLS, +1);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(inv, MonsterSpawn)
+{
+       entity mon = M_ARGV(0, entity);
+       mon.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
+
+       if(autocvar_g_invasion_type == INV_TYPE_HUNT)
+               return false; // allowed
+
+       if(!(mon.spawnflags & MONSTERFLAG_SPAWNED))
+               return true;
+
+       if(!(mon.spawnflags & MONSTERFLAG_RESPAWNED))
+       {
+               inv_numspawned += 1;
+               inv_maxcurrent += 1;
+       }
+
+       mon.monster_skill = inv_monsterskill;
+
+       if((get_monsterinfo(mon.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_INVASION_SUPERMONSTER, mon.monster_name);
+}
+
+MUTATOR_HOOKFUNCTION(inv, SV_StartFrame)
+{
+       if(autocvar_g_invasion_type != INV_TYPE_ROUND)
+               return; // uses map spawned monsters
+
+       monsters_total = inv_maxspawned; // TODO: make sure numspawned never exceeds maxspawned
+       monsters_killed = inv_numkilled;
+}
+
+MUTATOR_HOOKFUNCTION(inv, PlayerRegen)
+{
+       // no regeneration in invasion, regardless of the game type
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.bot_attack)
+               IL_REMOVE(g_bot_targets, player);
+       player.bot_attack = false;
+}
+
+MUTATOR_HOOKFUNCTION(inv, Damage_Calculate)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target) && frag_attacker != frag_target)
+       {
+               frag_damage = 0;
+               frag_force = '0 0 0';
+
+               M_ARGV(4, float) = frag_damage;
+               M_ARGV(6, vector) = frag_force;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(inv, BotShouldAttack)
+{
+       entity targ = M_ARGV(1, entity);
+
+       if(!IS_MONSTER(targ))
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, SetStartItems)
+{
+       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+       {
+               start_health = 200;
+               start_armorvalue = 200;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(inv, AccuracyTargetValid)
+{
+       entity frag_target = M_ARGV(1, entity);
+
+       if(IS_MONSTER(frag_target))
+               return MUT_ACCADD_INVALID;
+       return MUT_ACCADD_INDIFFERENT;
+}
+
+MUTATOR_HOOKFUNCTION(inv, AllowMobSpawning)
+{
+       // monster spawning disabled during an invasion
+       M_ARGV(1, string) = "You cannot spawn monsters during an invasion!";
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, CheckRules_World)
+{
+       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+               return false;
+
+       M_ARGV(0, float) = WinningCondition_Invasion();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(0, float) = invasion_teams;
+}
+
+MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
+{
+       M_ARGV(0, string) = "This command does not work during an invasion!";
+       return true;
+}
+
+void invasion_ScoreRules(int inv_teams)
+{
+       if(inv_teams) { CheckAllowedTeams(NULL); }
+       GameRules_score_enabled(false);
+       GameRules_scoring(inv_teams, 0, 0, {
+           if (inv_teams) {
+            field_team(ST_INV_KILLS, "frags", SFL_SORT_PRIO_PRIMARY);
+           }
+           field(SP_KILLS, "frags", ((inv_teams) ? SFL_SORT_PRIO_SECONDARY : SFL_SORT_PRIO_PRIMARY));
+       });
+}
+
+void invasion_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+       if(autocvar_g_invasion_type == INV_TYPE_HUNT || autocvar_g_invasion_type == INV_TYPE_STAGE)
+               cvar_set("fraglimit", "0");
+
+       if(autocvar_g_invasion_teams)
+       {
+               invasion_teams = BITS(bound(2, autocvar_g_invasion_teams, 4));
+       }
+       else
+               invasion_teams = 0;
+
+       independent_players = 1; // to disable extra useless scores
+
+       invasion_ScoreRules(invasion_teams);
+
+       independent_players = 0;
+
+       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+       {
+               round_handler_Spawn(Invasion_CheckPlayers, Invasion_CheckWinner, Invasion_RoundStart);
+               round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
+
+               inv_roundcnt = 0;
+               inv_maxrounds = 15; // 15?
+       }
+}
+
+void invasion_Initialize()
+{
+       InitializeEntity(NULL, invasion_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/invasion/invasion.qh b/qcsrc/common/gamemodes/gamemode/invasion/invasion.qh
new file mode 100644 (file)
index 0000000..85cd7ec
--- /dev/null
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit")
+int autocvar_g_invasion_teams;
+int autocvar_g_invasion_type;
+bool autocvar_g_invasion_team_spawns;
+bool g_invasion;
+void invasion_Initialize();
+
+REGISTER_MUTATOR(inv, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               if (autocvar_g_invasion_teams >= 2) {
+                       GameRules_teams(true);
+                       GameRules_spawning_teams(autocvar_g_invasion_team_spawns);
+               }
+        GameRules_limit_score(autocvar_g_invasion_point_limit);
+
+               g_invasion = true;
+               cvar_settemp("g_monsters", "1");
+               invasion_Initialize();
+       }
+       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;
+
+const int INV_TYPE_ROUND = 0; // round-based waves of enemies
+const int INV_TYPE_HUNT = 1; // clear the map of placed enemies
+const int INV_TYPE_STAGE = 2; // reach the end of the level
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/keepaway/_mod.inc b/qcsrc/common/gamemodes/gamemode/keepaway/_mod.inc
new file mode 100644 (file)
index 0000000..9426d78
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keepaway/keepaway.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/keepaway/_mod.qh b/qcsrc/common/gamemodes/gamemode/keepaway/_mod.qh
new file mode 100644 (file)
index 0000000..32872a2
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keepaway/keepaway.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qc b/qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qc
new file mode 100644 (file)
index 0000000..8eb88a3
--- /dev/null
@@ -0,0 +1,475 @@
+#include "keepaway.qh"
+
+// TODO: keepaway
+#ifdef SVQC
+#include <common/effects/all.qh>
+
+.entity ballcarried;
+
+int autocvar_g_keepaway_ballcarrier_effects;
+float autocvar_g_keepaway_ballcarrier_damage;
+float autocvar_g_keepaway_ballcarrier_force;
+float autocvar_g_keepaway_ballcarrier_highspeed;
+float autocvar_g_keepaway_ballcarrier_selfdamage;
+float autocvar_g_keepaway_ballcarrier_selfforce;
+float autocvar_g_keepaway_noncarrier_damage;
+float autocvar_g_keepaway_noncarrier_force;
+float autocvar_g_keepaway_noncarrier_selfdamage;
+float autocvar_g_keepaway_noncarrier_selfforce;
+bool autocvar_g_keepaway_noncarrier_warn;
+int autocvar_g_keepaway_score_bckill;
+int autocvar_g_keepaway_score_killac;
+int autocvar_g_keepaway_score_timepoints;
+float autocvar_g_keepaway_score_timeinterval;
+float autocvar_g_keepawayball_damageforcescale;
+int autocvar_g_keepawayball_effects;
+float autocvar_g_keepawayball_respawntime;
+int autocvar_g_keepawayball_trail_color;
+
+bool ka_ballcarrier_waypointsprite_visible_for_player(entity this, entity player, entity view) // runs on waypoints which are attached to ballcarriers, updates once per frame
+{
+       if(view.ballcarried)
+               if(IS_SPEC(player))
+                       return false; // we don't want spectators of the ballcarrier to see the attached waypoint on the top of their screen
+
+       // TODO: Make the ballcarrier lack a waypointsprite whenever they have the invisibility powerup
+
+       return true;
+}
+
+void ka_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":ka:", mode, ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+void ka_TouchEvent(entity this, entity toucher);
+void ka_RespawnBall(entity this) // runs whenever the ball needs to be relocated
+{
+       if(game_stopped) return;
+       vector oldballorigin = this.origin;
+
+       if(!MoveToRandomMapLocation(this, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
+       {
+               entity spot = SelectSpawnPoint(this, true);
+               setorigin(this, spot.origin);
+               this.angles = spot.angles;
+       }
+
+       makevectors(this.angles);
+       set_movetype(this, MOVETYPE_BOUNCE);
+       this.velocity = '0 0 200';
+       this.angles = '0 0 0';
+       this.effects = autocvar_g_keepawayball_effects;
+       settouch(this, ka_TouchEvent);
+       setthink(this, ka_RespawnBall);
+       this.nextthink = time + autocvar_g_keepawayball_respawntime;
+       navigation_dynamicgoal_set(this);
+
+       Send_Effect(EFFECT_ELECTRO_COMBO, oldballorigin, '0 0 0', 1);
+       Send_Effect(EFFECT_ELECTRO_COMBO, this.origin, '0 0 0', 1);
+
+       WaypointSprite_Spawn(WP_KaBall, 0, 0, this, '0 0 64', NULL, this.team, this, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
+       WaypointSprite_Ping(this.waypointsprite_attachedforcarrier);
+
+       sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+}
+
+void ka_TimeScoring(entity this)
+{
+       if(this.owner.ballcarried)
+       { // add points for holding the ball after a certain amount of time
+               if(autocvar_g_keepaway_score_timepoints)
+                       GameRules_scoring_add(this.owner, SCORE, autocvar_g_keepaway_score_timepoints);
+
+               GameRules_scoring_add(this.owner, KEEPAWAY_BCTIME, (autocvar_g_keepaway_score_timeinterval / 1)); // interval is divided by 1 so that time always shows "seconds"
+               this.nextthink = time + autocvar_g_keepaway_score_timeinterval;
+       }
+}
+
+void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball comes in contact with something
+{
+       if(game_stopped) return;
+       if(!this) return;
+       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+       { // The ball fell off the map, respawn it since players can't get to it
+               ka_RespawnBall(this);
+               return;
+       }
+       if(IS_DEAD(toucher)) { return; }
+       if(STAT(FROZEN, toucher)) { return; }
+       if (!IS_PLAYER(toucher))
+       {  // The ball just touched an object, most likely the world
+               Send_Effect(EFFECT_BALL_SPARKS, this.origin, '0 0 0', 1);
+               sound(this, CH_TRIGGER, SND_KA_TOUCH, VOL_BASE, ATTEN_NORM);
+               return;
+       }
+       else if(this.wait > time) { return; }
+
+       // attach the ball to the player
+       this.owner = toucher;
+       toucher.ballcarried = this;
+       GameRules_scoring_vip(toucher, true);
+       setattachment(this, toucher, "");
+       setorigin(this, '0 0 0');
+
+       // make the ball invisible/unable to do anything/set up time scoring
+       this.velocity = '0 0 0';
+       set_movetype(this, MOVETYPE_NONE);
+       this.effects |= EF_NODRAW;
+       settouch(this, func_null);
+       setthink(this, ka_TimeScoring);
+       this.nextthink = time + autocvar_g_keepaway_score_timeinterval;
+       this.takedamage = DAMAGE_NO;
+       navigation_dynamicgoal_unset(this);
+
+       // apply effects to player
+       toucher.glow_color = autocvar_g_keepawayball_trail_color;
+       toucher.glow_trail = true;
+       toucher.effects |= autocvar_g_keepaway_ballcarrier_effects;
+
+       // messages and sounds
+       ka_EventLog("pickup", toucher);
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_PICKUP, toucher.netname);
+       Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, toucher.netname);
+       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP_SELF);
+       sound(this.owner, CH_TRIGGER, SND_KA_PICKEDUP, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+
+       // scoring
+       GameRules_scoring_add(toucher, KEEPAWAY_PICKUPS, 1);
+
+       // waypoints
+       WaypointSprite_AttachCarrier(WP_KaBallCarrier, toucher, RADARICON_FLAGCARRIER);
+       toucher.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = ka_ballcarrier_waypointsprite_visible_for_player;
+       WaypointSprite_UpdateRule(toucher.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+       WaypointSprite_Ping(toucher.waypointsprite_attachedforcarrier);
+       WaypointSprite_Kill(this.waypointsprite_attachedforcarrier);
+}
+
+void ka_DropEvent(entity plyr) // runs any time that a player is supposed to lose the ball
+{
+       entity ball;
+       ball = plyr.ballcarried;
+
+       if(!ball) { return; }
+
+       // reset the ball
+       setattachment(ball, NULL, "");
+       set_movetype(ball, MOVETYPE_BOUNCE);
+       ball.wait = time + 1;
+       settouch(ball, ka_TouchEvent);
+       setthink(ball, ka_RespawnBall);
+       ball.nextthink = time + autocvar_g_keepawayball_respawntime;
+       ball.takedamage = DAMAGE_YES;
+       ball.effects &= ~EF_NODRAW;
+       setorigin(ball, plyr.origin + '0 0 10');
+       ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
+       entity e = ball.owner; ball.owner = NULL;
+       e.ballcarried = NULL;
+       GameRules_scoring_vip(e, false);
+       navigation_dynamicgoal_set(ball);
+
+       // reset the player effects
+       plyr.glow_trail = false;
+       plyr.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
+
+       // messages and sounds
+       ka_EventLog("dropped", plyr);
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_DROPPED, plyr.netname);
+       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname);
+       sound(NULL, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
+
+       // scoring
+       // GameRules_scoring_add(plyr, KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
+
+       // waypoints
+       WaypointSprite_Spawn(WP_KaBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
+       WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+       WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
+       WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
+}
+
+/** used to clear the ballcarrier whenever the match switches from warmup to normal */
+void ka_Reset(entity this)
+{
+       if((this.owner) && (IS_PLAYER(this.owner)))
+               ka_DropEvent(this.owner);
+
+       if(time < game_starttime)
+       {
+               setthink(this, ka_RespawnBall);
+               settouch(this, func_null);
+               this.nextthink = game_starttime;
+       }
+       else
+               ka_RespawnBall(this);
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+void havocbot_goalrating_ball(entity this, float ratingscale, vector org)
+{
+       float t;
+       entity ball_owner;
+       ball_owner = ka_ball.owner;
+
+       if (ball_owner == this)
+               return;
+
+       // If ball is carried by player then hunt them down.
+       if (ball_owner)
+       {
+               t = (this.health + this.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
+               navigation_routerating(this, ball_owner, t * ratingscale, 2000);
+       }
+       else // Ball has been dropped so collect.
+               navigation_routerating(this, ka_ball, ratingscale, 2000);
+}
+
+void havocbot_role_ka_carrier(entity this)
+{
+       if (IS_DEAD(this))
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+
+       if (!this.ballcarried)
+       {
+               this.havocbot_role = havocbot_role_ka_collector;
+               navigation_goalrating_timeout_expire(this, 2);
+       }
+}
+
+void havocbot_role_ka_collector(entity this)
+{
+       if (IS_DEAD(this))
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+               havocbot_goalrating_items(this, 10000, this.origin, 10000);
+               havocbot_goalrating_enemyplayers(this, 1000, this.origin, 10000);
+               havocbot_goalrating_ball(this, 20000, this.origin);
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+
+       if (this.ballcarried)
+       {
+               this.havocbot_role = havocbot_role_ka_carrier;
+               navigation_goalrating_timeout_expire(this, 2);
+       }
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ka, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
+       {
+               if(frag_target.ballcarried) { // add to amount of times killing carrier
+                       GameRules_scoring_add(frag_attacker, KEEPAWAY_CARRIERKILLS, 1);
+                       if(autocvar_g_keepaway_score_bckill) // add bckills to the score
+                               GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_bckill);
+               }
+               else if(!frag_attacker.ballcarried)
+                       if(autocvar_g_keepaway_noncarrier_warn)
+                               Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN);
+
+               if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
+                       GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_killac);
+       }
+
+       if(frag_target.ballcarried) { ka_DropEvent(frag_target); } // a player with the ball has died, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, GiveFragsForKill)
+{
+       M_ARGV(2, float) = 0; // no frags counted in keepaway
+       return true; // you deceptive little bugger ;3 This needs to be true in order for this function to even count.
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       // clear the item used for the ball in keepaway
+       player.items &= ~IT_KEY1;
+
+       // if the player has the ball, make sure they have the item for it (Used for HUD primarily)
+       if(player.ballcarried)
+               player.items |= IT_KEY1;
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerUseKey)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(MUTATOR_RETURNVALUE == 0)
+       if(player.ballcarried)
+       {
+               ka_DropEvent(player);
+               return true;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(ka, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+       float frag_damage = M_ARGV(4, float);
+       vector frag_force = M_ARGV(6, vector);
+
+       if(frag_attacker.ballcarried) // if the attacker is a ballcarrier
+       {
+               if(frag_target == frag_attacker) // damage done to yourself
+               {
+                       frag_damage *= autocvar_g_keepaway_ballcarrier_selfdamage;
+                       frag_force *= autocvar_g_keepaway_ballcarrier_selfforce;
+               }
+               else // damage done to noncarriers
+               {
+                       frag_damage *= autocvar_g_keepaway_ballcarrier_damage;
+                       frag_force *= autocvar_g_keepaway_ballcarrier_force;
+               }
+       }
+       else if (!frag_target.ballcarried) // if the target is a noncarrier
+       {
+               if(frag_target == frag_attacker) // damage done to yourself
+               {
+                       frag_damage *= autocvar_g_keepaway_noncarrier_selfdamage;
+                       frag_force *= autocvar_g_keepaway_noncarrier_selfforce;
+               }
+               else // damage done to other noncarriers
+               {
+                       frag_damage *= autocvar_g_keepaway_noncarrier_damage;
+                       frag_force *= autocvar_g_keepaway_noncarrier_force;
+               }
+       }
+
+       M_ARGV(4, float) = frag_damage;
+       M_ARGV(6, vector) = frag_force;
+}
+
+MUTATOR_HOOKFUNCTION(ka, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPowerups)
+{
+       entity player = M_ARGV(0, entity);
+
+       // In the future this hook is supposed to allow me to do some extra stuff with waypointsprites and invisibility powerup
+       // So bare with me until I can fix a certain bug with ka_ballcarrier_waypointsprite_visible_for_player()
+
+       player.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
+
+       if(player.ballcarried)
+               player.effects |= autocvar_g_keepaway_ballcarrier_effects;
+}
+
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPhysics_UpdateStats)
+{
+       entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
+
+       if(player.ballcarried)
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_keepaway_ballcarrier_highspeed;
+}
+
+MUTATOR_HOOKFUNCTION(ka, BotShouldAttack)
+{
+       entity bot = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+
+       // if neither player has ball then don't attack unless the ball is on the ground
+       if(!targ.ballcarried && !bot.ballcarried && ka_ball.owner)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(ka, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       if (bot.ballcarried)
+               bot.havocbot_role = havocbot_role_ka_carrier;
+       else
+               bot.havocbot_role = havocbot_role_ka_collector;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
+{
+       entity frag_target = M_ARGV(0, entity);
+
+       if(frag_target.ballcarried)
+               ka_DropEvent(frag_target);
+}
+
+.bool pushable;
+
+// ==============
+// Initialization
+// ==============
+
+MODEL(KA_BALL, "models/orbs/orbblue.md3");
+
+void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
+{
+       entity e = new(keepawayball);
+       setmodel(e, MDL_KA_BALL);
+       setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
+       e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
+       e.takedamage = DAMAGE_YES;
+       e.solid = SOLID_TRIGGER;
+       set_movetype(e, MOVETYPE_BOUNCE);
+       e.glow_color = autocvar_g_keepawayball_trail_color;
+       e.glow_trail = true;
+       e.flags = FL_ITEM;
+       IL_PUSH(g_items, e);
+       e.pushable = true;
+       e.reset = ka_Reset;
+       settouch(e, ka_TouchEvent);
+       e.owner = NULL;
+       ka_ball = e;
+       navigation_dynamicgoal_init(ka_ball, false);
+
+       InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
+}
+
+void ka_Initialize() // run at the start of a match, initiates game mode
+{
+       ka_SpawnBall();
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qh b/qcsrc/common/gamemodes/gamemode/keepaway/keepaway.qh
new file mode 100644 (file)
index 0000000..a4615c1
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#include <common/scores.qh>
+void ka_Initialize();
+
+REGISTER_MUTATOR(ka, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+           GameRules_scoring(0, SFL_SORT_PRIO_PRIMARY, 0, {
+            field(SP_KEEPAWAY_PICKUPS, "pickups", 0);
+            field(SP_KEEPAWAY_CARRIERKILLS, "bckills", 0);
+            field(SP_KEEPAWAY_BCTIME, "bctime", SFL_SORT_PRIO_SECONDARY);
+        });
+
+               ka_Initialize();
+       }
+       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
diff --git a/qcsrc/common/gamemodes/gamemode/keyhunt/_mod.inc b/qcsrc/common/gamemodes/gamemode/keyhunt/_mod.inc
new file mode 100644 (file)
index 0000000..3861dea
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keyhunt/keyhunt.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/keyhunt/_mod.qh b/qcsrc/common/gamemodes/gamemode/keyhunt/_mod.qh
new file mode 100644 (file)
index 0000000..cd796c7
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keyhunt/keyhunt.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qc b/qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qc
new file mode 100644 (file)
index 0000000..6523612
--- /dev/null
@@ -0,0 +1,1324 @@
+#include "keyhunt.qh"
+
+// TODO: sv_keyhunt
+#ifdef SVQC
+float autocvar_g_balance_keyhunt_damageforcescale;
+float autocvar_g_balance_keyhunt_delay_collect;
+float autocvar_g_balance_keyhunt_delay_damage_return;
+float autocvar_g_balance_keyhunt_delay_return;
+float autocvar_g_balance_keyhunt_delay_round;
+float autocvar_g_balance_keyhunt_delay_tracking;
+float autocvar_g_balance_keyhunt_return_when_unreachable;
+float autocvar_g_balance_keyhunt_dropvelocity;
+float autocvar_g_balance_keyhunt_maxdist;
+float autocvar_g_balance_keyhunt_protecttime;
+
+int autocvar_g_balance_keyhunt_score_capture;
+int autocvar_g_balance_keyhunt_score_carrierfrag;
+int autocvar_g_balance_keyhunt_score_collect;
+int autocvar_g_balance_keyhunt_score_destroyed;
+int autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
+int autocvar_g_balance_keyhunt_score_push;
+float autocvar_g_balance_keyhunt_throwvelocity;
+
+//int autocvar_g_keyhunt_teams;
+int autocvar_g_keyhunt_teams_override;
+
+// #define KH_PLAYER_USE_ATTACHMENT
+// #define KH_PLAYER_USE_CARRIEDMODEL
+
+#ifdef KH_PLAYER_USE_ATTACHMENT
+const vector KH_PLAYER_ATTACHMENT_DIST_ROTATED = '0 -4 0';
+const vector KH_PLAYER_ATTACHMENT_DIST = '4 0 0';
+const vector KH_PLAYER_ATTACHMENT = '0 0 0';
+const vector KH_PLAYER_ATTACHMENT_ANGLES = '0 0 0';
+const string KH_PLAYER_ATTACHMENT_BONE = "";
+#else
+const float KH_KEY_ZSHIFT = 22;
+const float KH_KEY_XYDIST = 24;
+const float KH_KEY_XYSPEED = 45;
+#endif
+const float KH_KEY_WP_ZSHIFT = 20;
+
+const vector KH_KEY_MIN = '-10 -10 -46';
+const vector KH_KEY_MAX = '10 10 3';
+const float KH_KEY_BRIGHTNESS = 2;
+
+bool kh_no_radar_circles;
+
+// kh_state
+//     bits  0- 4: team of key 1, or 0 for no such key, or 30 for dropped, or 31 for self
+//     bits  5- 9: team of key 2, or 0 for no such key, or 30 for dropped, or 31 for self
+//     bits 10-14: team of key 3, or 0 for no such key, or 30 for dropped, or 31 for self
+//     bits 15-19: team of key 4, or 0 for no such key, or 30 for dropped, or 31 for self
+.float siren_time;  //  time delay the siren
+//.float stuff_time;  //  time delay to stuffcmd a cvar
+
+int kh_keystatus[17];
+//kh_keystatus[0] = status of dropped keys, kh_keystatus[1 - 16] = player #
+//replace 17 with cvar("maxplayers") or similar !!!!!!!!!
+//for(i = 0; i < maxplayers; ++i)
+//     kh_keystatus[i] = "0";
+
+int kh_Team_ByID(int t)
+{
+       if(t == 0) return NUM_TEAM_1;
+       if(t == 1) return NUM_TEAM_2;
+       if(t == 2) return NUM_TEAM_3;
+       if(t == 3) return NUM_TEAM_4;
+       return 0;
+}
+
+//entity kh_worldkeylist;
+.entity kh_worldkeynext;
+entity kh_controller;
+//bool kh_tracking_enabled;
+int kh_teams;
+int kh_interferemsg_team;
+float kh_interferemsg_time;
+.entity kh_next, kh_prev; // linked list
+.float kh_droptime;
+.int kh_dropperteam;
+.entity kh_previous_owner;
+.int kh_previous_owner_playerid;
+
+int kh_key_dropped, kh_key_carried;
+
+int kh_Key_AllOwnedByWhichTeam();
+
+const int ST_KH_CAPS = 1;
+void kh_ScoreRules(int teams)
+{
+       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+        field_team(ST_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+        field(SP_KH_PUSHES, "pushes", 0);
+        field(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
+        field(SP_KH_PICKUPS, "pickups", 0);
+        field(SP_KH_KCKILLS, "kckills", 0);
+        field(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
+       });
+}
+
+bool kh_KeyCarrier_waypointsprite_visible_for_player(entity this, entity player, entity view)  // runs all the time
+{
+       if(!IS_PLAYER(view) || DIFF_TEAM(this, view))
+               if(!kh_tracking_enabled)
+                       return false;
+
+       return true;
+}
+
+bool kh_Key_waypointsprite_visible_for_player(entity this, entity player, entity view)
+{
+       if(!kh_tracking_enabled)
+               return false;
+       if(!this.owner)
+               return true;
+       if(!this.owner.owner)
+               return true;
+       return false;  // draw only when key is not owned
+}
+
+void kh_update_state()
+{
+       entity key;
+       int f;
+       int s = 0;
+       FOR_EACH_KH_KEY(key)
+       {
+               if(key.owner)
+                       f = key.team;
+               else
+                       f = 30;
+               s |= (32 ** key.count) * f;
+       }
+
+       FOREACH_CLIENT(true, { STAT(KH_KEYS, it) = s; });
+
+       FOR_EACH_KH_KEY(key)
+       {
+               if(key.owner)
+                       STAT(KH_KEYS, key.owner) |= (32 ** key.count) * 31;
+       }
+       //print(ftos((nextent(NULL)).kh_state), "\n");
+}
+
+
+
+
+var kh_Think_t kh_Controller_Thinkfunc;
+void kh_Controller_SetThink(float t, kh_Think_t func)  // runs occasionaly
+{
+       kh_Controller_Thinkfunc = func;
+       kh_controller.cnt = ceil(t);
+       if(t == 0)
+               kh_controller.nextthink = time; // force
+}
+void kh_WaitForPlayers();
+void kh_Controller_Think(entity this)  // called a lot
+{
+       if(game_stopped)
+               return;
+       if(this.cnt > 0)
+       {
+               if(getthink(this) != kh_WaitForPlayers)
+                       this.cnt -= 1;
+       }
+       else if(this.cnt == 0)
+       {
+               this.cnt -= 1;
+               kh_Controller_Thinkfunc();
+       }
+       this.nextthink = time + 1;
+}
+
+// frags f: take from cvar * f
+// frags 0: no frags
+void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner)  // update the score when a key is captured
+{
+       string s;
+       if(game_stopped)
+               return;
+
+       if(frags_player)
+               UpdateFrags(player, frags_player);
+
+       if(key && key.owner && frags_owner)
+               UpdateFrags(key.owner, frags_owner);
+
+       if(!autocvar_sv_eventlog)  //output extra info to the console or text file
+               return;
+
+       s = strcat(":keyhunt:", what, ":", ftos(player.playerid), ":", ftos(frags_player));
+
+       if(key && key.owner)
+               s = strcat(s, ":", ftos(key.owner.playerid));
+       else
+               s = strcat(s, ":0");
+
+       s = strcat(s, ":", ftos(frags_owner), ":");
+
+       if(key)
+               s = strcat(s, key.netname);
+
+       GameLogEcho(s);
+}
+
+vector kh_AttachedOrigin(entity e)  // runs when a team captures the flag, it can run 2 or 3 times.
+{
+       if(e.tag_entity)
+       {
+               makevectors(e.tag_entity.angles);
+               return e.tag_entity.origin + e.origin.x * v_forward - e.origin.y * v_right + e.origin.z * v_up;
+       }
+       else
+               return e.origin;
+}
+
+void kh_Key_Attach(entity key)  // runs when a player picks up a key and several times when a key is assigned to a player at the start of a round
+{
+#ifdef KH_PLAYER_USE_ATTACHMENT
+       entity first = key.owner.kh_next;
+       if(key == first)
+       {
+               setattachment(key, key.owner, KH_PLAYER_ATTACHMENT_BONE);
+               if(key.kh_next)
+               {
+                       setattachment(key.kh_next, key, "");
+                       setorigin(key, key.kh_next.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
+                       setorigin(key.kh_next, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
+                       key.kh_next.angles = '0 0 0';
+               }
+               else
+                       setorigin(key, KH_PLAYER_ATTACHMENT);
+               key.angles = KH_PLAYER_ATTACHMENT_ANGLES;
+       }
+       else
+       {
+               setattachment(key, key.kh_prev, "");
+               if(key.kh_next)
+                       setattachment(key.kh_next, key, "");
+               setorigin(key, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
+               setorigin(first, first.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
+               key.angles = '0 0 0';
+       }
+#else
+       setattachment(key, key.owner, "");
+       setorigin(key, '0 0 1' * KH_KEY_ZSHIFT);  // fixing x, y in think
+       key.angles_y -= key.owner.angles.y;
+#endif
+       key.flags = 0;
+       if(IL_CONTAINS(g_items, key))
+               IL_REMOVE(g_items, key);
+       key.solid = SOLID_NOT;
+       set_movetype(key, MOVETYPE_NONE);
+       key.team = key.owner.team;
+       key.nextthink = time;
+       key.damageforcescale = 0;
+       key.takedamage = DAMAGE_NO;
+       key.modelindex = kh_key_carried;
+       navigation_dynamicgoal_unset(key);
+}
+
+void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs several times times when all the keys are captured
+{
+#ifdef KH_PLAYER_USE_ATTACHMENT
+       entity first = key.owner.kh_next;
+       if(key == first)
+       {
+               if(key.kh_next)
+               {
+                       setattachment(key.kh_next, key.owner, KH_PLAYER_ATTACHMENT_BONE);
+                       setorigin(key.kh_next, key.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
+                       key.kh_next.angles = KH_PLAYER_ATTACHMENT_ANGLES;
+               }
+       }
+       else
+       {
+               if(key.kh_next)
+                       setattachment(key.kh_next, key.kh_prev, "");
+               setorigin(first, first.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
+       }
+       // in any case:
+       setattachment(key, NULL, "");
+       setorigin(key, key.owner.origin + '0 0 1' * (STAT(PL_MIN, key.owner).z - KH_KEY_MIN_z));
+       key.angles = key.owner.angles;
+#else
+       setorigin(key, key.owner.origin + key.origin.z * '0 0 1');
+       setattachment(key, NULL, "");
+       key.angles_y += key.owner.angles.y;
+#endif
+       key.flags = FL_ITEM;
+       if(!IL_CONTAINS(g_items, key))
+               IL_PUSH(g_items, key);
+       key.solid = SOLID_TRIGGER;
+       set_movetype(key, MOVETYPE_TOSS);
+       key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
+       key.damageforcescale = autocvar_g_balance_keyhunt_damageforcescale;
+       key.takedamage = DAMAGE_YES;
+       // let key.team stay
+       key.modelindex = kh_key_dropped;
+       navigation_dynamicgoal_set(key);
+       key.kh_previous_owner = key.owner;
+       key.kh_previous_owner_playerid = key.owner.playerid;
+}
+
+void kh_Key_AssignTo(entity key, entity player)  // runs every time a key is picked up or assigned. Runs prior to kh_key_attach
+{
+       if(key.owner == player)
+               return;
+
+       int ownerteam0 = kh_Key_AllOwnedByWhichTeam();
+
+       if(key.owner)
+       {
+               kh_Key_Detach(key);
+
+               // remove from linked list
+               if(key.kh_next)
+                       key.kh_next.kh_prev = key.kh_prev;
+               key.kh_prev.kh_next = key.kh_next;
+               key.kh_next = NULL;
+               key.kh_prev = NULL;
+
+               if(key.owner.kh_next == NULL)
+               {
+                       // No longer a key carrier
+                       if(!kh_no_radar_circles)
+                               WaypointSprite_Ping(key.owner.waypointsprite_attachedforcarrier);
+                       WaypointSprite_DetachCarrier(key.owner);
+               }
+       }
+
+       key.owner = player;
+
+       if(player)
+       {
+               // insert into linked list
+               key.kh_next = player.kh_next;
+               key.kh_prev = player;
+               player.kh_next = key;
+               if(key.kh_next)
+                       key.kh_next.kh_prev = key;
+
+               float i;
+               i = kh_keystatus[key.owner.playerid];
+                       if(key.netname == "^1red key")
+                               i += 1;
+                       if(key.netname == "^4blue key")
+                               i += 2;
+                       if(key.netname == "^3yellow key")
+                               i += 4;
+                       if(key.netname == "^6pink key")
+                               i += 8;
+               kh_keystatus[key.owner.playerid] = i;
+
+               kh_Key_Attach(key);
+
+               if(key.kh_next == NULL)
+               {
+                       // player is now a key carrier
+                       entity wp = WaypointSprite_AttachCarrier(WP_Null, player, RADARICON_FLAGCARRIER);
+                       wp.colormod = colormapPaletteColor(player.team - 1, 0);
+                       player.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_KeyCarrier_waypointsprite_visible_for_player;
+                       WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team, SPRITERULE_TEAMPLAY);
+                       if(player.team == NUM_TEAM_1)
+                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierRed, WP_KeyCarrierFriend, WP_KeyCarrierRed);
+                       else if(player.team == NUM_TEAM_2)
+                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierBlue, WP_KeyCarrierFriend, WP_KeyCarrierBlue);
+                       else if(player.team == NUM_TEAM_3)
+                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierYellow, WP_KeyCarrierFriend, WP_KeyCarrierYellow);
+                       else if(player.team == NUM_TEAM_4)
+                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierPink, WP_KeyCarrierFriend, WP_KeyCarrierPink);
+                       if(!kh_no_radar_circles)
+                               WaypointSprite_Ping(player.waypointsprite_attachedforcarrier);
+               }
+       }
+
+       // moved that here, also update if there's no player
+       kh_update_state();
+
+       key.pusher = NULL;
+
+       int ownerteam = kh_Key_AllOwnedByWhichTeam();
+       if(ownerteam != ownerteam0)
+       {
+               entity k;
+               if(ownerteam != -1)
+               {
+                       kh_interferemsg_time = time + 0.2;
+                       kh_interferemsg_team = player.team;
+
+                       // audit all key carrier sprites, update them to "Run here"
+                       FOR_EACH_KH_KEY(k)
+                       {
+                               if (!k.owner) continue;
+                               entity first = WP_Null;
+                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
+                               entity third = WP_Null;
+                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
+                               WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFinish, third);
+                       }
+               }
+               else
+               {
+                       kh_interferemsg_time = 0;
+
+                       // audit all key carrier sprites, update them to "Key Carrier"
+                       FOR_EACH_KH_KEY(k)
+                       {
+                               if (!k.owner) continue;
+                               entity first = WP_Null;
+                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
+                               entity third = WP_Null;
+                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
+                               WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFriend, third);
+                       }
+               }
+       }
+}
+
+void kh_Key_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(this.owner)
+               return;
+       if(ITEM_DAMAGE_NEEDKILL(deathtype))
+       {
+               this.pain_finished = bound(time, time + autocvar_g_balance_keyhunt_delay_damage_return, this.pain_finished);
+               return;
+       }
+       if(force == '0 0 0')
+               return;
+       if(time > this.pushltime)
+               if(IS_PLAYER(attacker))
+                       this.team = attacker.team;
+}
+
+void kh_Key_Collect(entity key, entity player)  //a player picks up a dropped key
+{
+       sound(player, CH_TRIGGER, SND_KH_COLLECT, VOL_BASE, ATTEN_NORM);
+
+       if(key.kh_dropperteam != player.team)
+       {
+               kh_Scores_Event(player, key, "collect", autocvar_g_balance_keyhunt_score_collect, 0);
+               GameRules_scoring_add(player, KH_PICKUPS, 1);
+       }
+       key.kh_dropperteam = 0;
+       int realteam = kh_Team_ByID(key.count);
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_PICKUP), player.netname);
+
+       kh_Key_AssignTo(key, player); // this also updates .kh_state
+}
+
+void kh_Key_Touch(entity this, entity toucher)  // runs many, many times when a key has been dropped and can be picked up
+{
+       if(game_stopped)
+               return;
+
+       if(this.owner) // already carried
+               return;
+
+       if(ITEM_TOUCH_NEEDKILL())
+       {
+               this.pain_finished = bound(time, time + autocvar_g_balance_keyhunt_delay_damage_return, this.pain_finished);
+               return;
+       }
+
+       if (!IS_PLAYER(toucher))
+               return;
+       if(IS_DEAD(toucher))
+               return;
+       if(toucher == this.enemy)
+               if(time < this.kh_droptime + autocvar_g_balance_keyhunt_delay_collect)
+                       return;  // you just dropped it!
+       kh_Key_Collect(this, toucher);
+}
+
+void kh_Key_Remove(entity key)  // runs after when all the keys have been collected or when a key has been dropped for more than X seconds
+{
+       entity o = key.owner;
+       kh_Key_AssignTo(key, NULL);
+       if(o) // it was attached
+               WaypointSprite_Kill(key.waypointsprite_attachedforcarrier);
+       else // it was dropped
+               WaypointSprite_DetachCarrier(key);
+
+       // remove key from key list
+       if (kh_worldkeylist == key)
+               kh_worldkeylist = kh_worldkeylist.kh_worldkeynext;
+       else
+       {
+               o = kh_worldkeylist;
+               while (o)
+               {
+                       if (o.kh_worldkeynext == key)
+                       {
+                               o.kh_worldkeynext = o.kh_worldkeynext.kh_worldkeynext;
+                               break;
+                       }
+                       o = o.kh_worldkeynext;
+               }
+       }
+
+       delete(key);
+
+       kh_update_state();
+}
+
+void kh_FinishRound()  // runs when a team captures the keys
+{
+       // prepare next round
+       kh_interferemsg_time = 0;
+       entity key;
+
+       kh_no_radar_circles = true;
+       FOR_EACH_KH_KEY(key)
+               kh_Key_Remove(key);
+       kh_no_radar_circles = false;
+
+       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
+}
+
+void nades_GiveBonus(entity player, float score);
+
+void kh_WinnerTeam(int winner_team)  // runs when a team wins
+{
+       // all key carriers get some points
+       entity key;
+       float 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)
+       {
+               float f = DistributeEvenly_Get(1);
+               kh_Scores_Event(key.owner, key, "capture", f, 0);
+               GameRules_scoring_add_team(key.owner, KH_CAPS, 1);
+               nades_GiveBonus(key.owner, autocvar_g_nades_bonus_score_high);
+       }
+
+       bool first = true;
+       string keyowner = "";
+       FOR_EACH_KH_KEY(key)
+               if(key.owner.kh_next == key)
+               {
+                       if(!first)
+                               keyowner = strcat(keyowner, ", ");
+                       keyowner = key.owner.netname;
+                       first = false;
+               }
+
+       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_KEYHUNT_CAPTURE), keyowner);
+
+       first = true;
+       vector firstorigin = '0 0 0', lastorigin = '0 0 0', midpoint = '0 0 0';
+       FOR_EACH_KH_KEY(key)
+       {
+               vector thisorigin = kh_AttachedOrigin(key);
+               //dprint("Key origin: ", vtos(thisorigin), "\n");
+               midpoint += thisorigin;
+
+               if(!first)
+                       te_lightning2(NULL, lastorigin, thisorigin);
+               lastorigin = thisorigin;
+               if(first)
+                       firstorigin = thisorigin;
+               first = false;
+       }
+       if(NumTeams(kh_teams) > 2)
+       {
+               te_lightning2(NULL, lastorigin, firstorigin);
+       }
+       midpoint = midpoint * (1 / NumTeams(kh_teams));
+       te_customflash(midpoint, 1000, 1, Team_ColorRGB(winner_team) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
+
+       play2all(SND(KH_CAPTURE));
+       kh_FinishRound();
+}
+
+void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes a flag carrier off the map
+{
+       float f;
+       entity attacker = NULL;
+       if(lostkey.pusher)
+               if(lostkey.pusher.team != loser_team)
+                       if(IS_PLAYER(lostkey.pusher))
+                               attacker = lostkey.pusher;
+
+       if(attacker)
+       {
+               if(lostkey.kh_previous_owner)
+                       kh_Scores_Event(lostkey.kh_previous_owner, NULL, "pushed", 0, -autocvar_g_balance_keyhunt_score_push);
+                       // don't actually GIVE him the -nn points, just log
+               kh_Scores_Event(attacker, NULL, "push", autocvar_g_balance_keyhunt_score_push, 0);
+               GameRules_scoring_add(attacker, KH_PUSHES, 1);
+               //centerprint(attacker, "Your push is the best!"); // does this really need to exist?
+       }
+       else
+       {
+               int players = 0;
+               float of = autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
+
+               FOREACH_CLIENT(IS_PLAYER(it) && it.team != loser_team, { ++players; });
+
+               entity key;
+               int keys = 0;
+               FOR_EACH_KH_KEY(key)
+                       if(key.owner && key.team != loser_team)
+                               ++keys;
+
+               if(lostkey.kh_previous_owner)
+                       kh_Scores_Event(lostkey.kh_previous_owner, NULL, "destroyed", 0, -autocvar_g_balance_keyhunt_score_destroyed);
+                       // don't actually GIVE him the -nn points, just log
+
+               if(lostkey.kh_previous_owner.playerid == lostkey.kh_previous_owner_playerid)
+                       GameRules_scoring_add(lostkey.kh_previous_owner, KH_DESTROYS, 1);
+
+               DistributeEvenly_Init(autocvar_g_balance_keyhunt_score_destroyed, keys * of + players);
+
+               FOR_EACH_KH_KEY(key)
+                       if(key.owner && key.team != loser_team)
+                       {
+                               f = DistributeEvenly_Get(of);
+                               kh_Scores_Event(key.owner, NULL, "destroyed_holdingkey", f, 0);
+                       }
+
+               int fragsleft = DistributeEvenly_Get(players);
+
+               // Now distribute these among all other teams...
+               int j = NumTeams(kh_teams) - 1;
+               for(int i = 0; i < NumTeams(kh_teams); ++i)
+               {
+                       int thisteam = kh_Team_ByID(i);
+                       if(thisteam == loser_team) // bad boy, no cookie - this WILL happen
+                               continue;
+
+                       players = 0;
+                       FOREACH_CLIENT(IS_PLAYER(it) && it.team == thisteam, { ++players; });
+
+                       DistributeEvenly_Init(fragsleft, j);
+                       fragsleft = DistributeEvenly_Get(j - 1);
+                       DistributeEvenly_Init(DistributeEvenly_Get(1), players);
+
+                       FOREACH_CLIENT(IS_PLAYER(it) && it.team == thisteam, {
+                               f = DistributeEvenly_Get(1);
+                               kh_Scores_Event(it, NULL, "destroyed", f, 0);
+                       });
+
+                       --j;
+               }
+       }
+
+       int realteam = kh_Team_ByID(lostkey.count);
+       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(loser_team, CENTER_ROUND_TEAM_LOSS));
+       if(attacker)
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_PUSHED), attacker.netname, lostkey.kh_previous_owner.netname);
+       else
+               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DESTROYED), lostkey.kh_previous_owner.netname);
+
+       play2all(SND(KH_DESTROY));
+       te_tarexplosion(lostkey.origin);
+
+       kh_FinishRound();
+}
+
+void kh_Key_Think(entity this)  // runs all the time
+{
+       if(game_stopped)
+               return;
+
+       if(this.owner)
+       {
+#ifndef KH_PLAYER_USE_ATTACHMENT
+               makevectors('0 1 0' * (this.cnt + (time % 360) * KH_KEY_XYSPEED));
+               setorigin(this, v_forward * KH_KEY_XYDIST + '0 0 1' * this.origin.z);
+#endif
+       }
+
+       // if in nodrop or time over, end the round
+       if(!this.owner)
+               if(time > this.pain_finished)
+                       kh_LoserTeam(this.team, this);
+
+       if(this.owner)
+       if(kh_Key_AllOwnedByWhichTeam() != -1)
+       {
+               if(this.siren_time < time)
+               {
+                       sound(this.owner, CH_TRIGGER, SND_KH_ALARM, VOL_BASE, ATTEN_NORM);  // play a simple alarm
+                       this.siren_time = time + 2.5;  // repeat every 2.5 seconds
+               }
+
+               entity key;
+               vector p = this.owner.origin;
+               FOR_EACH_KH_KEY(key)
+                       if(vdist(key.owner.origin - p, >, autocvar_g_balance_keyhunt_maxdist))
+                               goto not_winning;
+               kh_WinnerTeam(this.team);
+LABEL(not_winning)
+       }
+
+       if(kh_interferemsg_time && time > kh_interferemsg_time)
+       {
+               kh_interferemsg_time = 0;
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(it.team == kh_interferemsg_team)
+                               if(it.kh_next)
+                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_MEET);
+                               else
+                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_HELP);
+                       else
+                               Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(kh_interferemsg_team, CENTER_KEYHUNT_INTERFERE));
+               });
+       }
+
+       this.nextthink = time + 0.05;
+}
+
+void key_reset(entity this)
+{
+       kh_Key_AssignTo(this, NULL);
+       kh_Key_Remove(this);
+}
+
+const string STR_ITEM_KH_KEY = "item_kh_key";
+void kh_Key_Spawn(entity initial_owner, float _angle, float i)  // runs every time a new flag is created, ie after all the keys have been collected
+{
+       entity key = spawn();
+       key.count = i;
+       key.classname = STR_ITEM_KH_KEY;
+       settouch(key, kh_Key_Touch);
+       setthink(key, kh_Key_Think);
+       key.nextthink = time;
+       key.items = IT_KEY1 | IT_KEY2;
+       key.cnt = _angle;
+       key.angles = '0 360 0' * random();
+       key.event_damage = kh_Key_Damage;
+       key.takedamage = DAMAGE_YES;
+       key.damagedbytriggers = autocvar_g_balance_keyhunt_return_when_unreachable;
+       key.damagedbycontents = autocvar_g_balance_keyhunt_return_when_unreachable;
+       key.modelindex = kh_key_dropped;
+       key.model = "key";
+       key.kh_dropperteam = 0;
+       key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+       setsize(key, KH_KEY_MIN, KH_KEY_MAX);
+       key.colormod = Team_ColorRGB(initial_owner.team) * KH_KEY_BRIGHTNESS;
+       key.reset = key_reset;
+       navigation_dynamicgoal_init(key, false);
+
+       switch(initial_owner.team)
+       {
+               case NUM_TEAM_1:
+                       key.netname = "^1red key";
+                       break;
+               case NUM_TEAM_2:
+                       key.netname = "^4blue key";
+                       break;
+               case NUM_TEAM_3:
+                       key.netname = "^3yellow key";
+                       break;
+               case NUM_TEAM_4:
+                       key.netname = "^6pink key";
+                       break;
+               default:
+                       key.netname = "NETGIER key";
+                       break;
+       }
+
+       // link into key list
+       key.kh_worldkeynext = kh_worldkeylist;
+       kh_worldkeylist = key;
+
+       Send_Notification(NOTIF_ONE, initial_owner, MSG_CENTER, APP_TEAM_NUM(initial_owner.team, CENTER_KEYHUNT_START));
+
+       WaypointSprite_Spawn(WP_KeyDropped, 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, NULL, key.team, key, waypointsprite_attachedforcarrier, false, RADARICON_FLAG);
+       key.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_Key_waypointsprite_visible_for_player;
+
+       kh_Key_AssignTo(key, initial_owner);
+}
+
+// -1 when no team completely owns all keys yet
+int kh_Key_AllOwnedByWhichTeam()  // constantly called. check to see if all the keys are owned by the same team
+{
+       entity key;
+       int teem = -1;
+       int keys = NumTeams(kh_teams);
+       FOR_EACH_KH_KEY(key)
+       {
+               if(!key.owner)
+                       return -1;
+               if(teem == -1)
+                       teem = key.team;
+               else if(teem != key.team)
+                       return -1;
+               --keys;
+       }
+       if(keys != 0)
+               return -1;
+       return teem;
+}
+
+void kh_Key_DropOne(entity key)
+{
+       // prevent collecting this one for some time
+       entity player = key.owner;
+
+       key.kh_droptime = time;
+       key.enemy = player;
+
+       kh_Scores_Event(player, key, "dropkey", 0, 0);
+       GameRules_scoring_add(player, KH_LOSSES, 1);
+       int realteam = kh_Team_ByID(key.count);
+       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DROP), player.netname);
+
+       kh_Key_AssignTo(key, NULL);
+       makevectors(player.v_angle);
+       key.velocity = W_CalculateProjectileVelocity(player, player.velocity, autocvar_g_balance_keyhunt_throwvelocity * v_forward, false);
+       key.pusher = NULL;
+       key.pushltime = time + autocvar_g_balance_keyhunt_protecttime;
+       key.kh_dropperteam = key.team;
+
+       sound(player, CH_TRIGGER, SND_KH_DROP, VOL_BASE, ATTEN_NORM);
+}
+
+void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies
+{
+       if(player.kh_next)
+       {
+               entity mypusher = NULL;
+               if(player.pusher)
+                       if(time < player.pushltime)
+                               mypusher = player.pusher;
+
+               entity key;
+               while((key = player.kh_next))
+               {
+                       kh_Scores_Event(player, key, "losekey", 0, 0);
+                       GameRules_scoring_add(player, KH_LOSSES, 1);
+                       int realteam = kh_Team_ByID(key.count);
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), player.netname);
+                       kh_Key_AssignTo(key, NULL);
+                       makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random());
+                       key.velocity = W_CalculateProjectileVelocity(player, player.velocity, autocvar_g_balance_keyhunt_dropvelocity * v_forward, false);
+                       key.pusher = mypusher;
+                       key.pushltime = time + autocvar_g_balance_keyhunt_protecttime;
+                       if(suicide)
+                               key.kh_dropperteam = player.team;
+               }
+               sound(player, CH_TRIGGER, SND_KH_DROP, VOL_BASE, ATTEN_NORM);
+       }
+}
+
+int kh_GetMissingTeams()
+{
+       int missing_teams = 0;
+       for(int i = 0; i < NumTeams(kh_teams); ++i)
+       {
+               int teem = kh_Team_ByID(i);
+               int players = 0;
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
+                               ++players;
+               });
+               if (!players)
+                       missing_teams |= (2 ** i);
+       }
+       return missing_teams;
+}
+
+void kh_WaitForPlayers()  // delay start of the round until enough players are present
+{
+       static int prev_missing_teams_mask;
+       if(time < game_starttime)
+       {
+               if (prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
+               return;
+       }
+
+       int missing_teams_mask = kh_GetMissingTeams();
+       if(!missing_teams_mask)
+       {
+               if(prev_missing_teams_mask > 0)
+                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+               prev_missing_teams_mask = -1;
+               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
+               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
+       }
+       else
+       {
+               if(player_count == 0)
+               {
+                       if(prev_missing_teams_mask > 0)
+                               Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+                       prev_missing_teams_mask = -1;
+               }
+               else
+               {
+                       if(prev_missing_teams_mask != missing_teams_mask)
+                       {
+                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
+                               prev_missing_teams_mask = missing_teams_mask;
+                       }
+               }
+               kh_Controller_SetThink(1, kh_WaitForPlayers);
+       }
+}
+
+void kh_EnableTrackingDevice()  // runs after each round
+{
+       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
+       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
+
+       kh_tracking_enabled = true;
+}
+
+void kh_StartRound()  // runs at the start of each round
+{
+       if(time < game_starttime)
+       {
+               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
+               return;
+       }
+
+       if(kh_GetMissingTeams())
+       {
+               kh_Controller_SetThink(1, kh_WaitForPlayers);
+               return;
+       }
+
+       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
+       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
+
+       for(int i = 0; i < NumTeams(kh_teams); ++i)
+       {
+               int teem = kh_Team_ByID(i);
+               int players = 0;
+               entity my_player = NULL;
+               FOREACH_CLIENT(IS_PLAYER(it), {
+                       if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
+                       {
+                               ++players;
+                               if(random() * players <= 1)
+                                       my_player = it;
+                       }
+               });
+               kh_Key_Spawn(my_player, 360 * i / NumTeams(kh_teams), i);
+       }
+
+       kh_tracking_enabled = false;
+       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_SCAN, autocvar_g_balance_keyhunt_delay_tracking);
+       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, kh_EnableTrackingDevice);
+}
+
+float kh_HandleFrags(entity attacker, entity targ, float f)  // adds to the player score
+{
+       if(attacker == targ)
+               return f;
+
+       if(targ.kh_next)
+       {
+               if(attacker.team == targ.team)
+               {
+                       int nk = 0;
+                       for(entity k = targ.kh_next; k != NULL; k = k.kh_next)
+                               ++nk;
+                       kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", -nk * autocvar_g_balance_keyhunt_score_collect, 0);
+               }
+               else
+               {
+                       kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", autocvar_g_balance_keyhunt_score_carrierfrag-1, 0);
+                       GameRules_scoring_add(attacker, KH_KCKILLS, 1);
+                       // the frag gets added later
+               }
+       }
+
+       return f;
+}
+
+void kh_Initialize()  // sets up th KH environment
+{
+       // setup variables
+       kh_teams = autocvar_g_keyhunt_teams_override;
+       if(kh_teams < 2)
+               kh_teams = cvar("g_keyhunt_teams"); // read the cvar directly as it gets written earlier in the same frame
+       kh_teams = BITS(bound(2, kh_teams, 4));
+
+       // make a KH entity for controlling the game
+       kh_controller = spawn();
+       setthink(kh_controller, kh_Controller_Think);
+       kh_Controller_SetThink(0, kh_WaitForPlayers);
+
+       setmodel(kh_controller, MDL_KH_KEY);
+       kh_key_dropped = kh_controller.modelindex;
+       /*
+       dprint(vtos(kh_controller.mins));
+       dprint(vtos(kh_controller.maxs));
+       dprint("\n");
+       */
+#ifdef KH_PLAYER_USE_CARRIEDMODEL
+       setmodel(kh_controller, MDL_KH_KEY_CARRIED);
+       kh_key_carried = kh_controller.modelindex;
+#else
+       kh_key_carried = kh_key_dropped;
+#endif
+
+       kh_controller.model = "";
+       kh_controller.modelindex = 0;
+
+       kh_ScoreRules(kh_teams);
+}
+
+void kh_finalize()
+{
+       // to be called before intermission
+       kh_FinishRound();
+       delete(kh_controller);
+       kh_controller = NULL;
+}
+
+// legacy bot role
+
+void(entity this) havocbot_role_kh_carrier;
+void(entity this) havocbot_role_kh_defense;
+void(entity this) havocbot_role_kh_offense;
+void(entity this) havocbot_role_kh_freelancer;
+
+
+void havocbot_goalrating_kh(entity this, float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
+{
+       entity head;
+       for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
+       {
+               if(head.owner == this)
+                       continue;
+               if(!kh_tracking_enabled)
+               {
+                       // if it's carried by our team we know about it
+                       // otherwise we have to see it to know about it
+                       if(!head.owner || head.team != this.team)
+                       {
+                               traceline(this.origin + this.view_ofs, head.origin, MOVE_NOMONSTERS, this);
+                               if (trace_fraction < 1 && trace_ent != head)
+                                       continue; // skip what I can't see
+                       }
+               }
+               if(!head.owner)
+                       navigation_routerating(this, head, ratingscale_dropped * 10000, 100000);
+               else if(head.team == this.team)
+                       navigation_routerating(this, head.owner, ratingscale_team * 10000, 100000);
+               else
+                       navigation_routerating(this, head.owner, ratingscale_enemy * 10000, 100000);
+       }
+
+       havocbot_goalrating_items(this, 1, this.origin, 10000);
+}
+
+void havocbot_role_kh_carrier(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (!(this.kh_next))
+       {
+               LOG_TRACE("changing role to freelancer");
+               this.havocbot_role = havocbot_role_kh_freelancer;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               if(kh_Key_AllOwnedByWhichTeam() == this.team)
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // bring home
+               else
+                       havocbot_goalrating_kh(this, 4, 4, 1); // play defensively
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_kh_defense(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (this.kh_next)
+       {
+               LOG_TRACE("changing role to carrier");
+               this.havocbot_role = havocbot_role_kh_carrier;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + random() * 10 + 20;
+       if (time > this.havocbot_role_timeout)
+       {
+               LOG_TRACE("changing role to freelancer");
+               this.havocbot_role = havocbot_role_kh_freelancer;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               float key_owner_team;
+               navigation_goalrating_start(this);
+
+               key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == this.team)
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend key carriers
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(this, 4, 1, 0.1); // play defensively
+               else
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_kh_offense(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (this.kh_next)
+       {
+               LOG_TRACE("changing role to carrier");
+               this.havocbot_role = havocbot_role_kh_carrier;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + random() * 10 + 20;
+       if (time > this.havocbot_role_timeout)
+       {
+               LOG_TRACE("changing role to freelancer");
+               this.havocbot_role = havocbot_role_kh_freelancer;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               float key_owner_team;
+
+               navigation_goalrating_start(this);
+
+               key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == this.team)
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(this, 0.1, 1, 4); // play offensively
+               else
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK! EMERGENCY!
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void havocbot_role_kh_freelancer(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (this.kh_next)
+       {
+               LOG_TRACE("changing role to carrier");
+               this.havocbot_role = havocbot_role_kh_carrier;
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + random() * 10 + 10;
+       if (time > this.havocbot_role_timeout)
+       {
+               if (random() < 0.5)
+               {
+                       LOG_TRACE("changing role to offense");
+                       this.havocbot_role = havocbot_role_kh_offense;
+               }
+               else
+               {
+                       LOG_TRACE("changing role to defense");
+                       this.havocbot_role = havocbot_role_kh_defense;
+               }
+               this.havocbot_role_timeout = 0;
+               return;
+       }
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               int key_owner_team = kh_Key_AllOwnedByWhichTeam();
+               if(key_owner_team == this.team)
+                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
+               else if(key_owner_team == -1)
+                       havocbot_goalrating_kh(this, 1, 10, 4); // prefer dropped keys
+               else
+                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+
+// register this as a mutator
+
+MUTATOR_HOOKFUNCTION(kh, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       kh_Key_DropAll(player, true);
+}
+
+MUTATOR_HOOKFUNCTION(kh, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       kh_Key_DropAll(player, true);
+}
+
+MUTATOR_HOOKFUNCTION(kh, PlayerDies)
+{
+       entity frag_attacker = M_ARGV(1, entity);
+       entity frag_target = M_ARGV(2, entity);
+
+       if(frag_target == frag_attacker)
+               kh_Key_DropAll(frag_target, true);
+       else if(IS_PLAYER(frag_attacker))
+               kh_Key_DropAll(frag_target, false);
+       else
+               kh_Key_DropAll(frag_target, true);
+}
+
+MUTATOR_HOOKFUNCTION(kh, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+       entity frag_attacker = M_ARGV(0, entity);
+       entity frag_target = M_ARGV(1, entity);
+       float frag_score = M_ARGV(2, float);
+       M_ARGV(2, float) = kh_HandleFrags(frag_attacker, frag_target, frag_score);
+}
+
+MUTATOR_HOOKFUNCTION(kh, MatchEnd)
+{
+       kh_finalize();
+}
+
+MUTATOR_HOOKFUNCTION(kh, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(0, float) = kh_teams;
+}
+
+MUTATOR_HOOKFUNCTION(kh, SpectateCopy)
+{
+       entity spectatee = M_ARGV(0, entity);
+       entity client = M_ARGV(1, entity);
+
+       STAT(KH_KEYS, client) = STAT(KH_KEYS, spectatee);
+}
+
+MUTATOR_HOOKFUNCTION(kh, PlayerUseKey)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(MUTATOR_RETURNVALUE == 0)
+       {
+               entity k = player.kh_next;
+               if(k)
+               {
+                       kh_Key_DropOne(k);
+                       return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(kh, HavocBot_ChooseRole)
+{
+    entity bot = M_ARGV(0, entity);
+
+       if(IS_DEAD(bot))
+               return true;
+
+       float r = random() * 3;
+       if (r < 1)
+               bot.havocbot_role = havocbot_role_kh_offense;
+       else if (r < 2)
+               bot.havocbot_role = havocbot_role_kh_defense;
+       else
+               bot.havocbot_role = havocbot_role_kh_freelancer;
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(kh, DropSpecialItems)
+{
+       entity frag_target = M_ARGV(0, entity);
+
+       kh_Key_DropAll(frag_target, false);
+}
+
+MUTATOR_HOOKFUNCTION(kh, reset_map_global)
+{
+       kh_WaitForPlayers(); // takes care of killing the "missing teams" message
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qh b/qcsrc/common/gamemodes/gamemode/keyhunt/keyhunt.qh
new file mode 100644 (file)
index 0000000..a086ee6
--- /dev/null
@@ -0,0 +1,36 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.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_STATIC();
+       MUTATOR_ONADD
+       {
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_keyhunt_team_spawns);
+        GameRules_limit_score(autocvar_g_keyhunt_point_limit);
+        GameRules_limit_lead(autocvar_g_keyhunt_point_leadlimit);
+
+               kh_Initialize();
+       }
+       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:
+bool kh_tracking_enabled;
+.entity kh_next;
+
+USING(kh_Think_t, void());
+void kh_StartRound();
+void kh_Controller_SetThink(float t, kh_Think_t func);
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/lms/_mod.inc b/qcsrc/common/gamemodes/gamemode/lms/_mod.inc
new file mode 100644 (file)
index 0000000..43bb76d
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/lms/lms.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/lms/_mod.qh b/qcsrc/common/gamemodes/gamemode/lms/_mod.qh
new file mode 100644 (file)
index 0000000..5e780bb
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/lms/lms.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/lms/lms.qc b/qcsrc/common/gamemodes/gamemode/lms/lms.qc
new file mode 100644 (file)
index 0000000..b6bfb4e
--- /dev/null
@@ -0,0 +1,438 @@
+#include "lms.qh"
+
+#ifdef SVQC
+#include <common/mutators/mutator/instagib/items.qh>
+#include <server/campaign.qh>
+#include <server/command/_mod.qh>
+
+int autocvar_g_lms_extra_lives;
+bool autocvar_g_lms_join_anytime;
+int autocvar_g_lms_last_join;
+bool autocvar_g_lms_regenerate;
+
+// main functions
+float LMS_NewPlayerLives()
+{
+       float fl;
+       fl = autocvar_fraglimit;
+       if(fl == 0)
+               fl = 999;
+
+       // first player has left the game for dying too much? Nobody else can get in.
+       if(lms_lowest_lives < 1)
+               return 0;
+
+       if(!autocvar_g_lms_join_anytime)
+               if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
+                       return 0;
+
+       return bound(1, lms_lowest_lives, fl);
+}
+
+void ClearWinners();
+
+// LMS winning condition: game terminates if and only if there's at most one
+// one player who's living lives. Top two scores being equal cancels the time
+// limit.
+int WinningCondition_LMS()
+{
+       entity first_player = NULL;
+       int total_players = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               if (!total_players)
+                       first_player = it;
+               ++total_players;
+       });
+
+       if (total_players)
+       {
+               if (total_players > 1)
+               {
+                       // two or more active players - continue with the game
+
+                       if (autocvar_g_campaign)
+                       {
+                               FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+                                       float pl_lives = GameRules_scoring_add(it, LMS_LIVES, 0);
+                                       if (!pl_lives)
+                                               return WINNING_YES; // human player lost, game over
+                                       break;
+                               });
+                       }
+               }
+               else
+               {
+                       // exactly one player?
+
+                       ClearWinners();
+                       SetWinners(winning, 0); // NOTE: exactly one player is still "player", so this works out
+
+                       if (LMS_NewPlayerLives())
+                       {
+                               // game still running (that is, nobody got removed from the game by a frag yet)? then continue
+                               return WINNING_NO;
+                       }
+                       else
+                       {
+                               // a winner!
+                               // and assign him his first place
+                               GameRules_scoring_add(first_player, LMS_RANK, 1);
+                               if(warmup_stage)
+                                       return WINNING_NO;
+                               else
+                                       return WINNING_YES;
+                       }
+               }
+       }
+       else
+       {
+               // nobody is playing at all...
+               if (LMS_NewPlayerLives())
+               {
+                       // wait for players...
+               }
+               else
+               {
+                       // SNAFU (maybe a draw game?)
+                       ClearWinners();
+                       LOG_TRACE("No players, ending game.");
+                       return WINNING_YES;
+               }
+       }
+
+       // When we get here, we have at least two players who are actually LIVING,
+       // now check if the top two players have equal score.
+       WinningConditionHelper(NULL);
+
+       ClearWinners();
+       if(WinningConditionHelper_winner)
+               WinningConditionHelper_winner.winning = true;
+       if(WinningConditionHelper_topscore == WinningConditionHelper_secondscore)
+               return WINNING_NEVER;
+
+       // Top two have different scores? Way to go for our beloved TIMELIMIT!
+       return WINNING_NO;
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(lms, reset_map_global)
+{
+       lms_lowest_lives = 999;
+}
+
+MUTATOR_HOOKFUNCTION(lms, reset_map_players)
+{
+       FOREACH_CLIENT(true, {
+               TRANSMUTE(Player, it);
+               it.frags = FRAGS_PLAYER;
+               GameRules_scoring_add(it, LMS_LIVES, LMS_NewPlayerLives());
+               PutClientInServer(it);
+       });
+}
+
+MUTATOR_HOOKFUNCTION(lms, PutClientInServer)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.frags == FRAGS_SPECTATOR)
+               TRANSMUTE(Observer, player);
+       else
+       {
+               float tl = GameRules_scoring_add(player, LMS_LIVES, 0);
+               if(tl < lms_lowest_lives)
+                       lms_lowest_lives = tl;
+               if(tl <= 0)
+                       TRANSMUTE(Observer, player);
+               if(warmup_stage)
+                       GameRules_scoring_add(player, LMS_RANK, -GameRules_scoring_add(player, LMS_RANK, 0));
+       }
+}
+
+MUTATOR_HOOKFUNCTION(lms, ForbidSpawn)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(warmup_stage)
+               return false;
+       if(player.frags == FRAGS_SPECTATOR)
+               return true;
+       if(GameRules_scoring_add(player, LMS_LIVES, 0) <= 0)
+       {
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_LMS_NOLIVES);
+               return true;
+       }
+       return false;
+}
+
+MUTATOR_HOOKFUNCTION(lms, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       frag_target.respawn_flags |= RESPAWN_FORCE;
+}
+
+void lms_RemovePlayer(entity player)
+{
+       static int quitters = 0;
+       float player_rank = GameRules_scoring_add(player, LMS_RANK, 0);
+       if (!player_rank)
+       {
+               int pl_cnt = 0;
+               FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
+               if (player.lms_spectate_warning != 2)
+               {
+                       if(IS_BOT_CLIENT(player))
+                               bot_clear(player);
+                       player.frags = FRAGS_LMS_LOSER;
+                       GameRules_scoring_add(player, LMS_RANK, pl_cnt + 1);
+               }
+               else
+               {
+                       lms_lowest_lives = 999;
+                       FOREACH_CLIENT(true, {
+                               if (it.frags == FRAGS_LMS_LOSER)
+                               {
+                                       float it_rank = GameRules_scoring_add(it, LMS_RANK, 0);
+                                       if (it_rank > player_rank && it_rank <= 256)
+                                               GameRules_scoring_add(it, LMS_RANK, -1);
+                                       lms_lowest_lives = 0;
+                               }
+                               else if (it.frags != FRAGS_SPECTATOR)
+                               {
+                                       float tl = GameRules_scoring_add(it, LMS_LIVES, 0);
+                                       if(tl < lms_lowest_lives)
+                                               lms_lowest_lives = tl;
+                               }
+                       });
+                       GameRules_scoring_add(player, LMS_RANK, 665 - quitters); // different from 666
+                       if(!warmup_stage)
+                       {
+                               GameRules_scoring_add(player, LMS_LIVES, -GameRules_scoring_add(player, LMS_LIVES, 0));
+                               ++quitters;
+                       }
+                       player.frags = FRAGS_LMS_LOSER;
+                       TRANSMUTE(Observer, player);
+               }
+               if (pl_cnt == 2 && !warmup_stage) // a player is forfeiting leaving only one player
+                       lms_lowest_lives = 0; // end the game now!
+       }
+
+       if(CS(player).killcount != FRAGS_SPECTATOR)
+               if(GameRules_scoring_add(player, LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_NOLIVES, player.netname);
+               else
+                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_FORFEIT, player.netname);
+}
+
+MUTATOR_HOOKFUNCTION(lms, ClientDisconnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       lms_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(lms, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       if (!IS_PLAYER(player))
+               return true;
+
+       lms_RemovePlayer(player);
+       return true;  // prevent team reset
+}
+
+MUTATOR_HOOKFUNCTION(lms, ClientConnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(GameRules_scoring_add(player, LMS_LIVES, LMS_NewPlayerLives()) <= 0)
+       {
+               GameRules_scoring_add(player, LMS_RANK, 666); // mark as forced spectator for the hud code
+               player.frags = FRAGS_SPECTATOR;
+       }
+}
+
+MUTATOR_HOOKFUNCTION(lms, AutoJoinOnConnection)
+{
+       if(autocvar_g_campaign)
+               return false;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, PlayerPreThink)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(player.deadflag == DEAD_DYING)
+               player.deadflag = DEAD_RESPAWNING;
+}
+
+MUTATOR_HOOKFUNCTION(lms, PlayerRegen)
+{
+       if(autocvar_g_lms_regenerate)
+               return false;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, ForbidThrowCurrentWeapon)
+{
+       // forbode!
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
+{
+       entity frag_target = M_ARGV(1, entity);
+
+       if (!warmup_stage)
+       {
+               // remove a life
+               int tl = GameRules_scoring_add(frag_target, LMS_LIVES, -1);
+               if(tl < lms_lowest_lives)
+                       lms_lowest_lives = tl;
+               if(tl <= 0)
+               {
+                       int pl_cnt = 0;
+                       FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
+                       if(IS_BOT_CLIENT(frag_target))
+                               bot_clear(frag_target);
+                       frag_target.frags = FRAGS_LMS_LOSER;
+                       GameRules_scoring_add(frag_target, LMS_RANK, pl_cnt);
+               }
+       }
+       M_ARGV(2, float) = 0; // frag score
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, SetStartItems)
+{
+       start_items &= ~IT_UNLIMITED_AMMO;
+       start_health       = warmup_start_health       = cvar("g_lms_start_health");
+       start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
+       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
+       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
+       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
+       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
+       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
+}
+
+MUTATOR_HOOKFUNCTION(lms, ForbidPlayerScore_Clear)
+{
+       // don't clear player score
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, FilterItemDefinition)
+{
+       entity definition = M_ARGV(0, entity);
+
+       if (autocvar_g_lms_extra_lives && definition == ITEM_ExtraLife)
+       {
+               return false;
+       }
+       return true;
+}
+
+void lms_extralife(entity this)
+{
+       StartItem(this, ITEM_ExtraLife);
+}
+
+MUTATOR_HOOKFUNCTION(lms, OnEntityPreSpawn)
+{
+       if (!autocvar_g_powerups) return false;
+       if (!autocvar_g_lms_extra_lives) return false;
+
+       entity ent = M_ARGV(0, entity);
+
+       // Can't use .itemdef here
+       if (ent.classname != "item_health_mega") return false;
+
+       entity e = spawn();
+       setthink(e, lms_extralife);
+
+       e.nextthink = time + 0.1;
+       e.spawnflags = ent.spawnflags;
+       e.noalign = ent.noalign;
+       setorigin(e, ent.origin);
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, ItemTouch)
+{
+       entity item = M_ARGV(0, entity);
+       entity toucher = M_ARGV(1, entity);
+
+       if(item.itemdef == ITEM_ExtraLife)
+       {
+               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES);
+               GameRules_scoring_add(toucher, LMS_LIVES, autocvar_g_lms_extra_lives);
+               return MUT_ITEMTOUCH_PICKUP;
+       }
+
+       return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
+{
+       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+               ++M_ARGV(0, int); // activerealplayers
+               ++M_ARGV(1, int); // realplayers
+       });
+
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, ClientCommand_Spectate)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(warmup_stage || player.lms_spectate_warning)
+       {
+               // for the forfeit message...
+               player.lms_spectate_warning = 2;
+       }
+       else
+       {
+               if(player.frags != FRAGS_SPECTATOR && player.frags != FRAGS_LMS_LOSER)
+               {
+                       player.lms_spectate_warning = 1;
+                       sprint(player, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
+               }
+               return MUT_SPECCMD_RETURN;
+       }
+       return MUT_SPECCMD_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(lms, CheckRules_World)
+{
+       M_ARGV(0, float) = WinningCondition_LMS();
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, WantWeapon)
+{
+       M_ARGV(2, bool) = true; // all weapons
+}
+
+MUTATOR_HOOKFUNCTION(lms, GetPlayerStatus)
+{
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(lms, AddPlayerScore)
+{
+       if(game_stopped)
+       if(M_ARGV(0, entity) == SP_LMS_RANK) // score field
+               return true; // allow writing to this field in intermission as it is needed for newly joining players
+}
+
+void lms_Initialize()
+{
+       lms_lowest_lives = 9999;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/lms/lms.qh b/qcsrc/common/gamemodes/gamemode/lms/lms.qh
new file mode 100644 (file)
index 0000000..2889220
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+#include <common/scores.qh>
+.float lms_spectate_warning;
+#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
+void lms_Initialize();
+
+REGISTER_MUTATOR(lms, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+        GameRules_limit_score(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override));
+        GameRules_limit_lead(0);
+        GameRules_score_enabled(false);
+        GameRules_scoring(0, 0, 0, {
+            field(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
+            field(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
+        });
+
+               lms_Initialize();
+       }
+       return 0;
+}
+
+// lives related defs
+float lms_lowest_lives;
+float LMS_NewPlayerLives();
+#endif
index fa718eb16fe9884a74512688212372359fd026b6..426b341a63a077b1316305a435d0975241b490ea 100644 (file)
@@ -195,9 +195,9 @@ void GiveBall(entity plyr, entity ball)
                ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
        }
 
-       plyr.(weaponentity).weapons = plyr.weapons;
+       STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
        plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
-       plyr.weapons = WEPSET(NEXBALL);
+       STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
        Weapon w = WEP_NEXBALL;
        w.wr_resetplayer(w, plyr);
        plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
@@ -828,15 +828,15 @@ MUTATOR_HOOKFUNCTION(nb, PlayerPreThink)
                        {
                                .entity weaponentity = weaponentities[slot];
 
-                               if(player.(weaponentity).weapons)
+                               if(STAT(WEAPONS, player.(weaponentity)))
                                {
-                                       player.weapons = player.(weaponentity).weapons;
+                                       STAT(WEAPONS, player) = STAT(WEAPONS, player.(weaponentity));
                                        Weapon w = WEP_NEXBALL;
                                        w.wr_resetplayer(w, player);
                                        player.(weaponentity).m_switchweapon = player.m_switchweapon;
                                        W_SwitchWeapon(player, player.(weaponentity).m_switchweapon, weaponentity);
 
-                                       player.(weaponentity).weapons = '0 0 0';
+                                       STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
                                }
                        }
                }
@@ -862,13 +862,13 @@ MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
                .entity weaponentity = weaponentities[slot];
-               player.(weaponentity).weapons = '0 0 0';
+               STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
        }
 
        if (nexball_mode & NBM_BASKETBALL)
-               player.weapons |= WEPSET(NEXBALL);
+               STAT(WEAPONS, player) |= WEPSET(NEXBALL);
        else
-               player.weapons = '0 0 0';
+               STAT(WEAPONS, player) = '0 0 0';
 
        return false;
 }
index 2637aeef212b5415a589b42848b99f1b1290fef6..c4f4d32c4262f282d49a12872d9f23a7970ae313 100644 (file)
@@ -1229,7 +1229,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        // Needs weapons?
        int c = 0;
        FOREACH(Weapons, it != WEP_Null, {
-               if(this.weapons & (it.m_wepset))
+               if(STAT(WEAPONS, this) & (it.m_wepset))
                if(++c >= 4)
                        break;
        });
@@ -1248,7 +1248,7 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        {
                // gather health and armor only
                if (it.solid)
-               if ( ((it.health || it.armorvalue) && needarmor) || (it.weapons && needweapons ) )
+               if ( ((it.health || it.armorvalue) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
                if (vdist(it.origin - org, <, sradius))
                {
                        int t = it.bot_pickupevalfunc(this, it);
diff --git a/qcsrc/common/gamemodes/gamemode/race/_mod.inc b/qcsrc/common/gamemodes/gamemode/race/_mod.inc
new file mode 100644 (file)
index 0000000..73f34a5
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/race/race.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/race/_mod.qh b/qcsrc/common/gamemodes/gamemode/race/_mod.qh
new file mode 100644 (file)
index 0000000..1158df5
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/race/race.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/race/race.qc b/qcsrc/common/gamemodes/gamemode/race/race.qc
new file mode 100644 (file)
index 0000000..c98e1b6
--- /dev/null
@@ -0,0 +1,492 @@
+#include "race.qh"
+
+// TODO: sv_race
+#ifdef SVQC
+#include <server/race.qh>
+
+#define autocvar_g_race_laps_limit cvar("g_race_laps_limit")
+float autocvar_g_race_qualifying_timelimit;
+float autocvar_g_race_qualifying_timelimit_override;
+int autocvar_g_race_teams;
+
+// legacy bot roles
+.float race_checkpoint;
+void havocbot_role_race(entity this)
+{
+       if(IS_DEAD(this))
+               return;
+
+       if (navigation_goalrating_timeout(this))
+       {
+               navigation_goalrating_start(this);
+
+               bool raw_touch_check = true;
+               int cp = this.race_checkpoint;
+
+               LABEL(search_racecheckpoints)
+               IL_EACH(g_racecheckpoints, true,
+               {
+                       if(it.cnt == cp || cp == -1)
+                       {
+                               // redirect bot to next goal if it touched the waypoint of an untouchable checkpoint
+                               // e.g. checkpoint in front of Stormkeep's warpzone
+                               // the same workaround is applied in CTS game mode
+                               if (raw_touch_check && vdist(this.origin - it.nearestwaypoint.origin, <, 30))
+                               {
+                                       cp = race_NextCheckpoint(cp);
+                                       raw_touch_check = false;
+                                       goto search_racecheckpoints;
+                               }
+                               navigation_routerating(this, it, 1000000, 5000);
+                       }
+               });
+
+               navigation_goalrating_end(this);
+
+               navigation_goalrating_timeout_set(this);
+       }
+}
+
+void race_ScoreRules()
+{
+    GameRules_score_enabled(false);
+       GameRules_scoring(race_teams, 0, 0, {
+        if (race_teams) {
+            field_team(ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else if (g_race_qualifying) {
+            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+        } else {
+            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
+            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
+            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
+        }
+       });
+}
+
+void race_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
+{
+       if(autocvar_sv_eventlog)
+               GameLogEcho(strcat(":race:", mode, ":", ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
+}
+
+float WinningCondition_Race(float fraglimit)
+{
+       float wc;
+       float n, c;
+
+       n = 0;
+       c = 0;
+       FOREACH_CLIENT(IS_PLAYER(it), {
+               ++n;
+               if(CS(it).race_completed)
+                       ++c;
+       });
+       if(n && (n == c))
+               return WINNING_YES;
+       wc = WinningCondition_Scores(fraglimit, 0);
+
+       // ALWAYS initiate overtime, unless EVERYONE has finished the race!
+       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
+       // do NOT support equality when the laps are all raced!
+               return WINNING_STARTSUDDENDEATHOVERTIME;
+       else
+               return WINNING_NEVER;
+}
+
+float WinningCondition_QualifyingThenRace(float limit)
+{
+       float wc;
+       wc = WinningCondition_Scores(limit, 0);
+
+       // NEVER initiate overtime
+       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
+       {
+               return WINNING_YES;
+       }
+
+       return wc;
+}
+
+MUTATOR_HOOKFUNCTION(rc, ClientKill)
+{
+       if(g_race_qualifying)
+               M_ARGV(1, float) = 0; // killtime
+}
+
+MUTATOR_HOOKFUNCTION(rc, AbortSpeedrun)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(autocvar_g_allow_checkpoints)
+               race_PreparePlayer(player); // nice try
+}
+
+MUTATOR_HOOKFUNCTION(rc, PlayerPhysics)
+{
+       entity player = M_ARGV(0, entity);
+       float dt = M_ARGV(1, float);
+
+       player.race_movetime_frac += dt;
+       float f = floor(player.race_movetime_frac);
+       player.race_movetime_frac -= f;
+       player.race_movetime_count += f;
+       player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
+
+#ifdef SVQC
+       if(IS_PLAYER(player))
+       {
+               if (player.race_penalty)
+                       if (time > player.race_penalty)
+                               player.race_penalty = 0;
+               if(player.race_penalty)
+               {
+                       player.velocity = '0 0 0';
+                       set_movetype(player, MOVETYPE_NONE);
+                       player.disableclientprediction = 2;
+               }
+       }
+#endif
+
+       // force kbd movement for fairness
+       float wishspeed;
+       vector wishvel;
+
+       // if record times matter
+       // ensure nothing EVIL is being done (i.e. div0_evade)
+       // this hinders joystick users though
+       // but it still gives SOME analog control
+       wishvel.x = fabs(CS(player).movement.x);
+       wishvel.y = fabs(CS(player).movement.y);
+       if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
+       {
+               wishvel.z = 0;
+               wishspeed = vlen(wishvel);
+               if(wishvel.x >= 2 * wishvel.y)
+               {
+                       // pure X motion
+                       if(CS(player).movement.x > 0)
+                               CS(player).movement_x = wishspeed;
+                       else
+                               CS(player).movement_x = -wishspeed;
+                       CS(player).movement_y = 0;
+               }
+               else if(wishvel.y >= 2 * wishvel.x)
+               {
+                       // pure Y motion
+                       CS(player).movement_x = 0;
+                       if(CS(player).movement.y > 0)
+                               CS(player).movement_y = wishspeed;
+                       else
+                               CS(player).movement_y = -wishspeed;
+               }
+               else
+               {
+                       // diagonal
+                       if(CS(player).movement.x > 0)
+                               CS(player).movement_x = M_SQRT1_2 * wishspeed;
+                       else
+                               CS(player).movement_x = -M_SQRT1_2 * wishspeed;
+                       if(CS(player).movement.y > 0)
+                               CS(player).movement_y = M_SQRT1_2 * wishspeed;
+                       else
+                               CS(player).movement_y = -M_SQRT1_2 * wishspeed;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, reset_map_global)
+{
+       float s;
+
+       Score_NicePrint(NULL);
+
+       race_ClearRecords();
+       PlayerScore_Sort(race_place, 0, 1, 0);
+
+       FOREACH_CLIENT(true, {
+               if(it.race_place)
+               {
+                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
+                       if(!s)
+                               it.race_place = 0;
+               }
+               race_EventLog(ftos(it.race_place), it);
+       });
+
+       if(g_race_qualifying == 2)
+       {
+               g_race_qualifying = 0;
+               independent_players = 0;
+               cvar_set("fraglimit", ftos(race_fraglimit));
+               cvar_set("leadlimit", ftos(race_leadlimit));
+               cvar_set("timelimit", ftos(race_timelimit));
+               race_ScoreRules();
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, ClientConnect)
+{
+       entity player = M_ARGV(0, entity);
+
+       race_PreparePlayer(player);
+       player.race_checkpoint = -1;
+
+       string rr = RACE_RECORD;
+
+       if(IS_REAL_CLIENT(player))
+       {
+               msg_entity = player;
+               race_send_recordtime(MSG_ONE);
+               race_send_speedaward(MSG_ONE);
+
+               speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+               speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+               race_send_speedaward_alltimebest(MSG_ONE);
+
+               float i;
+               int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+               race_send_rankings_cnt(MSG_ONE);
+               for (i = 1; i <= m; ++i)
+               {
+                       race_SendRankings(i, 0, 0, MSG_ONE);
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, MakePlayerObserver)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(g_race_qualifying)
+       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
+               player.frags = FRAGS_LMS_LOSER;
+       else
+               player.frags = FRAGS_SPECTATOR;
+
+       race_PreparePlayer(player);
+       player.race_checkpoint = -1;
+}
+
+MUTATOR_HOOKFUNCTION(rc, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+       entity spawn_spot = M_ARGV(1, entity);
+
+       if(spawn_spot.target == "")
+               // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+               race_PreparePlayer(player);
+
+       // if we need to respawn, do it right
+       player.race_respawn_checkpoint = player.race_checkpoint;
+       player.race_respawn_spotref = spawn_spot;
+
+       player.race_place = 0;
+}
+
+MUTATOR_HOOKFUNCTION(rc, PutClientInServer)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(IS_PLAYER(player))
+       if(!game_stopped)
+       {
+               if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
+                       race_PreparePlayer(player);
+               else // respawn
+                       race_RetractPlayer(player);
+
+               race_AbandonRaceCheck(player);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, PlayerDies)
+{
+       entity frag_target = M_ARGV(2, entity);
+
+       frag_target.respawn_flags |= RESPAWN_FORCE;
+       race_AbandonRaceCheck(frag_target);
+}
+
+MUTATOR_HOOKFUNCTION(rc, HavocBot_ChooseRole)
+{
+       entity bot = M_ARGV(0, entity);
+
+       bot.havocbot_role = havocbot_role_race;
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(rc, GetPressedKeys)
+{
+       entity player = M_ARGV(0, entity);
+
+       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
+       {
+               if (!player.stored_netname)
+                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
+               if(player.stored_netname != player.netname)
+               {
+                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
+                       strcpy(player.stored_netname, player.netname);
+               }
+       }
+
+       if (!IS_OBSERVER(player))
+       {
+               if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
+               {
+                       speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
+                       speedaward_holder = player.netname;
+                       speedaward_uid = player.crypto_idfp;
+                       speedaward_lastupdate = time;
+               }
+               if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
+               {
+                       string rr = RACE_RECORD;
+                       race_send_speedaward(MSG_ALL);
+                       speedaward_lastsent = speedaward_speed;
+                       if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+                       {
+                               speedaward_alltimebest = speedaward_speed;
+                               speedaward_alltimebest_holder = speedaward_holder;
+                               speedaward_alltimebest_uid = speedaward_uid;
+                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
+                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
+                               race_send_speedaward_alltimebest(MSG_ALL);
+                       }
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, ForbidPlayerScore_Clear)
+{
+       if(g_race_qualifying)
+               return true; // in qualifying, you don't lose score by observing
+}
+
+MUTATOR_HOOKFUNCTION(rc, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(0, float) = race_teams;
+}
+
+MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining)
+{
+       // announce remaining frags if not in qualifying mode
+       if(!g_race_qualifying)
+               return true;
+}
+
+MUTATOR_HOOKFUNCTION(rc, GetRecords)
+{
+       int record_page = M_ARGV(0, int);
+       string ret_string = M_ARGV(1, string);
+
+       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+       {
+               if(MapInfo_Get_ByID(i))
+               {
+                       float r = race_readTime(MapInfo_Map_bspname, 1);
+
+                       if(!r)
+                               continue;
+
+                       string h = race_readName(MapInfo_Map_bspname, 1);
+                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
+               }
+       }
+
+       M_ARGV(1, string) = ret_string;
+}
+
+MUTATOR_HOOKFUNCTION(rc, HideTeamNagger)
+{
+       return true; // doesn't work so well
+}
+
+MUTATOR_HOOKFUNCTION(rc, FixClientCvars)
+{
+       entity player = M_ARGV(0, entity);
+
+       stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
+}
+
+MUTATOR_HOOKFUNCTION(rc, CheckRules_World)
+{
+       float checkrules_timelimit = M_ARGV(1, float);
+       float checkrules_fraglimit = M_ARGV(2, float);
+
+       if(checkrules_timelimit >= 0)
+       {
+               if(!g_race_qualifying)
+               {
+                       M_ARGV(0, float) = WinningCondition_Race(checkrules_fraglimit);
+                       return true;
+               }
+               else if(g_race_qualifying == 2)
+               {
+                       M_ARGV(0, float) = WinningCondition_QualifyingThenRace(checkrules_fraglimit);
+                       return true;
+               }
+       }
+}
+
+MUTATOR_HOOKFUNCTION(rc, ReadLevelCvars)
+{
+       if(g_race_qualifying == 2)
+               warmup_stage = 0;
+}
+
+void race_Initialize()
+{
+       race_ScoreRules();
+       if(g_race_qualifying == 2)
+               warmup_stage = 0;
+}
+
+void rc_SetLimits()
+{
+       int fraglimit_override, leadlimit_override;
+       float timelimit_override, qualifying_override;
+
+       if(autocvar_g_race_teams)
+       {
+               GameRules_teams(true);
+               race_teams = BITS(bound(2, autocvar_g_race_teams, 4));
+       }
+       else
+               race_teams = 0;
+
+       qualifying_override = autocvar_g_race_qualifying_timelimit_override;
+       fraglimit_override = autocvar_g_race_laps_limit;
+       leadlimit_override = 0; // currently not supported by race
+       timelimit_override = autocvar_timelimit_override;
+
+       float want_qualifying = ((qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit) > 0;
+
+       if(autocvar_g_campaign)
+       {
+               g_race_qualifying = 1;
+               independent_players = 1;
+       }
+       else if(want_qualifying)
+       {
+               g_race_qualifying = 2;
+               independent_players = 1;
+               race_fraglimit = (fraglimit_override >= 0) ? fraglimit_override : autocvar_fraglimit;
+               race_leadlimit = (leadlimit_override >= 0) ? leadlimit_override : autocvar_leadlimit;
+               race_timelimit = (timelimit_override >= 0) ? timelimit_override : autocvar_timelimit;
+               qualifying_override = (qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit;
+               fraglimit_override = 0;
+               leadlimit_override = 0;
+               timelimit_override = qualifying_override;
+       }
+       else
+               g_race_qualifying = 0;
+    GameRules_limit_score(fraglimit_override);
+    GameRules_limit_lead(leadlimit_override);
+    GameRules_limit_time(timelimit_override);
+    GameRules_limit_time_qualifying(qualifying_override);
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/race/race.qh b/qcsrc/common/gamemodes/gamemode/race/race.qh
new file mode 100644 (file)
index 0000000..ad966af
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+void rc_SetLimits();
+void race_Initialize();
+
+REGISTER_MUTATOR(rc, false)
+{
+    MUTATOR_STATIC();
+       MUTATOR_ONADD
+       {
+               rc_SetLimits();
+
+               race_Initialize();
+       }
+       return 0;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/tdm/_mod.inc b/qcsrc/common/gamemodes/gamemode/tdm/_mod.inc
new file mode 100644 (file)
index 0000000..ef7137a
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tdm/tdm.qc>
diff --git a/qcsrc/common/gamemodes/gamemode/tdm/_mod.qh b/qcsrc/common/gamemodes/gamemode/tdm/_mod.qh
new file mode 100644 (file)
index 0000000..f1965c1
--- /dev/null
@@ -0,0 +1,2 @@
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tdm/tdm.qh>
diff --git a/qcsrc/common/gamemodes/gamemode/tdm/tdm.qc b/qcsrc/common/gamemodes/gamemode/tdm/tdm.qc
new file mode 100644 (file)
index 0000000..39e5fec
--- /dev/null
@@ -0,0 +1,67 @@
+#include "tdm.qh"
+
+// TODO: sv_tdm
+// TODO? rename to teamdeathmatch
+#ifdef SVQC
+int autocvar_g_tdm_teams;
+int autocvar_g_tdm_teams_override;
+
+/*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
+Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
+Note: If you use spawnfunc_tdm_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
+Keys:
+"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
+"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
+spawnfunc(tdm_team)
+{
+       if(!g_tdm || !this.cnt) { delete(this); return; }
+
+       this.classname = "tdm_team";
+       this.team = this.cnt + 1;
+}
+
+// code from here on is just to support maps that don't have team entities
+void tdm_SpawnTeam (string teamname, int teamcolor)
+{
+       entity this = new_pure(tdm_team);
+       this.netname = teamname;
+       this.cnt = teamcolor - 1;
+       this.team = teamcolor;
+       this.spawnfunc_checked = true;
+       //spawnfunc_tdm_team(this);
+}
+
+void tdm_DelayedInit(entity this)
+{
+       // if no teams are found, spawn defaults
+       if(find(NULL, classname, "tdm_team") == NULL)
+       {
+               LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.");
+
+               int numteams = autocvar_g_tdm_teams_override;
+               if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
+
+               int teams = BITS(bound(2, numteams, 4));
+               if(teams & BIT(0))
+                       tdm_SpawnTeam("Red", NUM_TEAM_1);
+               if(teams & BIT(1))
+                       tdm_SpawnTeam("Blue", NUM_TEAM_2);
+               if(teams & BIT(2))
+                       tdm_SpawnTeam("Yellow", NUM_TEAM_3);
+               if(teams & BIT(3))
+                       tdm_SpawnTeam("Pink", NUM_TEAM_4);
+       }
+}
+
+MUTATOR_HOOKFUNCTION(tdm, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+       M_ARGV(1, string) = "tdm_team";
+       return true;
+}
+
+MUTATOR_HOOKFUNCTION(tdm, Scores_CountFragsRemaining)
+{
+       // announce remaining frags
+       return true;
+}
+#endif
diff --git a/qcsrc/common/gamemodes/gamemode/tdm/tdm.qh b/qcsrc/common/gamemodes/gamemode/tdm/tdm.qh
new file mode 100644 (file)
index 0000000..1c8674a
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.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_STATIC();
+       MUTATOR_ONADD
+       {
+               GameRules_teams(true);
+        GameRules_spawning_teams(autocvar_g_tdm_team_spawns);
+               GameRules_limit_score(autocvar_g_tdm_point_limit);
+        GameRules_limit_lead(autocvar_g_tdm_point_leadlimit);
+
+               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
+       }
+       return 0;
+}
+#endif
index 35a643d53b0eac3dde0e9d317f63667c0c7e5687..979477cbafab6c676c4fdc7cabfeedf43134725b 100644 (file)
@@ -1,5 +1,9 @@
 #pragma once
 
+// TODO: find a better location for these?
+float total_players;
+float redalive, bluealive, yellowalive, pinkalive;
+
 // todo: accept the number of teams as a parameter
 void GameRules_teams(bool value);
 
index 8520075019b97c616107cabf94420ef9a27d58d6..9075c0912ed2a5044ba8e7b80b299a05723f31ba 100644 (file)
@@ -21,9 +21,11 @@ const int Inventory_groups_minor = 8; // ceil(Items_MAX / Inventory_groups_major
 #define G_MINOR(id) ((id) % Inventory_groups_minor)
 
 #ifdef CSQC
+Inventory g_inventory;
 NET_HANDLE(ENT_CLIENT_INVENTORY, bool isnew)
 {
     make_pure(this);
+    g_inventory = this;
     const int majorBits = ReadShort();
     for (int i = 0; i < Inventory_groups_major; ++i) {
         if (!(majorBits & BIT(i))) {
index b7fc933e8b5dbaf35dde8a37fca1762c51a4e08a..31b8f43cb17fe6041ec7c6155278db7aaad5823c 100644 (file)
@@ -7,6 +7,10 @@
 #include <common/stats.qh>
 #endif
 
+#ifdef SVQC
+#include <server/items.qh>
+#endif
+
 const int IT_UNLIMITED_WEAPON_AMMO             =  BIT(0); // when this bit is set, using a weapon does not reduce ammo. Checkpoints can give this powerup.
 const int IT_UNLIMITED_SUPERWEAPONS            =  BIT(1); // when this bit is set, superweapons don't expire. Checkpoints can give this powerup.
 
@@ -48,7 +52,16 @@ const int IT_PICKUPMASK                      = IT_UNLIMITED_AMMO | IT_JETPACK | IT_FU
 .float  invincible_finished = _STAT(INVINCIBLE_FINISHED);
 
 #define SPAWNFUNC_ITEM(name, item) \
-    spawnfunc(name) { StartItem(this, item); }
+    spawnfunc(name) \
+       { \
+               if (!Item_IsDefinitionAllowed(item)) \
+               { \
+                       startitem_failed = true; \
+                       delete(this); \
+                       return; \
+               } \
+               StartItem(this, item); \
+       }
 
 #else
 
@@ -59,9 +72,7 @@ const int IT_PICKUPMASK                       = IT_UNLIMITED_AMMO | IT_JETPACK | IT_FU
 enum
 {
        ITEM_FLAG_NORMAL = BIT(0), ///< Item is usable during normal gameplay.
-       ITEM_FLAG_INSTAGIB = BIT(1), ///< Item is usable in instagib.
-       ITEM_FLAG_OVERKILL = BIT(2), ///< Item is usable in overkill.
-       ITEM_FLAG_MUTATORBLOCKED = BIT(3)
+       ITEM_FLAG_MUTATORBLOCKED = BIT(1)
 };
 
 #define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
index 1d5bd87baceb116b7e241f9955e4e12b8f6d3ee9..7c5c12af7284268c1b14c2eb4db1d464bf89b52c 100644 (file)
@@ -38,7 +38,7 @@ MODEL(Bullets_ITEM, Item_Model("a_bullets.mdl"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_nails);
-void ammo_bullets_init(entity item)
+void ammo_bullets_init(Pickup this, entity item)
 {
     if(!item.ammo_nails)
         item.ammo_nails = g_pickup_nails;
@@ -72,7 +72,7 @@ MODEL(Cells_ITEM, Item_Model("a_cells.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_cells);
-void ammo_cells_init(entity item)
+void ammo_cells_init(Pickup this, entity item)
 {
     if(!item.ammo_cells)
         item.ammo_cells = g_pickup_cells;
@@ -102,7 +102,7 @@ MODEL(Plasma_ITEM, Item_Model("a_cells.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_plasma);
-void ammo_plasma_init(entity item)
+void ammo_plasma_init(Pickup this, entity item)
 {
     if(!item.ammo_plasma)
         item.ammo_plasma = g_pickup_plasma;
@@ -132,7 +132,7 @@ MODEL(Rockets_ITEM, Item_Model("a_rockets.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_rockets);
-void ammo_rockets_init(entity item)
+void ammo_rockets_init(Pickup this, entity item)
 {
     if(!item.ammo_rockets)
         item.ammo_rockets = g_pickup_rockets;
@@ -162,7 +162,7 @@ MODEL(Shells_ITEM, Item_Model("a_shells.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_shells);
-void ammo_shells_init(entity item)
+void ammo_shells_init(Pickup this, entity item)
 {
     if(!item.ammo_shells)
         item.ammo_shells = g_pickup_shells;
index 7f37c75aec002465260b1852810253e05c6a4b11..880a932d7c27db58ceb0cfc4943f36059a296483 100644 (file)
@@ -22,7 +22,7 @@ SOUND(ArmorSmall, Item_Sound("armor1"));
 PROPERTY(float, g_pickup_armorsmall_anyway);
 PROPERTY(int, g_pickup_armorsmall);
 PROPERTY(int, g_pickup_armorsmall_max);
-void item_armorsmall_init(entity item)
+void item_armorsmall_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armorsmall_max;
@@ -34,7 +34,7 @@ void item_armorsmall_init(entity item)
 REGISTER_ITEM(ArmorSmall, Armor) {
     this.m_canonical_spawnfunc = "item_armor_small";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+    this.spawnflags = ITEM_FLAG_NORMAL;
     this.m_model                =   MDL_ArmorSmall_ITEM;
     this.m_sound                =   SND_ArmorSmall;
 #endif
@@ -60,7 +60,7 @@ SOUND(ArmorMedium, Item_Sound("armor10"));
 PROPERTY(float, g_pickup_armormedium_anyway);
 PROPERTY(int, g_pickup_armormedium);
 PROPERTY(int, g_pickup_armormedium_max);
-void item_armormedium_init(entity item)
+void item_armormedium_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armormedium_max;
@@ -72,7 +72,7 @@ void item_armormedium_init(entity item)
 REGISTER_ITEM(ArmorMedium, Armor) {
     this.m_canonical_spawnfunc = "item_armor_medium";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+    this.spawnflags = ITEM_FLAG_NORMAL;
     this.m_model                =   MDL_ArmorMedium_ITEM;
     this.m_sound                =   SND_ArmorMedium;
 #endif
@@ -98,7 +98,7 @@ SOUND(ArmorBig, Item_Sound("armor17_5"));
 PROPERTY(float, g_pickup_armorbig_anyway);
 PROPERTY(int, g_pickup_armorbig);
 PROPERTY(int, g_pickup_armorbig_max);
-void item_armorbig_init(entity item)
+void item_armorbig_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armorbig_max;
@@ -110,7 +110,7 @@ void item_armorbig_init(entity item)
 REGISTER_ITEM(ArmorBig, Armor) {
     this.m_canonical_spawnfunc = "item_armor_big";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+    this.spawnflags = ITEM_FLAG_NORMAL;
     this.m_model                =   MDL_ArmorBig_ITEM;
     this.m_sound                =   SND_ArmorBig;
 #endif
@@ -138,7 +138,7 @@ SOUND(ArmorMega, Item_Sound("armor25"));
 PROPERTY(float, g_pickup_armormega_anyway);
 PROPERTY(int, g_pickup_armormega);
 PROPERTY(int, g_pickup_armormega_max);
-void item_armormega_init(entity item)
+void item_armormega_init(Pickup this, entity item)
 {
     if(!item.max_armorvalue)
         item.max_armorvalue = g_pickup_armormega_max;
@@ -150,7 +150,7 @@ void item_armormega_init(entity item)
 REGISTER_ITEM(ArmorMega, Armor) {
     this.m_canonical_spawnfunc = "item_armor_mega";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+    this.spawnflags = ITEM_FLAG_NORMAL;
     this.m_model                =   MDL_ArmorMega_ITEM;
     this.m_sound                =   SND_ArmorMega;
 #endif
index da431086e18587448cf697c8127390fd166134f0..6a5ffc5ca478677cdece01528f17c5509ab333cf 100644 (file)
@@ -22,7 +22,7 @@ SOUND(HealthSmall, Item_Sound("minihealth"));
 PROPERTY(float, g_pickup_healthsmall_anyway);
 PROPERTY(int, g_pickup_healthsmall);
 PROPERTY(int, g_pickup_healthsmall_max);
-void item_healthsmall_init(entity item)
+void item_healthsmall_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthsmall_max;
@@ -60,7 +60,7 @@ SOUND(HealthMedium, Item_Sound("mediumhealth"));
 PROPERTY(float, g_pickup_healthmedium_anyway);
 PROPERTY(int, g_pickup_healthmedium);
 PROPERTY(int, g_pickup_healthmedium_max);
-void item_healthmedium_init(entity item)
+void item_healthmedium_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthmedium_max;
@@ -98,7 +98,7 @@ SOUND(HealthBig, Item_Sound("mediumhealth"));
 PROPERTY(float, g_pickup_healthbig_anyway);
 PROPERTY(int, g_pickup_healthbig);
 PROPERTY(int, g_pickup_healthbig_max);
-void item_healthbig_init(entity item)
+void item_healthbig_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthbig_max;
@@ -138,7 +138,7 @@ SOUND(HealthMega, Item_Sound("megahealth"));
 PROPERTY(float, g_pickup_healthmega_anyway);
 PROPERTY(int, g_pickup_healthmega);
 PROPERTY(int, g_pickup_healthmega_max);
-void item_healthmega_init(entity item)
+void item_healthmega_init(Pickup this, entity item)
 {
     if(!item.max_health)
         item.max_health = g_pickup_healthmega_max;
@@ -150,7 +150,7 @@ void item_healthmega_init(entity item)
 REGISTER_ITEM(HealthMega, Health) {
     this.m_canonical_spawnfunc = "item_health_mega";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+    this.spawnflags = ITEM_FLAG_NORMAL;
     this.m_model                =   MDL_HealthMega_ITEM;
     this.m_sound                =   SND_HealthMega;
 #endif
index 284bf3d390fce1c7b62653a9570b9ef20a7dffe5..73f55e83f5a225a82605e5320f3de8291bf26c03 100644 (file)
@@ -17,7 +17,7 @@ MODEL(Jetpack_ITEM, Item_Model("g_jetpack.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_fuel_jetpack);
-void powerup_jetpack_init(entity item)
+void powerup_jetpack_init(Pickup this, entity item)
 {
     if(!item.ammo_fuel)
         item.ammo_fuel = g_pickup_fuel_jetpack;
@@ -55,7 +55,7 @@ MODEL(JetpackFuel_ITEM, Item_Model("g_fuel.md3"));
 
 #ifdef SVQC
 PROPERTY(int, g_pickup_fuel);
-void ammo_fuel_init(entity item)
+void ammo_fuel_init(Pickup this, entity item)
 {
     if(!item.ammo_fuel)
         item.ammo_fuel = g_pickup_fuel;
index fb4bc28cd8ede336f7d6d656ca25edbdd4972e42..0f09901af214c9c24bd78023b163b365400bd8d2 100644 (file)
@@ -42,7 +42,7 @@ CLASS(Pickup, GameItem)
     ATTRIB(Pickup, m_respawntime, float());
     ATTRIB(Pickup, m_respawntimejitter, float());
     ATTRIB(Pickup, m_pickupanyway, float());
-    ATTRIB(Pickup, m_iteminit, void(entity item));
+    ATTRIB(Pickup, m_iteminit, void(Pickup this, entity item));
     float Item_GiveTo(entity item, entity player);
     METHOD(Pickup, giveTo, bool(Pickup this, entity item, entity player));
     bool ITEM_HANDLE(Pickup, Pickup this, entity item, entity player);
index fe47b63430ddd1726b774f080f56905a4dc7568c..1c10afa488a581065888af5fa7a7324e82ca2eb6 100644 (file)
@@ -24,7 +24,7 @@ SOUND(Strength, Item_Sound("powerup"));
 
 #ifdef SVQC
 float autocvar_g_balance_powerup_strength_time;
-void powerup_strength_init(entity item)
+void powerup_strength_init(Pickup this, entity item)
 {
     if(!item.strength_finished)
         item.strength_finished = autocvar_g_balance_powerup_strength_time;
@@ -60,7 +60,7 @@ SOUND(Shield, Item_Sound("powerup_shield"));
 
 #ifdef SVQC
 float autocvar_g_balance_powerup_invincible_time;
-void powerup_shield_init(entity item)
+void powerup_shield_init(Pickup this, entity item)
 {
     if(!item.invincible_finished)
         item.invincible_finished = autocvar_g_balance_powerup_invincible_time;
index 2dd84596e46991e8f3f75daeb63b524273825d01..4addd24001f6d32a594424a2761855c222f3b300 100644 (file)
@@ -96,7 +96,7 @@ REGISTRY_CHECK(Gametypes)
 CLASS(Deathmatch, Gametype)
     INIT(Deathmatch)
     {
-        this.gametype_init(this, _("Deathmatch"),"dm","g_dm",false,"","timelimit=20 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
+        this.gametype_init(this, _("Deathmatch"),"dm","g_dm",false,"","timelimit=15 pointlimit=30 leadlimit=0",_("Score as many frags as you can"));
     }
     METHOD(Deathmatch, m_isAlwaysSupported, bool(Gametype this, int spawnpoints, float diameter))
     {
@@ -181,7 +181,7 @@ REGISTER_GAMETYPE(CTS, NEW(RaceCTS));
 CLASS(TeamDeathmatch, Gametype)
     INIT(TeamDeathmatch)
     {
-        this.gametype_init(this, _("Team Deathmatch"),"tdm","g_tdm",true,"","timelimit=20 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
+        this.gametype_init(this, _("Team Deathmatch"),"tdm","g_tdm",true,"","timelimit=15 pointlimit=50 teams=2 leadlimit=0",_("Help your team score the most frags against the enemy team"));
     }
     METHOD(TeamDeathmatch, m_parse_mapinfo, bool(string k, string v))
     {
diff --git a/qcsrc/common/mapobjects/_mod.inc b/qcsrc/common/mapobjects/_mod.inc
new file mode 100644 (file)
index 0000000..1aab2b9
--- /dev/null
@@ -0,0 +1,11 @@
+// generated file; do not modify
+#include <common/mapobjects/models.qc>
+#include <common/mapobjects/platforms.qc>
+#include <common/mapobjects/subs.qc>
+#include <common/mapobjects/teleporters.qc>
+#include <common/mapobjects/triggers.qc>
+
+#include <common/mapobjects/func/_mod.inc>
+#include <common/mapobjects/misc/_mod.inc>
+#include <common/mapobjects/target/_mod.inc>
+#include <common/mapobjects/trigger/_mod.inc>
diff --git a/qcsrc/common/mapobjects/_mod.qh b/qcsrc/common/mapobjects/_mod.qh
new file mode 100644 (file)
index 0000000..ebb7a43
--- /dev/null
@@ -0,0 +1,11 @@
+// generated file; do not modify
+#include <common/mapobjects/models.qh>
+#include <common/mapobjects/platforms.qh>
+#include <common/mapobjects/subs.qh>
+#include <common/mapobjects/teleporters.qh>
+#include <common/mapobjects/triggers.qh>
+
+#include <common/mapobjects/func/_mod.qh>
+#include <common/mapobjects/misc/_mod.qh>
+#include <common/mapobjects/target/_mod.qh>
+#include <common/mapobjects/trigger/_mod.qh>
diff --git a/qcsrc/common/mapobjects/defs.qh b/qcsrc/common/mapobjects/defs.qh
new file mode 100644 (file)
index 0000000..45afb51
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma once
+
+//-----------
+// SPAWNFLAGS
+//-----------
+const int START_ENABLED = BIT(0);
+const int START_DISABLED = BIT(0);
+const int ALL_ENTITIES = BIT(1);
+const int ON_MAPLOAD = BIT(1);
+const int INVERT_TEAMS = BIT(2);
+const int CRUSH = BIT(2);
+const int NOSPLASH = BIT(8); // generic anti-splashdamage spawnflag
+const int ONLY_PLAYERS = BIT(14);
+
+// triggers
+const int SPAWNFLAG_NOMESSAGE = BIT(0);
+const int SPAWNFLAG_NOTOUCH = BIT(0);
+
+//----------
+// SENDFLAGS
+//----------
+const int SF_TRIGGER_INIT = BIT(0);
+const int SF_TRIGGER_UPDATE = BIT(1);
+const int SF_TRIGGER_RESET = BIT(2);
+
+//----------------
+// STATES & ACTIVE
+//----------------
+#ifdef CSQC
+// this stuff is defined in the server side engine VM, so we must define it separately here
+const int STATE_TOP = 0;
+const int STATE_BOTTOM = 1;
+const int STATE_UP = 2;
+const int STATE_DOWN = 3;
+
+const int ACTIVE_NOT = 0;
+const int ACTIVE_ACTIVE = 1;
+const int ACTIVE_IDLE = 2;
+const int ACTIVE_BUSY = 2;
+const int ACTIVE_TOGGLE = 3;
+#endif
diff --git a/qcsrc/common/mapobjects/func/_mod.inc b/qcsrc/common/mapobjects/func/_mod.inc
new file mode 100644 (file)
index 0000000..0c82e97
--- /dev/null
@@ -0,0 +1,18 @@
+// generated file; do not modify
+#include <common/mapobjects/func/bobbing.qc>
+#include <common/mapobjects/func/breakable.qc>
+#include <common/mapobjects/func/button.qc>
+#include <common/mapobjects/func/conveyor.qc>
+#include <common/mapobjects/func/door.qc>
+#include <common/mapobjects/func/door_rotating.qc>
+#include <common/mapobjects/func/door_secret.qc>
+#include <common/mapobjects/func/fourier.qc>
+#include <common/mapobjects/func/ladder.qc>
+#include <common/mapobjects/func/pendulum.qc>
+#include <common/mapobjects/func/plat.qc>
+#include <common/mapobjects/func/pointparticles.qc>
+#include <common/mapobjects/func/rainsnow.qc>
+#include <common/mapobjects/func/rotating.qc>
+#include <common/mapobjects/func/stardust.qc>
+#include <common/mapobjects/func/train.qc>
+#include <common/mapobjects/func/vectormamamam.qc>
diff --git a/qcsrc/common/mapobjects/func/_mod.qh b/qcsrc/common/mapobjects/func/_mod.qh
new file mode 100644 (file)
index 0000000..052edb9
--- /dev/null
@@ -0,0 +1,18 @@
+// generated file; do not modify
+#include <common/mapobjects/func/bobbing.qh>
+#include <common/mapobjects/func/breakable.qh>
+#include <common/mapobjects/func/button.qh>
+#include <common/mapobjects/func/conveyor.qh>
+#include <common/mapobjects/func/door.qh>
+#include <common/mapobjects/func/door_rotating.qh>
+#include <common/mapobjects/func/door_secret.qh>
+#include <common/mapobjects/func/fourier.qh>
+#include <common/mapobjects/func/ladder.qh>
+#include <common/mapobjects/func/pendulum.qh>
+#include <common/mapobjects/func/plat.qh>
+#include <common/mapobjects/func/pointparticles.qh>
+#include <common/mapobjects/func/rainsnow.qh>
+#include <common/mapobjects/func/rotating.qh>
+#include <common/mapobjects/func/stardust.qh>
+#include <common/mapobjects/func/train.qh>
+#include <common/mapobjects/func/vectormamamam.qh>
diff --git a/qcsrc/common/mapobjects/func/bobbing.qc b/qcsrc/common/mapobjects/func/bobbing.qc
new file mode 100644 (file)
index 0000000..b647e15
--- /dev/null
@@ -0,0 +1,85 @@
+#include "bobbing.qh"
+#ifdef SVQC
+.float height;
+void func_bobbing_controller_think(entity this)
+{
+       vector v;
+       this.nextthink = time + 0.1;
+
+       if(this.owner.active != ACTIVE_ACTIVE)
+       {
+               this.owner.velocity = '0 0 0';
+               return;
+       }
+
+       // calculate sinewave using makevectors
+       makevectors((this.nextthink * this.owner.cnt + this.owner.phase * 360) * '0 1 0');
+       v = this.owner.destvec + this.owner.movedir * v_forward_y;
+       if(this.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
+               // * 10 so it will arrive in 0.1 sec
+               this.owner.velocity = (v - this.owner.origin) * 10;
+}
+
+/*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
+Brush model that moves back and forth on one axis (default Z).
+speed : how long one cycle takes in seconds (default 4)
+height : how far the cycle moves (default 32)
+phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise : path/name of looping .wav file to play.
+dmg : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+spawnfunc(func_bobbing)
+{
+       entity controller;
+       if (this.noise != "")
+       {
+               precache_sound(this.noise);
+               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+       }
+       if (!this.speed)
+               this.speed = 4;
+       if (!this.height)
+               this.height = 32;
+       // center of bobbing motion
+       this.destvec = this.origin;
+       // time scale to get degrees
+       this.cnt = 360 / this.speed;
+
+       this.active = ACTIVE_ACTIVE;
+
+       // damage when blocked
+       setblocked(this, generic_plat_blocked);
+       if(this.dmg && (this.message == ""))
+               this.message = " was squished";
+    if(this.dmg && (this.message2 == ""))
+               this.message2 = "was squished by";
+       if(this.dmg && (!this.dmgtime))
+               this.dmgtime = 0.25;
+       this.dmgtime2 = time;
+
+       // how far to bob
+       if (this.spawnflags & BOBBING_XAXIS)
+               this.movedir = '1 0 0' * this.height;
+       else if (this.spawnflags & BOBBING_YAXIS)
+               this.movedir = '0 1 0' * this.height;
+       else // Z
+               this.movedir = '0 0 1' * this.height;
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+
+       // wait for targets to spawn
+       controller = new(func_bobbing_controller);
+       controller.owner = this;
+       controller.nextthink = time + 1;
+       setthink(controller, func_bobbing_controller_think);
+       this.nextthink = this.ltime + 999999999;
+       setthink(this, SUB_NullThink);
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       this.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/bobbing.qh b/qcsrc/common/mapobjects/func/bobbing.qh
new file mode 100644 (file)
index 0000000..58f7bb7
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const int BOBBING_XAXIS = BIT(0);
+const int BOBBING_YAXIS = BIT(1);
diff --git a/qcsrc/common/mapobjects/func/breakable.qc b/qcsrc/common/mapobjects/func/breakable.qc
new file mode 100644 (file)
index 0000000..d8f6cb1
--- /dev/null
@@ -0,0 +1,373 @@
+#include "breakable.qh"
+#ifdef SVQC
+
+#include <server/g_damage.qh>
+#include <server/bot/api.qh>
+#include <common/csqcmodel_settings.qh>
+#include <lib/csqcmodel/sv_model.qh>
+#include <server/weapons/common.qh>
+
+.entity sprite;
+
+.float dmg;
+.float dmg_edge;
+.float dmg_radius;
+.float dmg_force;
+.float debrismovetype;
+.float debrissolid;
+.vector debrisvelocity;
+.vector debrisvelocityjitter;
+.vector debrisavelocityjitter;
+.float debristime;
+.float debristimejitter;
+.float debrisfadetime;
+.float debrisdamageforcescale;
+.float debrisskin;
+
+.string mdl_dead; // or "" to hide when broken
+.string debris; // space separated list of debris models
+// other fields:
+//   mdl = particle effect name
+//   count = particle effect multiplier
+//   targetname = target to trigger to unbreak the model
+//   target = targets to trigger when broken
+//   health = amount of damage it can take
+//   spawnflags:
+//     START_DISABLED: needs to be triggered to activate
+//     BREAKABLE_INDICATE_DAMAGE: indicate damage
+//     BREAKABLE_NODAMAGE: don't take direct damage (needs to be triggered to 'explode', then triggered again to restore)
+//     NOSPLASH: don't take splash damage
+// notes:
+//   for mdl_dead to work, origin must be set (using a common/origin brush).
+//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
+//   want that!
+
+void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
+
+//
+// func_breakable
+// - basically func_assault_destructible for general gameplay use
+//
+void LaunchDebris (entity this, string debrisname, vector force)
+{
+       entity dbr = spawn();
+       vector org = this.absmin
+                  + '1 0 0' * random() * (this.absmax.x - this.absmin.x)
+                  + '0 1 0' * random() * (this.absmax.y - this.absmin.y)
+                  + '0 0 1' * random() * (this.absmax.z - this.absmin.z);
+       setorigin(dbr, org);
+       _setmodel (dbr, debrisname );
+       dbr.skin = this.debrisskin;
+       dbr.colormap = this.colormap; // inherit team colors
+       dbr.owner = this; // do not be affected by our own explosion
+       set_movetype(dbr, this.debrismovetype);
+       dbr.solid = this.debrissolid;
+       if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
+               setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
+       dbr.velocity_x = this.debrisvelocity.x + this.debrisvelocityjitter.x * crandom();
+       dbr.velocity_y = this.debrisvelocity.y + this.debrisvelocityjitter.y * crandom();
+       dbr.velocity_z = this.debrisvelocity.z + this.debrisvelocityjitter.z * crandom();
+       dbr.velocity = dbr.velocity + force * this.debrisdamageforcescale;
+       dbr.angles = this.angles;
+       dbr.avelocity_x = random()*this.debrisavelocityjitter.x;
+       dbr.avelocity_y = random()*this.debrisavelocityjitter.y;
+       dbr.avelocity_z = random()*this.debrisavelocityjitter.z;
+       dbr.damageforcescale = this.debrisdamageforcescale;
+       if(dbr.damageforcescale)
+               dbr.takedamage = DAMAGE_YES;
+       SUB_SetFade(dbr, time + this.debristime + crandom() * this.debristimejitter, this.debrisfadetime);
+}
+
+void func_breakable_colormod(entity this)
+{
+       float h;
+       if (!(this.spawnflags & BREAKABLE_INDICATE_DAMAGE))
+               return;
+       h = this.health / this.max_health;
+       if(h < 0.25)
+               this.colormod = '1 0 0';
+       else if(h <= 0.75)
+               this.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
+       else
+               this.colormod = '1 1 1';
+}
+
+void func_breakable_look_destroyed(entity this)
+{
+       float floorZ;
+
+       if(this.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
+               this.dropped_origin = this.origin;
+
+       if(this.mdl_dead == "")
+               this.effects |= EF_NODRAW;
+       else {
+               if (this.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
+                       floorZ = this.absmin.z;
+                       setorigin(this, ((this.absmax + this.absmin) * 0.5));
+                       this.origin_z = floorZ;
+               }
+               _setmodel(this, this.mdl_dead);
+               ApplyMinMaxScaleAngles(this);
+               this.effects &= ~EF_NODRAW;
+       }
+
+       this.solid = SOLID_NOT;
+}
+
+void func_breakable_look_restore(entity this)
+{
+       _setmodel(this, this.mdl);
+       ApplyMinMaxScaleAngles(this);
+       this.effects &= ~EF_NODRAW;
+
+       if(this.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
+               setorigin(this, this.dropped_origin);
+
+       this.solid = SOLID_BSP;
+}
+
+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 = STATE_BROKEN;
+       if(this.spawnflags & BREAKABLE_NODAMAGE)
+               this.use = func_null;
+       func_breakable_colormod(this);
+       if (this.noise1)
+               stopsound (this, CH_TRIGGER_SINGLE);
+}
+
+void func_breakable_think(entity this)
+{
+       this.nextthink = time;
+       CSQCMODEL_AUTOUPDATE(this);
+}
+
+void func_breakable_destroy(entity this, entity actor, entity trigger);
+void func_breakable_behave_restore(entity this)
+{
+       this.health = this.max_health;
+       if(this.sprite)
+       {
+               WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
+               WaypointSprite_UpdateHealth(this.sprite, this.health);
+       }
+       if(!(this.spawnflags & BREAKABLE_NODAMAGE))
+       {
+               this.takedamage = DAMAGE_AIM;
+               if(!this.bot_attack)
+                       IL_PUSH(g_bot_targets, this);
+               this.bot_attack = true;
+               this.event_damage = func_breakable_damage;
+       }
+       if(this.spawnflags & BREAKABLE_NODAMAGE)
+               this.use = func_breakable_destroy; // don't need to set it usually, as .use isn't reset
+       this.state = STATE_ALIVE;
+       //this.nextthink = 0; // cancel auto respawn
+       setthink(this, func_breakable_think);
+       this.nextthink = time + 0.1;
+       func_breakable_colormod(this);
+       if (this.noise1)
+               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+}
+
+void func_breakable_init_for_player(entity this, entity player)
+{
+       if (this.noise1 && this.state == STATE_ALIVE && IS_REAL_CLIENT(player))
+       {
+               msg_entity = player;
+               soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       }
+}
+
+void func_breakable_destroyed(entity this)
+{
+       func_breakable_look_destroyed(this);
+       func_breakable_behave_destroyed(this);
+}
+
+void func_breakable_restore(entity this, entity actor, entity trigger)
+{
+       func_breakable_look_restore(this);
+       func_breakable_behave_restore(this);
+}
+
+void func_breakable_restore_self(entity this)
+{
+       func_breakable_restore(this, NULL, NULL);
+}
+
+vector debrisforce; // global, set before calling this
+void func_breakable_destroy(entity this, entity actor, entity trigger)
+{
+       float n, i;
+       string oldmsg;
+
+       entity act = this.owner;
+       this.owner = NULL; // set by W_PrepareExplosionByDamage
+
+       // now throw around the debris
+       n = tokenize_console(this.debris);
+       for(i = 0; i < n; ++i)
+               LaunchDebris(this, argv(i), debrisforce);
+
+       func_breakable_destroyed(this);
+
+       if(this.noise)
+               _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+
+       if(this.dmg)
+               RadiusDamage(this, act, this.dmg, this.dmg_edge, this.dmg_radius, this, NULL, this.dmg_force, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, NULL);
+
+       if(this.cnt) // TODO
+               __pointparticles(this.cnt, this.absmin * 0.5 + this.absmax * 0.5, '0 0 0', this.count);
+
+       if(this.respawntime)
+       {
+               CSQCMODEL_AUTOUPDATE(this);
+               setthink(this, func_breakable_restore_self);
+               this.nextthink = time + this.respawntime + crandom() * this.respawntimejitter;
+       }
+
+       oldmsg = this.message;
+       this.message = "";
+       SUB_UseTargets(this, act, trigger);
+       this.message = oldmsg;
+}
+
+void func_breakable_destroy_self(entity this)
+{
+       func_breakable_destroy(this, NULL, NULL);
+}
+
+void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(this.state == STATE_BROKEN)
+               return;
+       if(this.spawnflags & NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       if(this.team)
+               if(attacker.team == this.team)
+                       return;
+       this.pain_finished = time;
+       this.health = this.health - damage;
+       if(this.sprite)
+       {
+               WaypointSprite_Ping(this.sprite);
+               WaypointSprite_UpdateHealth(this.sprite, this.health);
+       }
+       func_breakable_colormod(this);
+
+       if(this.health <= 0)
+       {
+               debrisforce = force;
+
+               this.takedamage = DAMAGE_NO;
+               this.event_damage = func_null;
+
+               if(IS_CLIENT(attacker)) //&& this.classname == "func_assault_destructible")
+               {
+                       this.owner = attacker;
+                       this.realowner = attacker;
+               }
+
+               // do not explode NOW but in the NEXT FRAME!
+               // because recursive calls to RadiusDamage are not allowed
+               this.nextthink = time;
+               CSQCMODEL_AUTOUPDATE(this);
+               setthink(this, func_breakable_destroy_self);
+       }
+}
+
+void func_breakable_reset(entity this)
+{
+       this.team = this.team_saved;
+       func_breakable_look_restore(this);
+       if(this.spawnflags & START_DISABLED)
+               func_breakable_behave_destroyed(this);
+       else
+               func_breakable_behave_restore(this);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+spawnfunc(func_breakable)
+{
+       float n, i;
+       if(!this.health)
+               this.health = 100;
+       this.max_health = this.health;
+
+       // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
+       if(!this.debrismovetype) this.debrismovetype = MOVETYPE_BOUNCE;
+       if(!this.debrissolid) this.debrissolid = SOLID_NOT;
+       if(this.debrisvelocity == '0 0 0') this.debrisvelocity = '0 0 140';
+       if(this.debrisvelocityjitter == '0 0 0') this.debrisvelocityjitter = '70 70 70';
+       if(this.debrisavelocityjitter == '0 0 0') this.debrisavelocityjitter = '600 600 600';
+       if(!this.debristime) this.debristime = 3.5;
+       if(!this.debristimejitter) this.debristime = 2.5;
+
+       if(this.mdl != "")
+               this.cnt = _particleeffectnum(this.mdl);
+       if(this.count == 0)
+               this.count = 1;
+
+       if(this.message == "")
+               this.message = "got too close to an explosion";
+       if(this.message2 == "")
+               this.message2 = "was pushed into an explosion by";
+       if(!this.dmg_radius)
+               this.dmg_radius = 150;
+       if(!this.dmg_force)
+               this.dmg_force = 200;
+
+       this.mdl = this.model;
+       SetBrushEntityModel(this);
+
+       if(this.spawnflags & BREAKABLE_NODAMAGE)
+               this.use = func_breakable_destroy;
+       else
+               this.use = func_breakable_restore;
+
+       if(this.spawnflags & BREAKABLE_NODAMAGE)
+       {
+               this.takedamage = DAMAGE_NO;
+               this.event_damage = func_null;
+               this.bot_attack = false;
+       }
+
+       // precache all the models
+       if (this.mdl_dead)
+               precache_model(this.mdl_dead);
+       n = tokenize_console(this.debris);
+       for(i = 0; i < n; ++i)
+               precache_model(argv(i));
+       if(this.noise)
+               precache_sound(this.noise);
+       if(this.noise1)
+               precache_sound(this.noise1);
+
+       this.team_saved = this.team;
+       IL_PUSH(g_saved_team, this);
+       this.dropped_origin = this.origin;
+
+       this.reset = func_breakable_reset;
+       this.reset(this);
+
+       IL_PUSH(g_initforplayer, this);
+       this.init_for_player = func_breakable_init_for_player;
+
+       CSQCMODEL_AUTOINIT(this);
+}
+
+// for use in maps with a "model" key set
+spawnfunc(misc_breakablemodel) {
+       spawnfunc_func_breakable(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/breakable.qh b/qcsrc/common/mapobjects/func/breakable.qh
new file mode 100644 (file)
index 0000000..0efbcfa
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+
+const int BREAKABLE_INDICATE_DAMAGE = BIT(1);
+const int BREAKABLE_NODAMAGE = BIT(2);
+
+const int STATE_ALIVE = 0;
+const int STATE_BROKEN = 1;
+
+#ifdef SVQC
+spawnfunc(func_breakable);
+#endif
diff --git a/qcsrc/common/mapobjects/func/button.qc b/qcsrc/common/mapobjects/func/button.qc
new file mode 100644 (file)
index 0000000..28e6481
--- /dev/null
@@ -0,0 +1,170 @@
+#include "button.qh"
+#ifdef SVQC
+// button and multiple button
+
+void button_wait(entity this);
+void button_return(entity this);
+
+void button_wait(entity this)
+{
+       this.state = STATE_TOP;
+       if(this.wait >= 0)
+       {
+               this.nextthink = this.ltime + this.wait;
+               setthink(this, button_return);
+       }
+       SUB_UseTargets(this, this.enemy, NULL);
+       this.frame = 1;                 // use alternate textures
+}
+
+void button_done(entity this)
+{
+       this.state = STATE_BOTTOM;
+}
+
+void button_return(entity this)
+{
+       this.state = STATE_DOWN;
+       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, button_done);
+       this.frame = 0;                 // use normal textures
+       if (this.health)
+               this.takedamage = DAMAGE_YES;   // can be shot again
+}
+
+
+void button_blocked(entity this, entity blocker)
+{
+       // do nothing, just don't come all the way back out
+}
+
+
+void button_fire(entity this)
+{
+       this.health = this.max_health;
+       this.takedamage = DAMAGE_NO;    // will be reset upon return
+
+       if (this.state == STATE_UP || this.state == STATE_TOP)
+               return;
+
+       if (this.noise != "")
+               _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+
+       this.state = STATE_UP;
+       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, button_wait);
+}
+
+void button_reset(entity this)
+{
+       this.health = this.max_health;
+       setorigin(this, this.pos1);
+       this.frame = 0;                 // use normal textures
+       this.state = STATE_BOTTOM;
+       this.velocity = '0 0 0';
+       setthink(this, func_null);
+       this.nextthink = 0;
+       if (this.health)
+               this.takedamage = DAMAGE_YES;   // can be shot again
+}
+
+void button_use(entity this, entity actor, entity trigger)
+{
+       if(this.active != ACTIVE_ACTIVE)
+               return;
+
+       this.enemy = actor;
+       button_fire(this);
+}
+
+void button_touch(entity this, entity toucher)
+{
+       if (!toucher)
+               return;
+       if (!toucher.iscreature)
+               return;
+       if(toucher.velocity * this.movedir < 0)
+               return;
+       this.enemy = toucher;
+       if (toucher.owner)
+               this.enemy = toucher.owner;
+       button_fire (this);
+}
+
+void button_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(this.spawnflags & NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
+       {
+               if (this.health <= damage)
+               {
+                       this.enemy = attacker;
+                       button_fire(this);
+               }
+       }
+       else
+       {
+               this.health = this.health - damage;
+               if (this.health <= 0)
+               {
+                       this.enemy = attacker;
+                       button_fire(this);
+               }
+       }
+}
+
+
+/*QUAKED spawnfunc_func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle"                determines the opening direction
+"target"       all entities with a matching targetname will be used
+"speed"                override the default 40 speed
+"wait"         override the default 1 second wait (-1 = never return)
+"lip"          override the default 4 pixel lip remaining at end of move
+"health"       if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
+"noise"                sound that is played when the button is activated
+*/
+spawnfunc(func_button)
+{
+       SetMovedir(this);
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+       this.effects |= EF_LOWPRECISION;
+
+       setblocked(this, button_blocked);
+       this.use = button_use;
+
+//     if (this.health == 0) // all buttons are now shootable
+//             this.health = 10;
+       if (this.health)
+       {
+               this.max_health = this.health;
+               this.event_damage = button_damage;
+               this.takedamage = DAMAGE_YES;
+       }
+       else
+               settouch(this, button_touch);
+
+       if (!this.speed)
+               this.speed = 40;
+       if (!this.wait)
+               this.wait = 1;
+       if (!this.lip)
+               this.lip = 4;
+
+    if(this.noise != "")
+        precache_sound(this.noise);
+
+       this.active = ACTIVE_ACTIVE;
+
+       this.pos1 = this.origin;
+       this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
+    this.flags |= FL_NOTARGET;
+
+    this.reset = button_reset;
+
+       button_reset(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/button.qh b/qcsrc/common/mapobjects/func/button.qh
new file mode 100644 (file)
index 0000000..86a0fc9
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int BUTTON_DONTACCUMULATEDMG = BIT(7);
diff --git a/qcsrc/common/mapobjects/func/conveyor.qc b/qcsrc/common/mapobjects/func/conveyor.qc
new file mode 100644 (file)
index 0000000..9ad326c
--- /dev/null
@@ -0,0 +1,178 @@
+#include "conveyor.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_CONVEYOR)
+
+void conveyor_think(entity this)
+{
+#ifdef CSQC
+       // TODO: check if this is what is causing the glitchiness when switching between them
+       float dt = time - this.move_time;
+       this.move_time = time;
+       if(dt <= 0) { return; }
+#endif
+
+       // set myself as current conveyor where possible
+       IL_EACH(g_conveyed, it.conveyor == this,
+       {
+               it.conveyor = NULL;
+               IL_REMOVE(g_conveyed, it);
+       });
+
+       if(this.active == ACTIVE_ACTIVE)
+       {
+               FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, it.conveyor.active == ACTIVE_NOT && isPushable(it),
+               {
+                       vector emin = it.absmin;
+                       vector emax = it.absmax;
+                       if(this.solid == SOLID_BSP)
+                       {
+                               emin -= '1 1 1';
+                               emax += '1 1 1';
+                       }
+                       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;
+                               }
+               });
+
+               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;
+
+                       setorigin(it, it.origin + this.movedir * PHYS_INPUT_FRAMETIME);
+                       move_out_of_solid(it);
+#ifdef SVQC
+                       UpdateCSQCProjectile(it);
+#endif
+                       /*
+                       // stupid conveyor code
+                       tracebox(it.origin, it.mins, it.maxs, it.origin + this.movedir * sys_frametime, MOVE_NORMAL, it);
+                       if(trace_fraction > 0)
+                               setorigin(it, trace_endpos);
+                       */
+               });
+       }
+
+#ifdef SVQC
+       this.nextthink = time;
+#endif
+}
+
+#ifdef SVQC
+
+bool conveyor_send(entity this, entity to, int sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
+       WriteByte(MSG_ENTITY, sendflags);
+
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               WriteByte(MSG_ENTITY, this.warpzone_isboxy);
+               WriteVector(MSG_ENTITY, this.origin);
+
+               WriteVector(MSG_ENTITY, this.mins);
+               WriteVector(MSG_ENTITY, this.maxs);
+
+               WriteVector(MSG_ENTITY, this.movedir);
+
+               WriteByte(MSG_ENTITY, this.speed);
+               WriteByte(MSG_ENTITY, this.active);
+
+               WriteString(MSG_ENTITY, this.targetname);
+               WriteString(MSG_ENTITY, this.target);
+       }
+
+       if(sendflags & SF_TRIGGER_UPDATE)
+               WriteByte(MSG_ENTITY, this.active);
+
+       return true;
+}
+
+void conveyor_init(entity this)
+{
+       if (!this.speed) this.speed = 200;
+       this.movedir *= this.speed;
+       setthink(this, conveyor_think);
+       this.nextthink = time;
+       this.setactive = generic_netlinked_setactive;
+       IFTARGETED
+       {
+               // backwards compatibility
+               this.use = generic_netlinked_legacy_use;
+       }
+       this.reset = generic_netlinked_reset;
+       this.reset(this);
+
+       FixSize(this);
+
+       Net_LinkEntity(this, 0, false, conveyor_send);
+
+       this.SendFlags |= SF_TRIGGER_INIT;
+}
+
+spawnfunc(trigger_conveyor)
+{
+       SetMovedir(this);
+       EXACTTRIGGER_INIT;
+       conveyor_init(this);
+}
+
+spawnfunc(func_conveyor)
+{
+       SetMovedir(this);
+       InitMovingBrushTrigger(this);
+       set_movetype(this, MOVETYPE_NONE);
+       conveyor_init(this);
+}
+
+#elif defined(CSQC)
+
+void conveyor_draw(entity this) { conveyor_think(this); }
+
+void conveyor_init(entity this, bool isnew)
+{
+       if(isnew)
+               IL_PUSH(g_drawables, this);
+       this.draw = conveyor_draw;
+       this.drawmask = MASK_NORMAL;
+
+       set_movetype(this, MOVETYPE_NONE);
+       this.model = "";
+       this.solid = SOLID_TRIGGER;
+       this.move_time = time;
+}
+
+NET_HANDLE(ENT_CLIENT_CONVEYOR, bool isnew)
+{
+       int sendflags = ReadByte();
+
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               this.warpzone_isboxy = ReadByte();
+               this.origin = ReadVector();
+               setorigin(this, this.origin);
+
+               this.mins = ReadVector();
+               this.maxs = ReadVector();
+               setsize(this, this.mins, this.maxs);
+
+               this.movedir = ReadVector();
+
+               this.speed = ReadByte();
+               this.active = ReadByte();
+
+               this.targetname = strzone(ReadString());
+               this.target = strzone(ReadString());
+
+               conveyor_init(this, isnew);
+       }
+
+       if(sendflags & SF_TRIGGER_UPDATE)
+               this.active = ReadByte();
+
+       return true;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/conveyor.qh b/qcsrc/common/mapobjects/func/conveyor.qh
new file mode 100644 (file)
index 0000000..22b674f
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+#include "../defs.qh"
+
+IntrusiveList g_conveyed;
+STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
diff --git a/qcsrc/common/mapobjects/func/door.qc b/qcsrc/common/mapobjects/func/door.qc
new file mode 100644 (file)
index 0000000..c19041a
--- /dev/null
@@ -0,0 +1,801 @@
+#include "door.qh"
+#include "door_rotating.qh"
+/*
+
+Doors are similar to buttons, but can spawn a fat trigger field around them
+to open without a touch, and they link together to form simultanious
+double/quad doors.
+
+Door.owner is the master door.  If there is only one door, it points to itself.
+If multiple doors, all will point to a single one.
+
+Door.enemy chains from the master door through all doors linked in the chain.
+
+*/
+
+
+/*
+=============================================================================
+
+THINK FUNCTIONS
+
+=============================================================================
+*/
+
+void door_go_down(entity this);
+void door_go_up(entity this, entity actor, entity trigger);
+
+void door_blocked(entity this, entity blocker)
+{
+       if((this.spawnflags & DOOR_CRUSH)
+#ifdef SVQC
+               && (blocker.takedamage != DAMAGE_NO)
+#elif defined(CSQC)
+               && !IS_DEAD(blocker)
+#endif
+       )
+       { // KIll Kill Kill!!
+#ifdef SVQC
+               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+       }
+       else
+       {
+#ifdef SVQC
+               if((this.dmg) && (blocker.takedamage == DAMAGE_YES))    // Shall we bite?
+                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+
+                // don't change direction for dead or dying stuff
+               if(IS_DEAD(blocker)
+#ifdef SVQC
+                       && (blocker.takedamage == DAMAGE_NO)
+#endif
+               )
+               {
+                       if (this.wait >= 0)
+                       {
+                               if (this.state == STATE_DOWN)
+                               {
+                                       if (this.classname == "door")
+                                               door_go_up(this, NULL, NULL);
+                                       else
+                                               door_rotating_go_up(this, blocker);
+                               }
+                               else
+                               {
+                                       if (this.classname == "door")
+                                               door_go_down(this);
+                                       else
+                                               door_rotating_go_down(this);
+                               }
+                       }
+               }
+#ifdef SVQC
+               else
+               {
+                       //gib dying stuff just to make sure
+                       if((this.dmg) && (blocker.takedamage != DAMAGE_NO))    // Shall we bite?
+                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+               }
+#endif
+       }
+}
+
+void door_hit_top(entity this)
+{
+       if (this.noise1 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_TOP;
+       if (this.spawnflags & DOOR_TOGGLE)
+               return;         // don't come down automatically
+       if (this.classname == "door")
+       {
+               setthink(this, door_go_down);
+       } else
+       {
+               setthink(this, door_rotating_go_down);
+       }
+       this.nextthink = this.ltime + this.wait;
+}
+
+void door_hit_bottom(entity this)
+{
+       if (this.noise1 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_BOTTOM;
+}
+
+void door_go_down(entity this)
+{
+       if (this.noise2 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       if (this.max_health)
+       {
+               this.takedamage = DAMAGE_YES;
+               this.health = this.max_health;
+       }
+
+       this.state = STATE_DOWN;
+       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_hit_bottom);
+}
+
+void door_go_up(entity this, entity actor, entity trigger)
+{
+       if (this.state == STATE_UP)
+               return;         // already going up
+
+       if (this.state == STATE_TOP)
+       {       // reset top wait time
+               this.nextthink = this.ltime + this.wait;
+               return;
+       }
+
+       if (this.noise2 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_UP;
+       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_hit_top);
+
+       string oldmessage;
+       oldmessage = this.message;
+       this.message = "";
+       SUB_UseTargets(this, actor, trigger);
+       this.message = oldmessage;
+}
+
+
+/*
+=============================================================================
+
+ACTIVATION FUNCTIONS
+
+=============================================================================
+*/
+
+bool door_check_keys(entity door, entity player)
+{
+       if(door.owner)
+               door = door.owner;
+
+       // no key needed
+       if(!door.itemkeys)
+               return true;
+
+       // this door require a key
+       // only a player can have a key
+       if(!IS_PLAYER(player))
+               return false;
+
+       entity store = player;
+#ifdef SVQC
+       store = PS(player);
+#endif
+       int valid = (door.itemkeys & store.itemkeys);
+       door.itemkeys &= ~valid; // only some of the needed keys were given
+
+       if(!door.itemkeys)
+       {
+#ifdef SVQC
+               play2(player, door.noise);
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_UNLOCKED);
+#endif
+               return true;
+       }
+
+       if(!valid)
+       {
+#ifdef SVQC
+               if(player.key_door_messagetime <= time)
+               {
+                       play2(player, door.noise3);
+                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
+                       player.key_door_messagetime = time + 2;
+               }
+#endif
+               return false;
+       }
+
+       // door needs keys the player doesn't have
+#ifdef SVQC
+       if(player.key_door_messagetime <= time)
+       {
+               play2(player, door.noise3);
+               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
+               player.key_door_messagetime = time + 2;
+       }
+#endif
+
+       return false;
+}
+
+void door_fire(entity this, entity actor, entity trigger)
+{
+       if (this.owner != this)
+               objerror (this, "door_fire: this.owner != this");
+
+       if (this.spawnflags & DOOR_TOGGLE)
+       {
+               if (this.state == STATE_UP || this.state == STATE_TOP)
+               {
+                       entity e = this;
+                       do {
+                               if (e.classname == "door") {
+                                       door_go_down(e);
+                               } else {
+                                       door_rotating_go_down(e);
+                               }
+                               e = e.enemy;
+                       } while ((e != this) && (e != NULL));
+                       return;
+               }
+       }
+
+// trigger all paired doors
+       entity e = this;
+       do {
+               if (e.classname == "door") {
+                       door_go_up(e, actor, trigger);
+               } else {
+                       // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
+                       if ((e.spawnflags & DOOR_ROTATING_BIDIR) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
+                               e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
+                               e.pos2 = '0 0 0' - e.pos2;
+                       }
+                       // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
+                       if (!((e.spawnflags & DOOR_ROTATING_BIDIR) &&  (e.spawnflags & DOOR_ROTATING_BIDIR_IN_DOWN) && e.state == STATE_DOWN
+                               && (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
+                       {
+                               door_rotating_go_up(e, trigger);
+                       }
+               }
+               e = e.enemy;
+       } while ((e != this) && (e != NULL));
+}
+
+void door_use(entity this, entity actor, entity trigger)
+{
+       //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
+
+       if (this.owner)
+               door_fire(this.owner, actor, trigger);
+}
+
+void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(this.spawnflags & NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       this.health = this.health - damage;
+
+       if (this.itemkeys)
+       {
+               // don't allow opening doors through damage if keys are required
+               return;
+       }
+
+       if (this.health <= 0)
+       {
+               this.owner.health = this.owner.max_health;
+               this.owner.takedamage = DAMAGE_NO;      // wil be reset upon return
+               door_use(this.owner, NULL, NULL);
+       }
+}
+
+.float door_finished;
+
+/*
+================
+door_touch
+
+Prints messages
+================
+*/
+
+void door_touch(entity this, entity toucher)
+{
+       if (!IS_PLAYER(toucher))
+               return;
+       if (this.owner.door_finished > time)
+               return;
+
+       this.owner.door_finished = time + 2;
+
+#ifdef SVQC
+       if (!(this.owner.dmg) && (this.owner.message != ""))
+       {
+               if (IS_CLIENT(toucher))
+                       centerprint(toucher, this.owner.message);
+               play2(toucher, this.owner.noise);
+       }
+#endif
+}
+
+void door_generic_plat_blocked(entity this, entity blocker)
+{
+       if((this.spawnflags & DOOR_CRUSH) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
+#ifdef SVQC
+               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+       }
+       else
+       {
+
+#ifdef SVQC
+               if((this.dmg) && (blocker.takedamage == DAMAGE_YES))    // Shall we bite?
+                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+
+                //Dont chamge direction for dead or dying stuff
+               if(IS_DEAD(blocker) && (blocker.takedamage == DAMAGE_NO))
+               {
+                       if (this.wait >= 0)
+                       {
+                               if (this.state == STATE_DOWN)
+                                       door_rotating_go_up (this, blocker);
+                               else
+                                       door_rotating_go_down (this);
+                       }
+               }
+#ifdef SVQC
+               else
+               {
+                       //gib dying stuff just to make sure
+                       if((this.dmg) && (blocker.takedamage != DAMAGE_NO))    // Shall we bite?
+                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+               }
+#endif
+       }
+}
+
+/*
+=========================================
+door trigger
+
+Spawned if a door lacks a real activator
+=========================================
+*/
+
+void door_trigger_touch(entity this, entity toucher)
+{
+       if (toucher.health < 1)
+#ifdef SVQC
+               if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
+#elif defined(CSQC)
+               if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
+#endif
+                       return;
+
+       if (time < this.door_finished)
+               return;
+
+       // check if door is locked
+       if (!door_check_keys(this, toucher))
+               return;
+
+       this.door_finished = time + 1;
+
+       door_use(this.owner, toucher, NULL);
+}
+
+void door_spawnfield(entity this, vector fmins, vector fmaxs)
+{
+       entity  trigger;
+       vector  t1 = fmins, t2 = fmaxs;
+
+       trigger = new(doortriggerfield);
+       set_movetype(trigger, MOVETYPE_NONE);
+       trigger.solid = SOLID_TRIGGER;
+       trigger.owner = this;
+#ifdef SVQC
+       settouch(trigger, door_trigger_touch);
+#endif
+
+       setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
+}
+
+
+/*
+=============
+LinkDoors
+
+
+=============
+*/
+
+entity LinkDoors_nextent(entity cur, entity near, entity pass)
+{
+       while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & DOOR_DONT_LINK) || cur.enemy))
+       {
+       }
+       return cur;
+}
+
+bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
+{
+       float DELTA = 4;
+       if((e1.absmin_x > e2.absmax_x + DELTA)
+       || (e1.absmin_y > e2.absmax_y + DELTA)
+       || (e1.absmin_z > e2.absmax_z + DELTA)
+       || (e2.absmin_x > e1.absmax_x + DELTA)
+       || (e2.absmin_y > e1.absmax_y + DELTA)
+       || (e2.absmin_z > e1.absmax_z + DELTA)
+       ) { return false; }
+       return true;
+}
+
+#ifdef SVQC
+void door_link();
+#endif
+void LinkDoors(entity this)
+{
+       entity  t;
+       vector  cmins, cmaxs;
+
+#ifdef SVQC
+       door_link();
+#endif
+
+       if (this.enemy)
+               return;         // already linked by another door
+       if (this.spawnflags & DOOR_DONT_LINK)
+       {
+               this.owner = this.enemy = this;
+
+               if (this.health)
+                       return;
+               IFTARGETED
+                       return;
+               if (this.items)
+                       return;
+
+               door_spawnfield(this, this.absmin, this.absmax);
+
+               return;         // don't want to link this door
+       }
+
+       FindConnectedComponent(this, enemy, LinkDoors_nextent, LinkDoors_isconnected, this);
+
+       // set owner, and make a loop of the chain
+       LOG_TRACE("LinkDoors: linking doors:");
+       for(t = this; ; t = t.enemy)
+       {
+               LOG_TRACE(" ", etos(t));
+               t.owner = this;
+               if(t.enemy == NULL)
+               {
+                       t.enemy = this;
+                       break;
+               }
+       }
+       LOG_TRACE("");
+
+       // collect health, targetname, message, size
+       cmins = this.absmin;
+       cmaxs = this.absmax;
+       for(t = this; ; t = t.enemy)
+       {
+               if(t.health && !this.health)
+                       this.health = t.health;
+               if((t.targetname != "") && (this.targetname == ""))
+                       this.targetname = t.targetname;
+               if((t.message != "") && (this.message == ""))
+                       this.message = t.message;
+               if (t.absmin_x < cmins_x)
+                       cmins_x = t.absmin_x;
+               if (t.absmin_y < cmins_y)
+                       cmins_y = t.absmin_y;
+               if (t.absmin_z < cmins_z)
+                       cmins_z = t.absmin_z;
+               if (t.absmax_x > cmaxs_x)
+                       cmaxs_x = t.absmax_x;
+               if (t.absmax_y > cmaxs_y)
+                       cmaxs_y = t.absmax_y;
+               if (t.absmax_z > cmaxs_z)
+                       cmaxs_z = t.absmax_z;
+               if(t.enemy == this)
+                       break;
+       }
+
+       // distribute health, targetname, message
+       for(t = this; t; t = t.enemy)
+       {
+               t.health = this.health;
+               t.targetname = this.targetname;
+               t.message = this.message;
+               if(t.enemy == this)
+                       break;
+       }
+
+       // shootable, or triggered doors just needed the owner/enemy links,
+       // they don't spawn a field
+
+       if (this.health)
+               return;
+       IFTARGETED
+               return;
+       if (this.items)
+               return;
+
+       door_spawnfield(this, cmins, cmaxs);
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
+
+#ifdef SVQC
+/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+
+GOLD_KEY causes the door to open only if the activator holds a gold key.
+
+SILVER_KEY causes the door to open only if the activator holds a silver key.
+
+"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"                determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"       if set, door must be shot open
+"speed"                movement speed (100 default)
+"wait"         wait before returning (3 default, -1 = never return)
+"lip"          lip remaining at end of move (8 default)
+"dmg"          damage to inflict when blocked (2 default)
+"sounds"
+0)     no sound
+1)     stone
+2)     base
+3)     stone chain
+4)     screechy metal
+FIXME: only one sound set available at the time being
+
+*/
+
+float door_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               WriteString(MSG_ENTITY, this.classname);
+               WriteByte(MSG_ENTITY, this.spawnflags);
+
+               WriteString(MSG_ENTITY, this.model);
+
+               trigger_common_write(this, true);
+
+               WriteVector(MSG_ENTITY, this.pos1);
+               WriteVector(MSG_ENTITY, this.pos2);
+
+               WriteVector(MSG_ENTITY, this.size);
+
+               WriteShort(MSG_ENTITY, this.wait);
+               WriteShort(MSG_ENTITY, this.speed);
+               WriteByte(MSG_ENTITY, this.lip);
+               WriteByte(MSG_ENTITY, this.state);
+               WriteCoord(MSG_ENTITY, this.ltime);
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               // client makes use of this, we do not
+       }
+
+       if(sf & SF_TRIGGER_UPDATE)
+       {
+               WriteVector(MSG_ENTITY, this.origin);
+
+               WriteVector(MSG_ENTITY, this.pos1);
+               WriteVector(MSG_ENTITY, this.pos2);
+       }
+
+       return true;
+}
+
+void door_link()
+{
+       // set size now, as everything is loaded
+       //FixSize(this);
+       //Net_LinkEntity(this, false, 0, door_send);
+}
+#endif
+
+void door_init_startopen(entity this)
+{
+       setorigin(this, this.pos2);
+       this.pos2 = this.pos1;
+       this.pos1 = this.origin;
+
+#ifdef SVQC
+       this.SendFlags |= SF_TRIGGER_UPDATE;
+#endif
+}
+
+void door_reset(entity this)
+{
+       setorigin(this, this.pos1);
+       this.velocity = '0 0 0';
+       this.state = STATE_BOTTOM;
+       setthink(this, func_null);
+       this.nextthink = 0;
+
+#ifdef SVQC
+       this.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+#ifdef SVQC
+
+// common code for func_door and func_door_rotating spawnfuncs
+void door_init_shared(entity this)
+{
+       this.max_health = this.health;
+
+       // unlock sound
+       if(this.noise == "")
+       {
+               this.noise = "misc/talk.wav";
+       }
+       // door still locked sound
+       if(this.noise3 == "")
+       {
+               this.noise3 = "misc/talk.wav";
+       }
+       precache_sound(this.noise);
+       precache_sound(this.noise3);
+
+       if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message == ""))
+       {
+               this.message = "was squished";
+       }
+       if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message2 == ""))
+       {
+               this.message2 = "was squished by";
+       }
+
+       // TODO: other soundpacks
+       if (this.sounds > 0)
+       {
+               this.noise2 = "plats/medplat1.wav";
+               this.noise1 = "plats/medplat2.wav";
+       }
+
+       // sound when door stops moving
+       if(this.noise1 && this.noise1 != "")
+       {
+               precache_sound(this.noise1);
+       }
+       // sound when door is moving
+       if(this.noise2 && this.noise2 != "")
+       {
+               precache_sound(this.noise2);
+       }
+
+       if (!this.wait)
+       {
+               this.wait = 3;
+       }
+       if (!this.lip)
+       {
+               this.lip = 8;
+       }
+
+       this.state = STATE_BOTTOM;
+
+       if (this.health)
+       {
+               //this.canteamdamage = true; // TODO
+               this.takedamage = DAMAGE_YES;
+               this.event_damage = door_damage;
+       }
+
+       if (this.items)
+       {
+               this.wait = -1;
+       }
+}
+
+// spawnflags require key (for now only func_door)
+spawnfunc(func_door)
+{
+       // Quake 1 keys compatibility
+       if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
+               this.itemkeys |= ITEM_KEY_BIT(0);
+       if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
+               this.itemkeys |= ITEM_KEY_BIT(1);
+
+       SetMovedir(this);
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+       this.effects |= EF_LOWPRECISION;
+       this.classname = "door";
+
+       setblocked(this, door_blocked);
+       this.use = door_use;
+
+       this.pos1 = this.origin;
+       this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
+
+       if(this.spawnflags & DOOR_NONSOLID)
+               this.solid = SOLID_NOT;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+       if (this.spawnflags & DOOR_START_OPEN)
+               InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
+
+       door_init_shared(this);
+
+       if (!this.speed)
+       {
+               this.speed = 100;
+       }
+
+       settouch(this, door_touch);
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+       InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
+
+       this.reset = door_reset;
+}
+
+#elif defined(CSQC)
+
+NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
+{
+       int sf = ReadByte();
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               this.classname = strzone(ReadString());
+               this.spawnflags = ReadByte();
+
+               this.mdl = strzone(ReadString());
+               _setmodel(this, this.mdl);
+
+               trigger_common_read(this, true);
+
+               this.pos1 = ReadVector();
+               this.pos2 = ReadVector();
+
+               this.size = ReadVector();
+
+               this.wait = ReadShort();
+               this.speed = ReadShort();
+               this.lip = ReadByte();
+               this.state = ReadByte();
+               this.ltime = ReadCoord();
+
+               this.solid = SOLID_BSP;
+               set_movetype(this, MOVETYPE_PUSH);
+               this.use = door_use;
+
+               LinkDoors(this);
+
+               if(this.spawnflags & DOOR_START_OPEN)
+                       door_init_startopen(this);
+
+               this.move_time = time;
+               set_movetype(this, MOVETYPE_PUSH);
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               door_reset(this);
+       }
+
+       if(sf & SF_TRIGGER_UPDATE)
+       {
+               this.origin = ReadVector();
+               setorigin(this, this.origin);
+
+               this.pos1 = ReadVector();
+               this.pos2 = ReadVector();
+       }
+       return true;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/func/door.qh b/qcsrc/common/mapobjects/func/door.qh
new file mode 100644 (file)
index 0000000..181de8b
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+
+const int DOOR_START_OPEN = BIT(0);
+const int DOOR_DONT_LINK = BIT(2);
+const int SPAWNFLAGS_GOLD_KEY = BIT(3); // Quake 1 compat, can only be used with func_door!
+const int SPAWNFLAGS_SILVER_KEY = BIT(4); // Quake 1 compat, can only be used with func_door!
+const int DOOR_TOGGLE = BIT(5);
+
+const int DOOR_NONSOLID = BIT(10);
+const int DOOR_CRUSH = BIT(11); // can't use CRUSH cause that is the same as DOOR_DONT_LINK
+
+
+#ifdef CSQC
+// stuff for preload
+
+.float door_finished;
+#endif
diff --git a/qcsrc/common/mapobjects/func/door_rotating.qc b/qcsrc/common/mapobjects/func/door_rotating.qc
new file mode 100644 (file)
index 0000000..41fd05e
--- /dev/null
@@ -0,0 +1,159 @@
+#include "door_rotating.qh"
+/*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.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
+The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction
+must have set trigger_reverse to 1.
+BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
+
+"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle"                determines the destination angle for opening. negative values reverse the direction.
+"targetname"    if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health"       if set, door must be shot open
+"speed"                movement speed (100 default)
+"wait"         wait before returning (3 default, -1 = never return)
+"dmg"          damage to inflict when blocked (2 default)
+"sounds"
+0)     no sound
+1)     stone
+2)     base
+3)     stone chain
+4)     screechy metal
+FIXME: only one sound set available at the time being
+*/
+
+#ifdef GAMEQC
+void door_rotating_hit_top(entity this)
+{
+       if (this.noise1 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_TOP;
+       if (this.spawnflags & DOOR_TOGGLE)
+               return;         // don't come down automatically
+       setthink(this, door_rotating_go_down);
+       this.nextthink = this.ltime + this.wait;
+}
+
+void door_rotating_hit_bottom(entity this)
+{
+       if (this.noise1 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       if (this.lip==666) // this.lip is used to remember reverse opening direction for door_rotating
+       {
+               this.pos2 = '0 0 0' - this.pos2;
+               this.lip = 0;
+       }
+       this.state = STATE_BOTTOM;
+}
+
+void door_rotating_go_down(entity this)
+{
+       if (this.noise2 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       if (this.max_health)
+       {
+               this.takedamage = DAMAGE_YES;
+               this.health = this.max_health;
+       }
+
+       this.state = STATE_DOWN;
+       SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
+}
+
+void door_rotating_go_up(entity this, entity oth)
+{
+       if (this.state == STATE_UP)
+               return;         // already going up
+
+       if (this.state == STATE_TOP)
+       {       // reset top wait time
+               this.nextthink = this.ltime + this.wait;
+               return;
+       }
+       if (this.noise2 != "")
+               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_UP;
+       SUB_CalcAngleMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_rotating_hit_top);
+
+       string oldmessage;
+       oldmessage = this.message;
+       this.message = "";
+       SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
+       this.message = oldmessage;
+}
+#endif
+
+#ifdef SVQC
+void door_rotating_reset(entity this)
+{
+       this.angles = this.pos1;
+       this.avelocity = '0 0 0';
+       this.state = STATE_BOTTOM;
+       setthink(this, func_null);
+       this.nextthink = 0;
+}
+
+void door_rotating_init_startopen(entity this)
+{
+       this.angles = this.movedir;
+       this.pos2 = '0 0 0';
+       this.pos1 = this.movedir;
+}
+
+spawnfunc(func_door_rotating)
+{
+       //if (!this.deathtype) // map makers can override this
+       //      this.deathtype = " got in the way";
+
+       // I abuse "movedir" for denoting the axis for now
+       if (this.spawnflags & DOOR_ROTATING_XAXIS)
+               this.movedir = '0 0 1';
+       else if (this.spawnflags & DOOR_ROTATING_YAXIS)
+               this.movedir = '1 0 0';
+       else // Z
+               this.movedir = '0 1 0';
+
+       if (this.angles_y==0) this.angles_y = 90;
+
+       this.movedir = this.movedir * this.angles_y;
+       this.angles = '0 0 0';
+
+       this.avelocity = this.movedir;
+       if (!InitMovingBrushTrigger(this))
+               return;
+       this.velocity = '0 0 0';
+       //this.effects |= EF_LOWPRECISION;
+       this.classname = "door_rotating";
+
+       setblocked(this, door_blocked);
+       this.use = door_use;
+
+       this.pos1 = '0 0 0';
+       this.pos2 = this.movedir;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+       if (this.spawnflags & DOOR_START_OPEN)
+               InitializeEntity(this, door_rotating_init_startopen, INITPRIO_SETLOCATION);
+
+       door_init_shared(this);
+       if (!this.speed)
+       {
+               this.speed = 50;
+       }
+       this.lip = 0; // this.lip is used to remember reverse opening direction for door_rotating
+
+       settouch(this, door_touch);
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+       InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
+
+       this.reset = door_rotating_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/door_rotating.qh b/qcsrc/common/mapobjects/func/door_rotating.qh
new file mode 100644 (file)
index 0000000..5ff5728
--- /dev/null
@@ -0,0 +1,14 @@
+#pragma once
+
+
+const int DOOR_ROTATING_BIDIR = BIT(1);
+const int DOOR_ROTATING_BIDIR_IN_DOWN = BIT(3);
+
+const int DOOR_ROTATING_XAXIS = BIT(6);
+const int DOOR_ROTATING_YAXIS = BIT(7);
+
+
+#ifdef GAMEQC
+void door_rotating_go_down(entity this);
+void door_rotating_go_up(entity this, entity oth);
+#endif
diff --git a/qcsrc/common/mapobjects/func/door_secret.qc b/qcsrc/common/mapobjects/func/door_secret.qc
new file mode 100644 (file)
index 0000000..78e0dd6
--- /dev/null
@@ -0,0 +1,266 @@
+#include "door_secret.qh"
+#ifdef SVQC
+void fd_secret_move1(entity this);
+void fd_secret_move2(entity this);
+void fd_secret_move3(entity this);
+void fd_secret_move4(entity this);
+void fd_secret_move5(entity this);
+void fd_secret_move6(entity this);
+void fd_secret_done(entity this);
+
+void fd_secret_use(entity this, entity actor, entity trigger)
+{
+       float temp;
+       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...
+       if (this.origin != this.oldorigin)
+               return;
+
+       message_save = this.message;
+       this.message = ""; // no more message
+       SUB_UseTargets(this, actor, trigger);                           // fire all targets / killtargets
+       this.message = message_save;
+
+       this.velocity = '0 0 0';
+
+       // Make a sound, wait a little...
+
+       if (this.noise1 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.nextthink = this.ltime + 0.1;
+
+       temp = 1 - (this.spawnflags & DOOR_SECRET_1ST_LEFT);    // 1 or -1
+       makevectors(this.mangle);
+
+       if (!this.t_width)
+       {
+               if (this.spawnflags & DOOR_SECRET_1ST_DOWN)
+                       this.t_width = fabs(v_up * this.size);
+               else
+                       this.t_width = fabs(v_right * this.size);
+       }
+
+       if (!this.t_length)
+               this.t_length = fabs(v_forward * this.size);
+
+       if (this.spawnflags & DOOR_SECRET_1ST_DOWN)
+               this.dest1 = this.origin - v_up * this.t_width;
+       else
+               this.dest1 = this.origin + v_right * (this.t_width * temp);
+
+       this.dest2 = this.dest1 + v_forward * this.t_length;
+       SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move1);
+       if (this.noise2 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       fd_secret_use(this, NULL, NULL);
+}
+
+// Wait after first movement...
+void fd_secret_move1(entity this)
+{
+       this.nextthink = this.ltime + 1.0;
+       setthink(this, fd_secret_move2);
+       if (this.noise3 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+// Start moving sideways w/sound...
+void fd_secret_move2(entity this)
+{
+       if (this.noise2 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(this, this.dest2, TSPEED_LINEAR, this.speed, fd_secret_move3);
+}
+
+// Wait here until time to go back...
+void fd_secret_move3(entity this)
+{
+       if (this.noise3 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+       if (!(this.spawnflags & DOOR_SECRET_OPEN_ONCE) && this.wait >= 0)
+       {
+               this.nextthink = this.ltime + this.wait;
+               setthink(this, fd_secret_move4);
+       }
+}
+
+// Move backward...
+void fd_secret_move4(entity this)
+{
+       if (this.noise2 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move5);
+}
+
+// Wait 1 second...
+void fd_secret_move5(entity this)
+{
+       this.nextthink = this.ltime + 1.0;
+       setthink(this, fd_secret_move6);
+       if (this.noise3 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_move6(entity this)
+{
+       if (this.noise2 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+       SUB_CalcMove(this, this.oldorigin, TSPEED_LINEAR, this.speed, fd_secret_done);
+}
+
+void fd_secret_done(entity this)
+{
+       if (this.spawnflags&DOOR_SECRET_YES_SHOOT)
+       {
+               this.health = 10000;
+               this.takedamage = DAMAGE_YES;
+               //this.th_pain = fd_secret_use;
+       }
+       if (this.noise3 != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+.float door_finished;
+
+void secret_blocked(entity this, entity blocker)
+{
+       if (time < this.door_finished)
+               return;
+       this.door_finished = time + 0.5;
+       //T_Damage (other, this, this, this.dmg, this.dmg, this.deathtype, DT_IMPACT, (this.absmin + this.absmax) * 0.5, '0 0 0', Obituary_Generic);
+}
+
+/*
+==============
+secret_touch
+
+Prints messages
+================
+*/
+void secret_touch(entity this, entity toucher)
+{
+       if (!toucher.iscreature)
+               return;
+       if (this.door_finished > time)
+               return;
+
+       this.door_finished = time + 2;
+
+       if (this.message)
+       {
+               if (IS_CLIENT(toucher))
+                       centerprint(toucher, this.message);
+               play2(toucher, this.noise);
+       }
+}
+
+void secret_reset(entity this)
+{
+       if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
+       {
+               this.health = 10000;
+               this.takedamage = DAMAGE_YES;
+       }
+       setorigin(this, this.oldorigin);
+       setthink(this, func_null);
+       this.nextthink = 0;
+}
+
+/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
+Basic secret door. Slides back, then to the side. Angle determines direction.
+wait  = # of seconds before coming back
+1st_left = 1st move is left of arrow
+1st_down = 1st move is down from arrow
+always_shoot = even if targeted, keep shootable
+t_width = override WIDTH to move back (or height if going down)
+t_length = override LENGTH to move sideways
+"dmg"          damage to inflict when blocked (2 default)
+
+If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
+"sounds"
+1) medieval
+2) metal
+3) base
+*/
+
+spawnfunc(func_door_secret)
+{
+       /*if (!this.deathtype) // map makers can override this
+               this.deathtype = " got in the way";*/
+
+       if (!this.dmg)
+       {
+               this.dmg = 2;
+       }
+
+       // Magic formula...
+       this.mangle = this.angles;
+       this.angles = '0 0 0';
+       this.classname = "door";
+       if (!InitMovingBrushTrigger(this)) return;
+       this.effects |= EF_LOWPRECISION;
+
+       // TODO: other soundpacks
+       if (this.sounds > 0)
+       {
+               this.noise1 = "plats/medplat1.wav";
+               this.noise2 = "plats/medplat1.wav";
+               this.noise3 = "plats/medplat2.wav";
+       }
+
+       // sound on touch
+       if (this.noise == "")
+       {
+               this.noise = "misc/talk.wav";
+       }
+       precache_sound(this.noise);
+       // sound while moving backwards
+       if (this.noise1 && this.noise1 != "")
+       {
+               precache_sound(this.noise1);
+       }
+       // sound while moving sideways
+       if (this.noise2 && this.noise2 != "")
+       {
+               precache_sound(this.noise2);
+       }
+       // sound when door stops moving
+       if (this.noise3 && this.noise3 != "")
+       {
+               precache_sound(this.noise3);
+       }
+
+       settouch(this, secret_touch);
+       setblocked(this, secret_blocked);
+       this.speed = 50;
+       this.use = fd_secret_use;
+       IFTARGETED
+       {
+       }
+       else
+               this.spawnflags |= DOOR_SECRET_YES_SHOOT;
+
+       if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
+       {
+               //this.canteamdamage = true; // TODO
+               this.health = 10000;
+               this.takedamage = DAMAGE_YES;
+               this.event_damage = fd_secret_damage;
+       }
+       this.oldorigin = this.origin;
+       if (!this.wait) this.wait = 5; // seconds before closing
+
+       this.reset = secret_reset;
+       this.reset(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/door_secret.qh b/qcsrc/common/mapobjects/func/door_secret.qh
new file mode 100644 (file)
index 0000000..ee575bc
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once
+
+
+const int DOOR_SECRET_OPEN_ONCE = BIT(0); // stays open - LEGACY, set wait to -1 instead
+const int DOOR_SECRET_1ST_LEFT = BIT(1); // 1st move is left of arrow
+const int DOOR_SECRET_1ST_DOWN = BIT(2); // 1st move is down from arrow
+const int DOOR_SECRET_NO_SHOOT = BIT(3); // only opened by trigger
+const int DOOR_SECRET_YES_SHOOT = BIT(4); // shootable even if targeted
diff --git a/qcsrc/common/mapobjects/func/fourier.qc b/qcsrc/common/mapobjects/func/fourier.qc
new file mode 100644 (file)
index 0000000..28e0f0f
--- /dev/null
@@ -0,0 +1,89 @@
+#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.
+netname: list of <frequencymultiplier> <phase> <x> <y> <z> quadruples, separated by spaces; note that phase 0 represents a sine wave, and phase 0.25 a cosine wave (by default, it uses 1 0 0 0 1, to match func_bobbing's defaults
+speed: how long one cycle of frequency multiplier 1 in seconds (default 4)
+height: amplitude modifier (default 32)
+phase: cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
+noise: path/name of looping .wav file to play.
+dmg: Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime: See above.
+*/
+
+void func_fourier_controller_think(entity this)
+{
+       vector v;
+       float n, i, t;
+
+       this.nextthink = time + 0.1;
+       if(this.owner.active != ACTIVE_ACTIVE)
+       {
+               this.owner.velocity = '0 0 0';
+               return;
+       }
+
+
+       n = floor((tokenize_console(this.owner.netname)) / 5);
+       t = this.nextthink * this.owner.cnt + this.owner.phase * 360;
+
+       v = this.owner.destvec;
+
+       for(i = 0; i < n; ++i)
+       {
+               makevectors((t * stof(argv(i*5)) + stof(argv(i*5+1)) * 360) * '0 1 0');
+               v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * this.owner.height * v_forward_y;
+       }
+
+       if(this.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
+               // * 10 so it will arrive in 0.1 sec
+               this.owner.velocity = (v - this.owner.origin) * 10;
+}
+
+spawnfunc(func_fourier)
+{
+       entity controller;
+       if (this.noise != "")
+       {
+               precache_sound(this.noise);
+               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       if (!this.speed)
+               this.speed = 4;
+       if (!this.height)
+               this.height = 32;
+       this.destvec = this.origin;
+       this.cnt = 360 / this.speed;
+
+       setblocked(this, generic_plat_blocked);
+       if(this.dmg && (this.message == ""))
+               this.message = " was squished";
+    if(this.dmg && (this.message2 == ""))
+               this.message2 = "was squished by";
+       if(this.dmg && (!this.dmgtime))
+               this.dmgtime = 0.25;
+       this.dmgtime2 = time;
+
+       if(this.netname == "")
+               this.netname = "1 0 0 0 1";
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+
+       this.active = ACTIVE_ACTIVE;
+
+       // wait for targets to spawn
+       controller = new(func_fourier_controller);
+       controller.owner = this;
+       controller.nextthink = time + 1;
+       setthink(controller, func_fourier_controller_think);
+       this.nextthink = this.ltime + 999999999;
+       setthink(this, SUB_NullThink); // for PushMove
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       this.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/fourier.qh b/qcsrc/common/mapobjects/func/fourier.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/func/ladder.qc b/qcsrc/common/mapobjects/func/ladder.qc
new file mode 100644 (file)
index 0000000..020ecca
--- /dev/null
@@ -0,0 +1,148 @@
+#include "ladder.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
+
+void func_ladder_touch(entity this, entity toucher)
+{
+#ifdef SVQC
+       if (!toucher.iscreature)
+               return;
+       if(IS_VEHICLE(toucher))
+               return;
+#elif defined(CSQC)
+       if(!toucher.isplayermodel)
+               return;
+#endif
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       toucher.ladder_time = time + 0.1;
+       toucher.ladder_entity = this;
+}
+
+#ifdef SVQC
+bool func_ladder_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
+
+       WriteString(MSG_ENTITY, this.classname);
+       WriteByte(MSG_ENTITY, this.skin);
+       WriteCoord(MSG_ENTITY, this.speed);
+
+       trigger_common_write(this, false);
+
+       return true;
+}
+
+void func_ladder_link(entity this)
+{
+       trigger_link(this, func_ladder_send);
+       //this.model = "null";
+}
+
+void func_ladder_init(entity this)
+{
+       settouch(this, func_ladder_touch);
+       trigger_init(this);
+       func_ladder_link(this);
+
+       if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
+               return;
+
+       entity tracetest_ent = spawn();
+       setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
+       tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+
+       vector top_min = (this.absmin + this.absmax) / 2;
+       top_min.z = this.absmax.z;
+       vector top_max = top_min;
+       top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
+       tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
+       if(trace_startsolid)
+       {
+               tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
+               if(trace_startsolid)
+               {
+                       tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
+                       if(trace_startsolid)
+                       {
+                               if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
+                                       && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
+                               {
+                                       // move top on one side
+                                       top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
+                               }
+                               else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
+                                       && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
+                               {
+                                       // move top on one side
+                                       top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
+                               }
+                               tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
+                               if(trace_startsolid)
+                               {
+                                       if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
+                                               && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
+                                       {
+                                               // alternatively on the other side
+                                               top_max.y = top_min.y = this.absmax.y - (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
+                                       }
+                                       else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
+                                               && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
+                                       {
+                                               // alternatively on the other side
+                                               top_max.x = top_min.x = this.absmax.x - (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
+                                       }
+                                       tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
+                               }
+                       }
+               }
+       }
+       if(trace_startsolid || trace_endpos.z < this.absmax.z)
+       {
+               delete(tracetest_ent);
+               return;
+       }
+
+       this.bot_pickup = true; // allow bots to make use of this ladder
+       float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
+       top_min = trace_endpos;
+       waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
+}
+
+spawnfunc(func_ladder)
+{
+       IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
+
+       func_ladder_init(this);
+}
+
+spawnfunc(func_water)
+{
+       func_ladder_init(this);
+}
+
+#elif defined(CSQC)
+.float speed;
+
+void func_ladder_remove(entity this)
+{
+       strfree(this.classname);
+}
+
+NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
+{
+       this.classname = strzone(ReadString());
+       this.skin = ReadByte();
+       this.speed = ReadCoord();
+
+       trigger_common_read(this, false);
+
+       this.solid = SOLID_TRIGGER;
+       settouch(this, func_ladder_touch);
+       this.drawmask = MASK_NORMAL;
+       this.move_time = time;
+       this.entremove = func_ladder_remove;
+
+       return true;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/ladder.qh b/qcsrc/common/mapobjects/func/ladder.qh
new file mode 100644 (file)
index 0000000..26cbbda
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+.float ladder_time;
+.entity ladder_entity;
diff --git a/qcsrc/common/mapobjects/func/pendulum.qc b/qcsrc/common/mapobjects/func/pendulum.qc
new file mode 100644 (file)
index 0000000..a59f7a9
--- /dev/null
@@ -0,0 +1,77 @@
+#include "pendulum.qh"
+#ifdef SVQC
+.float freq;
+void func_pendulum_controller_think(entity this)
+{
+       float v;
+       this.nextthink = time + 0.1;
+
+       if (!(this.owner.active == ACTIVE_ACTIVE))
+       {
+               this.owner.avelocity_x = 0;
+               return;
+       }
+
+       // calculate sinewave using makevectors
+       makevectors((this.nextthink * this.owner.freq + this.owner.phase) * '0 360 0');
+       v = this.owner.speed * v_forward_y + this.cnt;
+       if(this.owner.classname == "func_pendulum") // don't brake stuff if the func_bobbing was killtarget'ed
+       {
+               // * 10 so it will arrive in 0.1 sec
+               this.owner.avelocity_z = (remainder(v - this.owner.angles_z, 360)) * 10;
+       }
+}
+
+spawnfunc(func_pendulum)
+{
+       entity controller;
+       if (this.noise != "")
+       {
+               precache_sound(this.noise);
+               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+       }
+
+       this.active = ACTIVE_ACTIVE;
+
+       // keys: angle, speed, phase, noise, freq
+
+       if(!this.speed)
+               this.speed = 30;
+       // not initializing this.dmg to 2, to allow damageless pendulum
+
+       if(this.dmg && (this.message == ""))
+               this.message = " was squished";
+       if(this.dmg && (this.message2 == ""))
+               this.message2 = "was squished by";
+       if(this.dmg && (!this.dmgtime))
+               this.dmgtime = 0.25;
+       this.dmgtime2 = time;
+
+       setblocked(this, generic_plat_blocked);
+
+       this.avelocity_z = 0.0000001;
+       if (!InitMovingBrushTrigger(this))
+               return;
+
+       if(!this.freq)
+       {
+               // find pendulum length (same formula as Q3A)
+               this.freq = 1 / (M_PI * 2) * sqrt(autocvar_sv_gravity / (3 * max(8, fabs(this.mins_z))));
+       }
+
+       // copy initial angle
+       this.cnt = this.angles_z;
+
+       // wait for targets to spawn
+       controller = new(func_pendulum_controller);
+       controller.owner = this;
+       controller.nextthink = time + 1;
+       setthink(controller, func_pendulum_controller_think);
+       this.nextthink = this.ltime + 999999999;
+       setthink(this, SUB_NullThink); // for PushMove
+
+       //this.effects |= EF_LOWPRECISION;
+
+       // TODO make a reset function for this one
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/pendulum.qh b/qcsrc/common/mapobjects/func/pendulum.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/func/plat.qc b/qcsrc/common/mapobjects/func/plat.qc
new file mode 100644 (file)
index 0000000..b052336
--- /dev/null
@@ -0,0 +1,190 @@
+#include "plat.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_PLAT)
+
+#ifdef SVQC
+void plat_link(entity this);
+
+void plat_delayedinit(entity this)
+{
+       plat_link(this);
+       plat_spawn_inside_trigger(this); // the "start moving" trigger
+}
+
+float plat_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_PLAT);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               WriteByte(MSG_ENTITY, this.platmovetype_start);
+               WriteByte(MSG_ENTITY, this.platmovetype_turn);
+               WriteByte(MSG_ENTITY, this.platmovetype_end);
+               WriteByte(MSG_ENTITY, this.spawnflags);
+
+               WriteString(MSG_ENTITY, this.model);
+
+               trigger_common_write(this, true);
+
+               WriteVector(MSG_ENTITY, this.pos1);
+               WriteVector(MSG_ENTITY, this.pos2);
+
+               WriteVector(MSG_ENTITY, this.size);
+
+               WriteAngle(MSG_ENTITY, this.mangle_x);
+               WriteAngle(MSG_ENTITY, this.mangle_y);
+               WriteAngle(MSG_ENTITY, this.mangle_z);
+
+               WriteShort(MSG_ENTITY, this.speed);
+               WriteShort(MSG_ENTITY, this.height);
+               WriteByte(MSG_ENTITY, this.lip);
+               WriteByte(MSG_ENTITY, this.state);
+
+               WriteShort(MSG_ENTITY, this.dmg);
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               // used on client
+       }
+
+       return true;
+}
+
+void plat_link(entity this)
+{
+       //Net_LinkEntity(this, 0, false, plat_send);
+}
+
+spawnfunc(func_plat)
+{
+       if (this.spawnflags & CRUSH)
+       {
+               this.dmg = 10000;
+       }
+
+    if (this.dmg && (this.message == ""))
+       {
+               this.message = "was squished";
+       }
+    if (this.dmg && (this.message2 == ""))
+       {
+               this.message2 = "was squished by";
+       }
+
+       if (this.sounds == 1)
+       {
+               this.noise = "plats/plat1.wav";
+               this.noise1 = "plats/plat2.wav";
+       }
+
+       if (this.sounds == 2)
+       {
+               this.noise = "plats/medplat1.wav";
+               this.noise1 = "plats/medplat2.wav";
+       }
+
+       // WARNING: backwards compatibility because people don't use already existing fields :(
+       if (this.sound1)
+               this.noise = this.sound1;
+       if (this.sound2)
+               this.noise1 = this.sound2;
+
+       if(this.noise && this.noise != "")
+       {
+               precache_sound(this.noise);
+       }
+       if(this.noise1 && this.noise1 != "")
+       {
+               precache_sound(this.noise1);
+       }
+
+       this.mangle = this.angles;
+       this.angles = '0 0 0';
+
+       this.classname = "plat";
+       if (!InitMovingBrushTrigger(this))
+               return;
+       this.effects |= EF_LOWPRECISION;
+       setsize (this, this.mins , this.maxs);
+
+       setblocked(this, plat_crush);
+
+       if (!this.speed) this.speed = 150;
+       if (!this.lip) this.lip = 16;
+       if (!this.height) this.height = this.size.z - this.lip;
+
+       this.pos1 = this.origin;
+       this.pos2 = this.origin;
+       this.pos2_z = this.origin.z - this.height;
+
+       this.reset = plat_reset;
+       this.reset(this);
+
+       InitializeEntity(this, plat_delayedinit, INITPRIO_FINDTARGET);
+}
+#elif defined(CSQC)
+void plat_draw(entity this)
+{
+       Movetype_Physics_NoMatchServer(this);
+       //Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
+}
+
+NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
+{
+       float sf = ReadByte();
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               this.platmovetype_start = ReadByte();
+               this.platmovetype_turn = ReadByte();
+               this.platmovetype_end = ReadByte();
+               this.spawnflags = ReadByte();
+
+               this.model = strzone(ReadString());
+               _setmodel(this, this.model);
+
+               trigger_common_read(this, true);
+
+               this.pos1 = ReadVector();
+               this.pos2 = ReadVector();
+
+               this.size = ReadVector();
+
+               this.mangle_x = ReadAngle();
+               this.mangle_y = ReadAngle();
+               this.mangle_z = ReadAngle();
+
+               this.speed = ReadShort();
+               this.height = ReadShort();
+               this.lip = ReadByte();
+               this.state = ReadByte();
+
+               this.dmg = ReadShort();
+
+               this.classname = "plat";
+               this.solid = SOLID_BSP;
+               set_movetype(this, MOVETYPE_PUSH);
+               this.drawmask = MASK_NORMAL;
+               this.draw = plat_draw;
+               if (isnew) IL_PUSH(g_drawables, this);
+               this.use = plat_use;
+               this.entremove = trigger_remove_generic;
+
+               plat_reset(this); // also called here
+
+               set_movetype(this, MOVETYPE_PUSH);
+               this.move_time = time;
+
+               plat_spawn_inside_trigger(this);
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               plat_reset(this);
+
+               this.move_time = time;
+       }
+       return true;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/plat.qh b/qcsrc/common/mapobjects/func/plat.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/func/pointparticles.qc b/qcsrc/common/mapobjects/func/pointparticles.qc
new file mode 100644 (file)
index 0000000..7de5a03
--- /dev/null
@@ -0,0 +1,341 @@
+#include "pointparticles.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_POINTPARTICLES)
+
+#ifdef SVQC
+// NOTE: also contains func_sparks
+
+bool pointparticles_SendEntity(entity this, entity to, float sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
+
+       // optional features to save space
+       sendflags = sendflags & 0x0F;
+       if(this.spawnflags & PARTICLES_IMPULSE)
+               sendflags |= SF_POINTPARTICLES_IMPULSE; // absolute count on toggle-on
+       if(this.movedir != '0 0 0' || this.velocity != '0 0 0')
+               sendflags |= SF_POINTPARTICLES_MOVING; // 4 bytes - saves CPU
+       if(this.waterlevel || this.count != 1)
+               sendflags |= SF_POINTPARTICLES_JITTER_AND_COUNT; // 4 bytes - obscure features almost never used
+       if(this.mins != '0 0 0' || this.maxs != '0 0 0')
+               sendflags |= SF_POINTPARTICLES_BOUNDS; // 14 bytes - saves lots of space
+
+       WriteByte(MSG_ENTITY, sendflags);
+       if(sendflags & SF_TRIGGER_UPDATE)
+       {
+               if(this.active == ACTIVE_ACTIVE)
+                       WriteCoord(MSG_ENTITY, this.impulse);
+               else
+                       WriteCoord(MSG_ENTITY, 0); // off
+       }
+       if(sendflags & SF_TRIGGER_RESET)
+       {
+               WriteVector(MSG_ENTITY, this.origin);
+       }
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               if(this.model != "null")
+               {
+                       WriteShort(MSG_ENTITY, this.modelindex);
+                       if(sendflags & SF_POINTPARTICLES_BOUNDS)
+                       {
+                               WriteVector(MSG_ENTITY, this.mins);
+                               WriteVector(MSG_ENTITY, this.maxs);
+                       }
+               }
+               else
+               {
+                       WriteShort(MSG_ENTITY, 0);
+                       if(sendflags & SF_POINTPARTICLES_BOUNDS)
+                       {
+                               WriteVector(MSG_ENTITY, this.maxs);
+                       }
+               }
+               WriteShort(MSG_ENTITY, this.cnt);
+               WriteString(MSG_ENTITY, this.mdl);
+               if(sendflags & SF_POINTPARTICLES_MOVING)
+               {
+                       WriteShort(MSG_ENTITY, compressShortVector(this.velocity));
+                       WriteShort(MSG_ENTITY, compressShortVector(this.movedir));
+               }
+               if(sendflags & SF_POINTPARTICLES_JITTER_AND_COUNT)
+               {
+                       WriteShort(MSG_ENTITY, this.waterlevel * 16.0);
+                       WriteByte(MSG_ENTITY, this.count * 16.0);
+               }
+               WriteString(MSG_ENTITY, this.noise);
+               if(this.noise != "")
+               {
+                       WriteByte(MSG_ENTITY, floor(this.atten * 64));
+                       WriteByte(MSG_ENTITY, floor(this.volume * 255));
+               }
+               WriteString(MSG_ENTITY, this.bgmscript);
+               if(this.bgmscript != "")
+               {
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
+               }
+       }
+       return 1;
+}
+
+void pointparticles_think(entity this)
+{
+       if(this.origin != this.oldorigin)
+       {
+               this.SendFlags |= SF_TRIGGER_RESET;
+               this.oldorigin = this.origin;
+       }
+       this.nextthink = time;
+}
+
+spawnfunc(func_pointparticles)
+{
+       if(this.model != "") { precache_model(this.model); _setmodel(this, this.model); }
+       if(this.noise != "") precache_sound(this.noise);
+       if(this.mdl != "") this.cnt = 0; // use a good handler
+
+       if(!this.bgmscriptsustain) this.bgmscriptsustain = 1;
+       else if(this.bgmscriptsustain < 0) this.bgmscriptsustain = 0;
+
+       if(!this.atten) this.atten = ATTEN_NORM;
+       else if(this.atten < 0) this.atten = 0;
+       if(!this.volume) this.volume = 1;
+       if(!this.count) this.count = 1;
+       if(!this.impulse) this.impulse = 1;
+
+       if(!this.modelindex)
+       {
+               setorigin(this, this.origin + this.mins);
+               setsize(this, '0 0 0', this.maxs - this.mins);
+       }
+       //if(!this.cnt) this.cnt = _particleeffectnum(this.mdl);
+       this.setactive = generic_netlinked_setactive;
+
+       Net_LinkEntity(this, (this.spawnflags & PARTICLES_VISCULLING), 0, pointparticles_SendEntity);
+
+       IFTARGETED
+       {
+               // backwards compatibility
+               this.use = generic_netlinked_legacy_use;
+       }
+       this.reset = generic_netlinked_reset;
+       this.reset(this);
+       setthink(this, pointparticles_think);
+       this.nextthink = time;
+}
+
+spawnfunc(func_sparks)
+{
+       if(this.count < 1) {
+               this.count = 25.0; // nice default value
+       }
+
+       if(this.impulse < 0.5) {
+               this.impulse = 2.5; // nice default value
+       }
+
+       this.mins = '0 0 0';
+       this.maxs = '0 0 0';
+       this.velocity = '0 0 -1';
+       this.mdl = "TE_SPARK";
+       this.cnt = 0; // use mdl
+
+       spawnfunc_func_pointparticles(this);
+}
+#elif defined(CSQC)
+
+.int dphitcontentsmask;
+
+entityclass(PointParticles);
+classfield(PointParticles) .int cnt; // effect number
+classfield(PointParticles) .vector velocity; // particle velocity
+classfield(PointParticles) .float waterlevel; // direction jitter
+classfield(PointParticles) .int count; // count multiplier
+classfield(PointParticles) .int impulse; // density
+classfield(PointParticles) .string noise; // sound
+classfield(PointParticles) .float atten;
+classfield(PointParticles) .float volume;
+classfield(PointParticles) .float absolute; // 1 = count per second is absolute, ABSOLUTE_ONLY_SPAWN_AT_TOGGLE = only spawn at toggle
+classfield(PointParticles) .vector movedir; // trace direction
+classfield(PointParticles) .float glow_color; // palette index
+
+const int ABSOLUTE_ONLY_SPAWN_AT_TOGGLE = 2;
+
+void Draw_PointParticles(entity this)
+{
+       float n, i, fail;
+       vector p;
+       vector sz;
+       vector o;
+       o = this.origin;
+       sz = this.maxs - this.mins;
+       n = doBGMScript(this);
+       if(this.absolute == ABSOLUTE_ONLY_SPAWN_AT_TOGGLE)
+       {
+               if(n >= 0)
+                       n = this.just_toggled ? this.impulse : 0;
+               else
+                       n = this.impulse * drawframetime;
+       }
+       else
+       {
+               n *= this.impulse * drawframetime;
+               if(this.just_toggled)
+                       if(n < 1)
+                               n = 1;
+       }
+       if(n == 0)
+               return;
+       fail = 0;
+       for(i = random(); i <= n && fail <= 64*n; ++i)
+       {
+               p = o + this.mins;
+               p.x += random() * sz.x;
+               p.y += random() * sz.y;
+               p.z += random() * sz.z;
+               if(WarpZoneLib_BoxTouchesBrush(p, p, this, NULL))
+               {
+                       if(this.movedir != '0 0 0')
+                       {
+                               traceline(p, p + normalize(this.movedir) * 4096, 0, NULL);
+                               p = trace_endpos;
+                               int eff_num;
+                               if(this.cnt)
+                                       eff_num = this.cnt;
+                               else
+                                       eff_num = _particleeffectnum(this.mdl);
+                               __pointparticles(eff_num, p, trace_plane_normal * vlen(this.movedir) + this.velocity + randomvec() * this.waterlevel, this.count);
+                       }
+                       else
+                       {
+                               int eff_num;
+                               if(this.cnt)
+                                       eff_num = this.cnt;
+                               else
+                                       eff_num = _particleeffectnum(this.mdl);
+                               __pointparticles(eff_num, p, this.velocity + randomvec() * this.waterlevel, this.count);
+                       }
+                       if(this.noise != "")
+                       {
+                               setorigin(this, p);
+                               _sound(this, CH_AMBIENT, this.noise, VOL_BASE * this.volume, this.atten);
+                       }
+                       this.just_toggled = 0;
+               }
+               else if(this.absolute)
+               {
+                       ++fail;
+                       --i;
+               }
+       }
+       setorigin(this, o);
+}
+
+void Ent_PointParticles_Remove(entity this)
+{
+    strfree(this.noise);
+    strfree(this.bgmscript);
+    strfree(this.mdl);
+}
+
+NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
+{
+       float i;
+       vector v;
+       int sendflags = ReadByte();
+       if(sendflags & SF_TRIGGER_UPDATE)
+       {
+               i = ReadCoord(); // density (<0: point, >0: volume)
+               if(i && !this.impulse && (this.cnt || this.mdl)) // this.cnt check is so it only happens if the ent already existed
+                       this.just_toggled = 1;
+               this.impulse = i;
+       }
+       if(sendflags & SF_TRIGGER_RESET)
+       {
+               this.origin = ReadVector();
+       }
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               this.modelindex = ReadShort();
+               if(sendflags & SF_POINTPARTICLES_BOUNDS)
+               {
+                       if(this.modelindex)
+                       {
+                               this.mins = ReadVector();
+                               this.maxs = ReadVector();
+                       }
+                       else
+                       {
+                               this.mins    = '0 0 0';
+                               this.maxs = ReadVector();
+                       }
+               }
+               else
+               {
+                       this.mins = this.maxs = '0 0 0';
+               }
+
+               this.cnt = ReadShort(); // effect number
+               this.mdl = strzone(ReadString()); // effect string
+
+               if(sendflags & SF_POINTPARTICLES_MOVING)
+               {
+                       this.velocity = decompressShortVector(ReadShort());
+                       this.movedir = decompressShortVector(ReadShort());
+               }
+               else
+               {
+                       this.velocity = this.movedir = '0 0 0';
+               }
+               if(sendflags & SF_POINTPARTICLES_JITTER_AND_COUNT)
+               {
+                       this.waterlevel = ReadShort() / 16.0;
+                       this.count = ReadByte() / 16.0;
+               }
+               else
+               {
+                       this.waterlevel = 0;
+                       this.count = 1;
+               }
+               strcpy(this.noise, ReadString());
+               if(this.noise != "")
+               {
+                       this.atten = ReadByte() / 64.0;
+                       this.volume = ReadByte() / 255.0;
+               }
+               strcpy(this.bgmscript, ReadString());
+               if(this.bgmscript != "")
+               {
+                       this.bgmscriptattack = ReadByte() / 64.0;
+                       this.bgmscriptdecay = ReadByte() / 64.0;
+                       this.bgmscriptsustain = ReadByte() / 255.0;
+                       this.bgmscriptrelease = ReadByte() / 64.0;
+               }
+               BGMScript_InitEntity(this);
+       }
+
+       return = true;
+
+       if(sendflags & SF_TRIGGER_UPDATE)
+       {
+               this.absolute = (this.impulse >= 0);
+               if(!this.absolute)
+               {
+                       v = this.maxs - this.mins;
+                       this.impulse *= -v.x * v.y * v.z / (64**3); // relative: particles per 64^3 cube
+               }
+       }
+
+       if(sendflags & SF_POINTPARTICLES_IMPULSE)
+               this.absolute = ABSOLUTE_ONLY_SPAWN_AT_TOGGLE;
+
+       setorigin(this, this.origin);
+       setsize(this, this.mins, this.maxs);
+       this.solid = SOLID_NOT;
+       this.draw = Draw_PointParticles;
+       if (isnew) IL_PUSH(g_drawables, this);
+       this.entremove = Ent_PointParticles_Remove;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/pointparticles.qh b/qcsrc/common/mapobjects/func/pointparticles.qh
new file mode 100644 (file)
index 0000000..b167527
--- /dev/null
@@ -0,0 +1,11 @@
+#pragma once
+
+// spawnflags
+const int PARTICLES_IMPULSE = BIT(1);
+const int PARTICLES_VISCULLING = BIT(2);
+
+// sendflags
+const int SF_POINTPARTICLES_IMPULSE = BIT(4);
+const int SF_POINTPARTICLES_MOVING = BIT(5); // Send velocity and movedir
+const int SF_POINTPARTICLES_JITTER_AND_COUNT = BIT(6); // Send waterlevel (=jitter) and count
+const int SF_POINTPARTICLES_BOUNDS = BIT(7); // Send min and max of the brush
diff --git a/qcsrc/common/mapobjects/func/rainsnow.qc b/qcsrc/common/mapobjects/func/rainsnow.qc
new file mode 100644 (file)
index 0000000..c765a42
--- /dev/null
@@ -0,0 +1,142 @@
+#include "rainsnow.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
+
+#ifdef SVQC
+bool rainsnow_SendEntity(entity this, entity to, float sf)
+{
+       vector myorg = this.origin + this.mins;
+       vector mysize = this.maxs - this.mins;
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
+       WriteByte(MSG_ENTITY, this.state);
+       WriteVector(MSG_ENTITY, myorg);
+       WriteVector(MSG_ENTITY, mysize);
+       WriteShort(MSG_ENTITY, compressShortVector(this.dest));
+       WriteShort(MSG_ENTITY, this.count);
+       WriteByte(MSG_ENTITY, this.cnt);
+       return true;
+}
+
+/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
+This is an invisible area like a trigger, which rain falls inside of.
+
+Keys:
+"velocity"
+ falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
+"cnt"
+ sets color of rain (default 12 - white)
+"count"
+ adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
+*/
+spawnfunc(func_rain)
+{
+       this.dest = this.velocity;
+       this.velocity = '0 0 0';
+       if (!this.dest)
+               this.dest = '0 0 -700';
+       this.angles = '0 0 0';
+       set_movetype(this, MOVETYPE_NONE);
+       this.solid = SOLID_NOT;
+       SetBrushEntityModel(this);
+       if (!this.cnt)
+       {
+               this.cnt = 12;
+       }
+       if (!this.count)
+               this.count = 2000;
+       // relative to absolute particle count
+       this.count = 0.1 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
+       if (this.count < 1)
+               this.count = 1;
+       if(this.count > 65535)
+               this.count = 65535;
+
+       this.state = RAINSNOW_RAIN;
+
+       Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
+}
+
+
+/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
+This is an invisible area like a trigger, which snow falls inside of.
+
+Keys:
+"velocity"
+ falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
+"cnt"
+ sets color of rain (default 12 - white)
+"count"
+ adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
+*/
+spawnfunc(func_snow)
+{
+       this.dest = this.velocity;
+       this.velocity = '0 0 0';
+       if (!this.dest)
+               this.dest = '0 0 -300';
+       this.angles = '0 0 0';
+       set_movetype(this, MOVETYPE_NONE);
+       this.solid = SOLID_NOT;
+       SetBrushEntityModel(this);
+       if (!this.cnt)
+       {
+               this.cnt = 12;
+       }
+       if (!this.count)
+               this.count = 2000;
+       // relative to absolute particle count
+       this.count = 0.1 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
+       if (this.count < 1)
+               this.count = 1;
+       if(this.count > 65535)
+               this.count = 65535;
+
+       this.state = RAINSNOW_SNOW;
+
+       Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
+}
+#elif defined(CSQC)
+float autocvar_cl_rainsnow_maxdrawdist = 2048;
+
+void Draw_Rain(entity this)
+{
+       vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
+       maxdist.z = 5;
+       if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
+       //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
+       te_particlerain(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
+}
+
+void Draw_Snow(entity this)
+{
+       vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
+       maxdist.z = 5;
+       if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
+       //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
+       te_particlesnow(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
+}
+
+NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
+{
+       this.state = ReadByte(); // Rain, Snow, or Whatever
+       this.origin = ReadVector();
+       this.maxs = ReadVector();
+       this.velocity = decompressShortVector(ReadShort());
+       this.count = ReadShort();
+       this.glow_color = ReadByte(); // color
+
+       return = true;
+
+       this.mins    = -0.5 * this.maxs;
+       this.maxs    =  0.5 * this.maxs;
+       this.origin  = this.origin - this.mins;
+
+       setorigin(this, this.origin);
+       setsize(this, this.mins, this.maxs);
+       this.solid = SOLID_NOT;
+       if (isnew) IL_PUSH(g_drawables, this);
+       if(this.state == RAINSNOW_RAIN)
+               this.draw = Draw_Rain;
+       else
+               this.draw = Draw_Snow;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/rainsnow.qh b/qcsrc/common/mapobjects/func/rainsnow.qh
new file mode 100644 (file)
index 0000000..d60eb4f
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const int RAINSNOW_SNOW = 0;
+const int RAINSNOW_RAIN = 1;
diff --git a/qcsrc/common/mapobjects/func/rotating.qc b/qcsrc/common/mapobjects/func/rotating.qc
new file mode 100644 (file)
index 0000000..35351ee
--- /dev/null
@@ -0,0 +1,110 @@
+#include "rotating.qh"
+#ifdef SVQC
+
+void func_rotating_setactive(entity this, int astate)
+{
+       if (astate == ACTIVE_TOGGLE)
+       {
+               if(this.active == ACTIVE_ACTIVE)
+                       this.active = ACTIVE_NOT;
+               else
+                       this.active = ACTIVE_ACTIVE;
+       }
+       else
+               this.active = astate;
+
+       if(this.active  == ACTIVE_NOT)
+       {
+               this.avelocity = '0 0 0';
+               stopsound(this, CH_AMBIENT_SINGLE);
+       }
+       else
+       {
+               this.avelocity = this.pos1;
+               if(this.noise && this.noise != "")
+               {
+                       _sound(this, CH_AMBIENT_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+               }
+       }
+}
+
+void func_rotating_reset(entity this)
+{
+       // TODO: reset angles as well?
+
+       if(this.spawnflags & FUNC_ROTATING_STARTOFF)
+       {
+               this.setactive(this, ACTIVE_NOT);
+       }
+       else
+       {
+               this.setactive(this, ACTIVE_ACTIVE);
+       }
+}
+
+void func_rotating_init_for_player(entity this, entity player)
+{
+       if (this.noise && this.noise != "" && this.active == ACTIVE_ACTIVE && IS_REAL_CLIENT(player))
+       {
+               msg_entity = player;
+               soundto (MSG_ONE, this, CH_AMBIENT_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+       }
+}
+
+/*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
+Brush model that spins in place on one axis (default Z).
+speed   : speed to rotate (in degrees per second)
+noise   : path/name of looping .wav file to play.
+dmg     : Do this mutch dmg every .dmgtime intervall when blocked
+dmgtime : See above.
+*/
+
+spawnfunc(func_rotating)
+{
+       if (this.noise && this.noise != "")
+       {
+               precache_sound(this.noise);
+       }
+
+       this.setactive = func_rotating_setactive;
+
+       if (!this.speed)
+               this.speed = 100;
+       if (this.spawnflags & FUNC_ROTATING_XAXIS)
+               this.avelocity = '0 0 1' * this.speed;
+       else if (this.spawnflags & FUNC_ROTATING_YAXIS)
+               this.avelocity = '1 0 0' * this.speed;
+       else // Z
+               this.avelocity = '0 1 0' * this.speed;
+
+       this.pos1 = this.avelocity;
+
+    if(this.dmg && (this.message == ""))
+        this.message = " was squished";
+    if(this.dmg && (this.message2 == ""))
+               this.message2 = "was squished by";
+
+
+    if(this.dmg && (!this.dmgtime))
+        this.dmgtime = 0.25;
+
+    this.dmgtime2 = time;
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+       // no EF_LOWPRECISION here, as rounding angles is bad
+
+    setblocked(this, generic_plat_blocked);
+
+       // wait for targets to spawn
+       this.nextthink = this.ltime + 999999999;
+       setthink(this, SUB_NullThink); // for PushMove
+
+       this.reset = func_rotating_reset;
+       this.reset(this);
+
+       // maybe send sound to new players
+       IL_PUSH(g_initforplayer, this);
+       this.init_for_player = func_rotating_init_for_player;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/rotating.qh b/qcsrc/common/mapobjects/func/rotating.qh
new file mode 100644 (file)
index 0000000..ad1b6ec
--- /dev/null
@@ -0,0 +1,6 @@
+#pragma once
+
+
+const int FUNC_ROTATING_XAXIS = BIT(2);
+const int FUNC_ROTATING_YAXIS = BIT(3);
+const int FUNC_ROTATING_STARTOFF = BIT(4);
diff --git a/qcsrc/common/mapobjects/func/stardust.qc b/qcsrc/common/mapobjects/func/stardust.qc
new file mode 100644 (file)
index 0000000..9c2fba8
--- /dev/null
@@ -0,0 +1,9 @@
+#include "stardust.qh"
+#ifdef SVQC
+spawnfunc(func_stardust)
+{
+       this.effects = EF_STARDUST;
+
+       CSQCMODEL_AUTOINIT(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/stardust.qh b/qcsrc/common/mapobjects/func/stardust.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/func/train.qc b/qcsrc/common/mapobjects/func/train.qc
new file mode 100644 (file)
index 0000000..4e9c334
--- /dev/null
@@ -0,0 +1,351 @@
+#include "train.qh"
+.float train_wait_turning;
+.entity future_target;
+void train_next(entity this);
+#ifdef SVQC
+void train_use(entity this, entity actor, entity trigger);
+#endif
+void train_wait(entity this)
+{
+       SUB_UseTargets(this.enemy, NULL, NULL);
+       this.enemy = NULL;
+
+       // if turning is enabled, the train will turn toward the next point while waiting
+       if(this.platmovetype_turn && !this.train_wait_turning)
+       {
+               entity targ, cp;
+               vector ang;
+               targ = this.future_target;
+               if((this.spawnflags & TRAIN_CURVE) && targ.curvetarget)
+                       cp = find(NULL, targetname, targ.curvetarget);
+               else
+                       cp = NULL;
+
+               if(cp) // bezier curves movement
+                       ang = cp.origin - (this.origin - this.view_ofs); // use the origin of the control point of the next path_corner
+               else // linear movement
+                       ang = targ.origin - (this.origin - this.view_ofs); // use the origin of the next path_corner
+               ang = vectoangles(ang);
+               ang_x = -ang_x; // flip up / down orientation
+
+               if(this.wait > 0) // slow turning
+                       SUB_CalcAngleMove(this, ang, TSPEED_TIME, this.ltime - time + this.wait, train_wait);
+               else // instant turning
+                       SUB_CalcAngleMove(this, ang, TSPEED_TIME, 0.0000001, train_wait);
+               this.train_wait_turning = true;
+               return;
+       }
+
+#ifdef SVQC
+       if(this.noise != "")
+               stopsoundto(MSG_BROADCAST, this, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
+#endif
+
+#ifdef SVQC
+       entity tg = this.future_target;
+       if(tg.spawnflags & TRAIN_NEEDACTIVATION)
+       {
+               this.use = train_use;
+               setthink(this, func_null);
+               this.nextthink = 0;
+       }
+       else
+#endif
+            if(this.wait < 0 || this.train_wait_turning) // no waiting or we already waited while turning
+       {
+               this.train_wait_turning = false;
+               train_next(this);
+       }
+       else
+       {
+               setthink(this, train_next);
+               this.nextthink = this.ltime + this.wait;
+       }
+}
+
+entity train_next_find(entity this)
+{
+       if(this.target_random)
+       {
+               RandomSelection_Init();
+               for(entity t = NULL; (t = find(t, targetname, this.target));)
+               {
+                       RandomSelection_AddEnt(t, 1, 0);
+               }
+               return RandomSelection_chosen_ent;
+       }
+       else
+       {
+               return find(NULL, targetname, this.target);
+       }
+}
+
+void train_next(entity this)
+{
+       entity targ = NULL, cp = NULL;
+       vector cp_org = '0 0 0';
+
+       targ = this.future_target;
+
+       this.target = targ.target;
+       this.target_random = targ.target_random;
+       this.future_target = train_next_find(targ);
+
+       if (this.spawnflags & TRAIN_CURVE)
+       {
+               if(targ.curvetarget)
+               {
+                       cp = find(NULL, targetname, targ.curvetarget); // get its second target (the control point)
+                       cp_org = cp.origin - this.view_ofs; // no control point found, assume a straight line to the destination
+               }
+       }
+       if (this.target == "")
+               objerror(this, "train_next: no next target");
+       this.wait = targ.wait;
+       if (!this.wait)
+               this.wait = 0.1;
+
+       if(targ.platmovetype)
+       {
+               // this path_corner contains a movetype overrider, apply it
+               this.platmovetype_start = targ.platmovetype_start;
+               this.platmovetype_end = targ.platmovetype_end;
+       }
+       else
+       {
+               // this path_corner doesn't contain a movetype overrider, use the train's defaults
+               this.platmovetype_start = this.platmovetype_start_default;
+               this.platmovetype_end = this.platmovetype_end_default;
+       }
+
+       if (targ.speed)
+       {
+               if (cp)
+                       SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+               else
+                       SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
+       }
+       else
+       {
+               if (cp)
+                       SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
+               else
+                       SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
+       }
+
+       if(this.noise != "")
+               _sound(this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_TRAIN)
+
+#ifdef SVQC
+float train_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRAIN);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               WriteString(MSG_ENTITY, this.platmovetype);
+               WriteByte(MSG_ENTITY, this.platmovetype_turn);
+               WriteByte(MSG_ENTITY, this.spawnflags);
+
+               WriteString(MSG_ENTITY, this.model);
+
+               trigger_common_write(this, true);
+
+               WriteString(MSG_ENTITY, this.curvetarget);
+
+               WriteVector(MSG_ENTITY, this.pos1);
+               WriteVector(MSG_ENTITY, this.pos2);
+
+               WriteVector(MSG_ENTITY, this.size);
+
+               WriteVector(MSG_ENTITY, this.view_ofs);
+
+               WriteAngle(MSG_ENTITY, this.mangle_x);
+               WriteAngle(MSG_ENTITY, this.mangle_y);
+               WriteAngle(MSG_ENTITY, this.mangle_z);
+
+               WriteShort(MSG_ENTITY, this.speed);
+               WriteShort(MSG_ENTITY, this.height);
+               WriteByte(MSG_ENTITY, this.lip);
+               WriteByte(MSG_ENTITY, this.state);
+               WriteByte(MSG_ENTITY, this.wait);
+
+               WriteShort(MSG_ENTITY, this.dmg);
+               WriteByte(MSG_ENTITY, this.dmgtime);
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               // used on client
+       }
+
+       return true;
+}
+
+void train_link(entity this)
+{
+       //Net_LinkEntity(this, 0, false, train_send);
+}
+
+void train_use(entity this, entity actor, entity trigger)
+{
+       this.nextthink = this.ltime + 1;
+       setthink(this, train_next);
+       this.use = func_null; // not again, next target can set it again if needed
+       if(trigger.target2 && trigger.target2 != "")
+               this.future_target = find(NULL, targetname, trigger.target2);
+}
+
+void func_train_find(entity this)
+{
+       entity targ = train_next_find(this);
+       this.target = targ.target;
+       this.target_random = targ.target_random;
+       // save the future target for later
+       this.future_target = train_next_find(targ);
+       if (this.target == "")
+               objerror(this, "func_train_find: no next target");
+       setorigin(this, targ.origin - this.view_ofs);
+
+       if(!(this.spawnflags & TRAIN_NEEDACTIVATION))
+       {
+               this.nextthink = this.ltime + 1;
+               setthink(this, train_next);
+       }
+
+       train_link(this);
+}
+
+#endif
+
+/*QUAKED spawnfunc_func_train (0 .5 .8) ?
+Ridable platform, targets spawnfunc_path_corner path to follow.
+speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
+target : targetname of first spawnfunc_path_corner (starts here)
+*/
+#ifdef SVQC
+spawnfunc(func_train)
+{
+       if (this.noise != "")
+               precache_sound(this.noise);
+
+       if (this.target == "")
+               objerror(this, "func_train without a target");
+       if (!this.speed)
+               this.speed = 100;
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+       this.effects |= EF_LOWPRECISION;
+
+       if(this.spawnflags & TRAIN_NEEDACTIVATION)
+               this.use = train_use;
+
+       if (this.spawnflags & TRAIN_TURN)
+       {
+               this.platmovetype_turn = true;
+               this.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
+       }
+       else
+               this.view_ofs = this.mins;
+
+       // wait for targets to spawn
+       InitializeEntity(this, func_train_find, INITPRIO_FINDTARGET);
+
+       setblocked(this, generic_plat_blocked);
+       if(this.dmg && (this.message == ""))
+               this.message = " was squished";
+    if(this.dmg && (this.message2 == ""))
+               this.message2 = "was squished by";
+       if(this.dmg && (!this.dmgtime))
+               this.dmgtime = 0.25;
+       this.dmgtime2 = time;
+
+       if(!set_platmovetype(this, this.platmovetype))
+               return;
+       this.platmovetype_start_default = this.platmovetype_start;
+       this.platmovetype_end_default = this.platmovetype_end;
+
+       // TODO make a reset function for this one
+}
+#elif defined(CSQC)
+void train_draw(entity this)
+{
+       //Movetype_Physics_NoMatchServer();
+       Movetype_Physics_MatchServer(this, autocvar_cl_projectiles_sloppy);
+}
+
+NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
+{
+       float sf = ReadByte();
+
+       if(sf & SF_TRIGGER_INIT)
+       {
+               this.platmovetype = strzone(ReadString());
+               this.platmovetype_turn = ReadByte();
+               this.spawnflags = ReadByte();
+
+               this.model = strzone(ReadString());
+               _setmodel(this, this.model);
+
+               trigger_common_read(this, true);
+
+               this.curvetarget = strzone(ReadString());
+
+               this.pos1 = ReadVector();
+               this.pos2 = ReadVector();
+
+               this.size = ReadVector();
+
+               this.view_ofs = ReadVector();
+
+               this.mangle_x = ReadAngle();
+               this.mangle_y = ReadAngle();
+               this.mangle_z = ReadAngle();
+
+               this.speed = ReadShort();
+               this.height = ReadShort();
+               this.lip = ReadByte();
+               this.state = ReadByte();
+               this.wait = ReadByte();
+
+               this.dmg = ReadShort();
+               this.dmgtime = ReadByte();
+
+               this.classname = "func_train";
+               this.solid = SOLID_BSP;
+               set_movetype(this, MOVETYPE_PUSH);
+               this.drawmask = MASK_NORMAL;
+               this.draw = train_draw;
+               if (isnew) IL_PUSH(g_drawables, this);
+               this.entremove = trigger_remove_generic;
+
+               if(set_platmovetype(this, this.platmovetype))
+               {
+                       this.platmovetype_start_default = this.platmovetype_start;
+                       this.platmovetype_end_default = this.platmovetype_end;
+               }
+
+               // everything is set up by the time the train is linked, we shouldn't need this
+               //func_train_find();
+
+               // but we will need these
+               train_next(this);
+
+               set_movetype(this, MOVETYPE_PUSH);
+               this.move_time = time;
+       }
+
+       if(sf & SF_TRIGGER_RESET)
+       {
+               // TODO: make a reset function for trains
+       }
+
+       return true;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/func/train.qh b/qcsrc/common/mapobjects/func/train.qh
new file mode 100644 (file)
index 0000000..0b2a099
--- /dev/null
@@ -0,0 +1,10 @@
+#pragma once
+
+
+const int TRAIN_CURVE = BIT(0);
+const int TRAIN_TURN = BIT(1);
+const int TRAIN_NEEDACTIVATION = BIT(2);
+
+#ifdef CSQC
+.float dmgtime;
+#endif
diff --git a/qcsrc/common/mapobjects/func/vectormamamam.qc b/qcsrc/common/mapobjects/func/vectormamamam.qc
new file mode 100644 (file)
index 0000000..61da52a
--- /dev/null
@@ -0,0 +1,194 @@
+#include "vectormamamam.qh"
+#ifdef SVQC
+// reusing some fields havocbots declared
+.entity wp00, wp01, wp02, wp03;
+
+.float targetfactor, target2factor, target3factor, target4factor;
+.vector targetnormal, target2normal, target3normal, target4normal;
+
+vector func_vectormamamam_origin(entity o, float timestep)
+{
+       vector v, p;
+       float flags;
+       entity e;
+
+       flags = o.spawnflags;
+       v = '0 0 0';
+
+       e = o.wp00;
+       if(e)
+       {
+               p = e.origin + timestep * e.velocity;
+               if(flags & PROJECT_ON_TARGETNORMAL)
+                       v = v + (p * o.targetnormal) * o.targetnormal * o.targetfactor;
+               else
+                       v = v + (p - (p * o.targetnormal) * o.targetnormal) * o.targetfactor;
+       }
+
+       e = o.wp01;
+       if(e)
+       {
+               p = e.origin + timestep * e.velocity;
+               if(flags & PROJECT_ON_TARGET2NORMAL)
+                       v = v + (p * o.target2normal) * o.target2normal * o.target2factor;
+               else
+                       v = v + (p - (p * o.target2normal) * o.target2normal) * o.target2factor;
+       }
+
+       e = o.wp02;
+       if(e)
+       {
+               p = e.origin + timestep * e.velocity;
+               if(flags & PROJECT_ON_TARGET3NORMAL)
+                       v = v + (p * o.target3normal) * o.target3normal * o.target3factor;
+               else
+                       v = v + (p - (p * o.target3normal) * o.target3normal) * o.target3factor;
+       }
+
+       e = o.wp03;
+       if(e)
+       {
+               p = e.origin + timestep * e.velocity;
+               if(flags & PROJECT_ON_TARGET4NORMAL)
+                       v = v + (p * o.target4normal) * o.target4normal * o.target4factor;
+               else
+                       v = v + (p - (p * o.target4normal) * o.target4normal) * o.target4factor;
+       }
+
+       return v;
+}
+
+void func_vectormamamam_controller_think(entity this)
+{
+       this.nextthink = time + vectormamamam_timestep;
+
+       if(this.owner.active != ACTIVE_ACTIVE)
+       {
+               this.owner.velocity = '0 0 0';
+               return;
+       }
+
+       if(this.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed
+               this.owner.velocity = (this.owner.destvec + func_vectormamamam_origin(this.owner, vectormamamam_timestep) - this.owner.origin) * 10;
+}
+
+void func_vectormamamam_findtarget(entity this)
+{
+       if(this.target != "")
+               this.wp00 = find(NULL, targetname, this.target);
+
+       if(this.target2 != "")
+               this.wp01 = find(NULL, targetname, this.target2);
+
+       if(this.target3 != "")
+               this.wp02 = find(NULL, targetname, this.target3);
+
+       if(this.target4 != "")
+               this.wp03 = find(NULL, targetname, this.target4);
+
+       if(!this.wp00 && !this.wp01 && !this.wp02 && !this.wp03)
+               objerror(this, "No reference entity found, so there is nothing to move. Aborting.");
+
+       this.destvec = this.origin - func_vectormamamam_origin(this, 0);
+
+       entity controller;
+       controller = new(func_vectormamamam_controller);
+       controller.owner = this;
+       controller.nextthink = time + 1;
+       setthink(controller, func_vectormamamam_controller_think);
+}
+
+void func_vectormamamam_setactive(entity this, int astate)
+{
+       if (astate == ACTIVE_TOGGLE)
+       {
+               if(this.active == ACTIVE_ACTIVE)
+                       this.active = ACTIVE_NOT;
+               else
+                       this.active = ACTIVE_ACTIVE;
+       }
+       else
+               this.active = astate;
+
+       if(this.active  == ACTIVE_NOT)
+       {
+               stopsound(this, CH_TRIGGER_SINGLE);
+       }
+       else
+       {
+               if(this.noise && this.noise != "")
+               {
+                       _sound(this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+               }
+       }
+}
+
+void func_vectormamamam_init_for_player(entity this, entity player)
+{
+       if (this.noise && this.noise != "" && this.active == ACTIVE_ACTIVE && IS_REAL_CLIENT(player))
+       {
+               msg_entity = player;
+               soundto(MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
+       }
+}
+
+spawnfunc(func_vectormamamam)
+{
+       if (this.noise != "")
+       {
+               precache_sound(this.noise);
+       }
+
+       if(!this.targetfactor)
+               this.targetfactor = 1;
+
+       if(!this.target2factor)
+               this.target2factor = 1;
+
+       if(!this.target3factor)
+               this.target3factor = 1;
+
+       if(!this.target4factor)
+               this.target4factor = 1;
+
+       if(this.targetnormal)
+               this.targetnormal = normalize(this.targetnormal);
+
+       if(this.target2normal)
+               this.target2normal = normalize(this.target2normal);
+
+       if(this.target3normal)
+               this.target3normal = normalize(this.target3normal);
+
+       if(this.target4normal)
+               this.target4normal = normalize(this.target4normal);
+
+       setblocked(this, generic_plat_blocked);
+       if(this.dmg && (this.message == ""))
+               this.message = " was squished";
+    if(this.dmg && (this.message == ""))
+               this.message2 = "was squished by";
+       if(this.dmg && (!this.dmgtime))
+               this.dmgtime = 0.25;
+       this.dmgtime2 = time;
+
+       if (!InitMovingBrushTrigger(this))
+               return;
+
+       // wait for targets to spawn
+       this.nextthink = this.ltime + 999999999;
+       setthink(this, SUB_NullThink); // for PushMove
+
+       // Savage: Reduce bandwith, critical on e.g. nexdm02
+       this.effects |= EF_LOWPRECISION;
+
+       this.setactive = func_vectormamamam_setactive;
+       this.setactive(this, ACTIVE_ACTIVE);
+
+       // maybe send sound to new players
+       IL_PUSH(g_initforplayer, this);
+       this.init_for_player = func_vectormamamam_init_for_player;
+
+       InitializeEntity(this, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/func/vectormamamam.qh b/qcsrc/common/mapobjects/func/vectormamamam.qh
new file mode 100644 (file)
index 0000000..7eb6b0a
--- /dev/null
@@ -0,0 +1,9 @@
+#pragma once
+
+
+const int PROJECT_ON_TARGETNORMAL = BIT(0);
+const int PROJECT_ON_TARGET2NORMAL = BIT(1);
+const int PROJECT_ON_TARGET3NORMAL = BIT(2);
+const int PROJECT_ON_TARGET4NORMAL = BIT(3);
+
+const float vectormamamam_timestep = 0.1;
diff --git a/qcsrc/common/mapobjects/misc/_mod.inc b/qcsrc/common/mapobjects/misc/_mod.inc
new file mode 100644 (file)
index 0000000..498f6c5
--- /dev/null
@@ -0,0 +1,6 @@
+// generated file; do not modify
+#include <common/mapobjects/misc/corner.qc>
+#include <common/mapobjects/misc/dynlight.qc>
+#include <common/mapobjects/misc/follow.qc>
+#include <common/mapobjects/misc/laser.qc>
+#include <common/mapobjects/misc/teleport_dest.qc>
diff --git a/qcsrc/common/mapobjects/misc/_mod.qh b/qcsrc/common/mapobjects/misc/_mod.qh
new file mode 100644 (file)
index 0000000..3415919
--- /dev/null
@@ -0,0 +1,6 @@
+// generated file; do not modify
+#include <common/mapobjects/misc/corner.qh>
+#include <common/mapobjects/misc/dynlight.qh>
+#include <common/mapobjects/misc/follow.qh>
+#include <common/mapobjects/misc/laser.qh>
+#include <common/mapobjects/misc/teleport_dest.qh>
diff --git a/qcsrc/common/mapobjects/misc/corner.qc b/qcsrc/common/mapobjects/misc/corner.qc
new file mode 100644 (file)
index 0000000..a0f67b7
--- /dev/null
@@ -0,0 +1,75 @@
+#include "corner.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_CORNER)
+
+#ifdef SVQC
+bool corner_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_CORNER);
+
+       WriteString(MSG_ENTITY, this.platmovetype);
+
+       WriteVector(MSG_ENTITY, this.origin);
+
+       WriteString(MSG_ENTITY, this.target);
+       WriteString(MSG_ENTITY, this.target2);
+       WriteString(MSG_ENTITY, this.target3);
+       WriteString(MSG_ENTITY, this.target4);
+       WriteString(MSG_ENTITY, this.targetname);
+       WriteByte(MSG_ENTITY, this.target_random);
+
+       WriteByte(MSG_ENTITY, this.wait);
+
+       return true;
+}
+
+void corner_link(entity this)
+{
+       //Net_LinkEntity(this, false, 0, corner_send);
+}
+
+spawnfunc(path_corner)
+{
+       // setup values for overriding train movement
+       // if a second value does not exist, both start and end speeds are the single value specified
+       set_platmovetype(this, this.platmovetype);
+
+       corner_link(this);
+}
+#elif defined(CSQC)
+
+void corner_remove(entity this)
+{
+       strfree(this.target);
+       strfree(this.target2);
+       strfree(this.target3);
+       strfree(this.target4);
+       strfree(this.targetname);
+       strfree(this.platmovetype);
+}
+
+NET_HANDLE(ENT_CLIENT_CORNER, bool isnew)
+{
+       this.platmovetype = strzone(ReadString());
+
+       this.origin = ReadVector();
+       setorigin(this, this.origin);
+
+       this.target = strzone(ReadString());
+       this.target2 = strzone(ReadString());
+       this.target3 = strzone(ReadString());
+       this.target4 = strzone(ReadString());
+       this.targetname = strzone(ReadString());
+       this.target_random = ReadByte();
+
+       this.wait = ReadByte();
+
+       return = true;
+
+       this.classname = "path_corner";
+       this.drawmask = MASK_NORMAL;
+       this.entremove = corner_remove;
+
+       set_platmovetype(this, this.platmovetype);
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/misc/corner.qh b/qcsrc/common/mapobjects/misc/corner.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/misc/dynlight.qc b/qcsrc/common/mapobjects/misc/dynlight.qc
new file mode 100644 (file)
index 0000000..7c70b84
--- /dev/null
@@ -0,0 +1,135 @@
+#include "dynlight.qh"
+
+#ifdef SVQC
+#include <server/defs.qh>
+#include <server/miscfunctions.qh>
+
+const float LOOP = 1;
+
+.float speed;
+
+//const int DNOSHADOW = 2;
+const int DFOLLOW = 4;
+.float light_lev;
+.float lefty;
+.vector color;
+.string dtagname;
+
+/*QUAKED dynlight (0 1 0) (-8 -8 -8) (8 8 8) START_OFF NOSHADOW FOLLOW
+Dynamic spawnfunc_light.
+Can do one of these things: sit still and be just a silly spawnfunc_light, travel along a path, follow an entity around, attach to a tag on an entity.
+It can spin around it's own axis in all the above cases.
+If targeted, it will toggle between on or off.
+keys:
+"light_lev" spawnfunc_light radius, default 200
+"color" spawnfunc_light color in rgb and brightness, 1 1 1 produces bright white, up to 255 255 255 (nuclear blast), recommended values up to 1 1 1, default 1 1 1
+"style" lightstyle, same as for static lights
+"angles" initial orientation
+"avelocity" a vector value, the direction and speed it rotates in
+"skin" cubemap number, must be 16 or above
+"dtagname" will attach to this tag on the entity which "targetname" matches "target". If the "target" is either not an md3 model or is missing tags, it will attach to the targets origin. Note that the "target" must be visible to the spawnfunc_light
+"targetname" will toggle on and off when triggered
+"target" if issued with a target, preferrably spawnfunc_path_corner, it will move along the path. If also issued with the FOLLOW spawnflag, then this is the entity it will follow. If issued with the "tagname" key it will attach it to this targets tag called "tagname", does not work together with FOLLOW or path movement
+"speed" the speed it will travel along the path, default 100
+flags:
+"START_OFF" spawnfunc_light will be in off state until targeted
+"NOSHADOW" will not cast shadows in realtime lighting mode
+"FOLLOW" will follow the entity which "targetname" matches "target"
+*/
+void dynlight_think(entity this)
+{
+       if(!this.owner)
+               delete(this);
+
+       this.nextthink = time + 0.1;
+}
+void dynlight_find_aiment(entity this)
+{
+       entity targ;
+       if (!this.target)
+               objerror (this, "dynlight: no target to follow");
+
+       targ = find(NULL, targetname, this.target);
+       set_movetype(this, MOVETYPE_FOLLOW);
+       this.aiment = targ;
+       this.owner = targ;
+       this.punchangle = targ.angles;
+       this.view_ofs = this.origin - targ.origin;
+       this.v_angle = this.angles - targ.angles;
+       setthink(this, dynlight_think);
+       this.nextthink = time + 0.1;
+}
+void dynlight_find_path(entity this)
+{
+       entity targ;
+       if (!this.target)
+               objerror (this, "dynlight: no target to follow");
+
+       targ = find(NULL, targetname, this.target);
+       this.target = targ.target;
+       setorigin(this, targ.origin);
+       setthink(this, train_next); // TODO: reliant on the train's pathing functions
+       this.nextthink = time + 0.1;
+}
+void dynlight_find_target(entity this)
+{
+       entity targ;
+       if (!this.target)
+               objerror (this, "dynlight: no target to follow");
+
+       targ = find(NULL, targetname, this.target);
+       setattachment(this, targ, this.dtagname);
+       this.owner = targ;
+       setthink(this, dynlight_think);
+       this.nextthink = time + 0.1;
+}
+void dynlight_use(entity this, entity actor, entity trigger)
+{
+       if (this.light_lev == 0)
+               this.light_lev = this.lefty;
+       else
+               this.light_lev = 0;
+}
+spawnfunc(dynlight)
+{
+       if (!this.light_lev)
+               this.light_lev = 200;
+       if (!this.color)
+               this.color = '1 1 1';
+       this.lefty = this.light_lev;
+       this.use = dynlight_use;
+       setsize (this, '0 0 0', '0 0 0');
+       setorigin(this, this.origin);
+       //this.pflags = PFLAGS_FULLDYNAMIC;
+       this.solid = SOLID_NOT;
+       //this.blocked = func_null;
+       //if (this.spawnflags & DNOSHADOW)
+       //      this.pflags = this.pflags + PFLAGS_NOSHADOW;
+       //if (this.spawnflags & START_OFF)
+       //      this.light_lev = 0;
+
+//tag attaching
+       if (this.dtagname)
+       {
+               InitializeEntity(this, dynlight_find_target, INITPRIO_FINDTARGET);
+               return;
+       }
+
+// entity following
+       if (this.spawnflags & DFOLLOW)
+       {
+               InitializeEntity(this, dynlight_find_aiment, INITPRIO_FINDTARGET);
+               return;
+       }
+// path following
+       if (this.target)
+//     if (!(this.spawnflags & DFOLLOW))
+       {
+               set_movetype(this, MOVETYPE_NOCLIP);
+               if (!this.speed)
+                       this.speed = 100;
+               InitializeEntity(this, dynlight_find_path, INITPRIO_FINDTARGET);
+               return;
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/misc/dynlight.qh b/qcsrc/common/mapobjects/misc/dynlight.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/misc/follow.qc b/qcsrc/common/mapobjects/misc/follow.qc
new file mode 100644 (file)
index 0000000..87619ca
--- /dev/null
@@ -0,0 +1,70 @@
+#include "follow.qh"
+// the way this entity works makes it no use to CSQC, as it removes itself instantly
+
+#ifdef SVQC
+void follow_init(entity this)
+{
+       entity src, dst;
+       src = NULL;
+       dst = NULL;
+       if(this.killtarget != "")
+               src = find(NULL, targetname, this.killtarget);
+       if(this.target != "")
+               dst = find(NULL, targetname, this.target);
+
+       if(!src && !dst)
+       {
+               objerror(this, "follow: could not find target/killtarget");
+               return;
+       }
+
+       if(this.jointtype)
+       {
+               // already done :P entity must stay
+               this.aiment = src;
+               this.enemy = dst;
+       }
+       else if(!src || !dst)
+       {
+               objerror(this, "follow: could not find target/killtarget");
+               return;
+       }
+       else if(this.spawnflags & FOLLOW_ATTACH)
+       {
+               // attach
+               if(this.spawnflags & FOLLOW_LOCAL)
+               {
+                       setattachment(dst, src, this.message);
+               }
+               else
+               {
+                       attach_sameorigin(dst, src, this.message);
+               }
+
+               dst.solid = SOLID_NOT; // solid doesn't work with attachment
+               delete(this);
+       }
+       else
+       {
+               if(this.spawnflags & FOLLOW_LOCAL)
+               {
+                       set_movetype(dst, MOVETYPE_FOLLOW);
+                       dst.aiment = src;
+                       // dst.punchangle = '0 0 0'; // keep unchanged
+                       dst.view_ofs = dst.origin;
+                       dst.v_angle = dst.angles;
+               }
+               else
+               {
+                       follow_sameorigin(dst, src);
+               }
+
+               delete(this);
+       }
+}
+
+spawnfunc(misc_follow)
+{
+       InitializeEntity(this, follow_init, INITPRIO_FINDTARGET);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/misc/follow.qh b/qcsrc/common/mapobjects/misc/follow.qh
new file mode 100644 (file)
index 0000000..aef491f
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const int FOLLOW_ATTACH = BIT(0);
+const int FOLLOW_LOCAL = BIT(1);
diff --git a/qcsrc/common/mapobjects/misc/laser.qc b/qcsrc/common/mapobjects/misc/laser.qc
new file mode 100644 (file)
index 0000000..df88b75
--- /dev/null
@@ -0,0 +1,418 @@
+#include "laser.qh"
+#if defined(CSQC)
+       #include <lib/csqcmodel/interpolate.qh>
+       #include <client/main.qh>
+       #include <lib/csqcmodel/cl_model.qh>
+#elif defined(MENUQC)
+#elif defined(SVQC)
+#endif
+
+REGISTER_NET_LINKED(ENT_CLIENT_LASER)
+
+#ifdef SVQC
+.float modelscale;
+void misc_laser_aim(entity this)
+{
+       vector a;
+       if(this.enemy)
+       {
+               if(this.spawnflags & LASER_FINITE)
+               {
+                       if(this.enemy.origin != this.mangle)
+                       {
+                               this.mangle = this.enemy.origin;
+                               this.SendFlags |= SF_LASER_UPDATE_TARGET;
+                       }
+               }
+               else
+               {
+                       a = vectoangles(this.enemy.origin - this.origin);
+                       a_x = -a_x;
+                       if(a != this.mangle)
+                       {
+                               this.mangle = a;
+                               this.SendFlags |= SF_LASER_UPDATE_TARGET;
+                       }
+               }
+       }
+       else
+       {
+               if(this.angles != this.mangle)
+               {
+                       this.mangle = this.angles;
+                       this.SendFlags |= SF_LASER_UPDATE_TARGET;
+               }
+       }
+       if(this.origin != this.oldorigin)
+       {
+               this.SendFlags |= SF_LASER_UPDATE_ORIGIN;
+               this.oldorigin = this.origin;
+       }
+}
+
+void misc_laser_init(entity this)
+{
+       if(this.target != "")
+               this.enemy = find(NULL, targetname, this.target);
+}
+
+.entity pusher;
+void misc_laser_think(entity this)
+{
+       vector o;
+       entity hitent;
+       vector hitloc;
+
+       this.nextthink = time;
+
+       if(this.active == ACTIVE_NOT)
+               return;
+
+       misc_laser_aim(this);
+
+       if(this.enemy)
+       {
+               o = this.enemy.origin;
+               if (!(this.spawnflags & LASER_FINITE))
+                       o = this.origin + normalize(o - this.origin) * LASER_BEAM_MAXLENGTH;
+       }
+       else
+       {
+               makevectors(this.mangle);
+               o = this.origin + v_forward * LASER_BEAM_MAXLENGTH;
+       }
+
+       if(this.dmg || this.enemy.target != "")
+       {
+               traceline(this.origin, o, MOVE_NORMAL, this);
+       }
+       hitent = trace_ent;
+       hitloc = trace_endpos;
+
+       if(this.enemy.target != "") // DETECTOR laser
+       {
+               if(trace_ent.iscreature)
+               {
+                       this.pusher = hitent;
+                       if(!this.count)
+                       {
+                               this.count = 1;
+
+                               SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
+                       }
+               }
+               else
+               {
+                       if(this.count)
+                       {
+                               this.count = 0;
+
+                               SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
+                       }
+               }
+       }
+
+       if(this.dmg)
+       {
+               if(this.team)
+                       if(((this.spawnflags & LASER_INVERT_TEAM) == 0) == (this.team != hitent.team))
+                               return;
+               if(hitent.takedamage)
+                       Damage(hitent, this, this, ((this.dmg < 0) ? 100000 : (this.dmg * frametime)), DEATH_HURTTRIGGER.m_id, DMG_NOWEP, hitloc, '0 0 0');
+       }
+}
+
+bool laser_SendEntity(entity this, entity to, float sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
+       sendflags = sendflags & 0x0F; // use that bit to indicate finite length laser
+       if(this.spawnflags & LASER_FINITE)
+               sendflags |= SF_LASER_FINITE;
+       if(this.alpha)
+               sendflags |= SF_LASER_ALPHA;
+       if(this.scale != 1 || this.modelscale != 1)
+               sendflags |= SF_LASER_SCALE;
+       if(this.spawnflags & LASER_NOTRACE)
+               sendflags |= SF_LASER_NOTRACE;
+       WriteByte(MSG_ENTITY, sendflags);
+       if(sendflags & SF_LASER_UPDATE_ORIGIN)
+       {
+               WriteVector(MSG_ENTITY, this.origin);
+       }
+       if(sendflags & SF_LASER_UPDATE_EFFECT)
+       {
+               WriteByte(MSG_ENTITY, this.beam_color.x * 255.0);
+               WriteByte(MSG_ENTITY, this.beam_color.y * 255.0);
+               WriteByte(MSG_ENTITY, this.beam_color.z * 255.0);
+               if(sendflags & SF_LASER_ALPHA)
+                       WriteByte(MSG_ENTITY, this.alpha * 255.0);
+               if(sendflags & SF_LASER_SCALE)
+               {
+                       WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
+                       WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
+               }
+               if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
+                       WriteShort(MSG_ENTITY, this.cnt);
+       }
+       if(sendflags & SF_LASER_UPDATE_TARGET)
+       {
+               if(sendflags & SF_LASER_FINITE)
+               {
+                       WriteVector(MSG_ENTITY, this.enemy.origin);
+               }
+               else
+               {
+                       WriteAngle(MSG_ENTITY, this.mangle_x);
+                       WriteAngle(MSG_ENTITY, this.mangle_y);
+               }
+       }
+       if(sendflags & SF_LASER_UPDATE_ACTIVE)
+               WriteByte(MSG_ENTITY, this.active);
+       return true;
+}
+
+/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
+Any object touching the beam will be hurt
+Keys:
+"target"
+ spawnfunc_target_position where the laser ends
+"mdl"
+ name of beam end effect to use
+"beam_color"
+ color of the beam (default: red)
+"dmg"
+ damage per second (-1 for a laser that kills immediately)
+*/
+
+void laser_setactive(entity this, int act)
+{
+       int old_status = this.active;
+       if(act == ACTIVE_TOGGLE)
+       {
+               if(this.active == ACTIVE_ACTIVE)
+               {
+                       this.active = ACTIVE_NOT;
+               }
+               else
+               {
+                       this.active = ACTIVE_ACTIVE;
+               }
+       }
+       else
+       {
+               this.active = act;
+       }
+
+       if (this.active != old_status)
+       {
+               this.SendFlags |= SF_LASER_UPDATE_ACTIVE;
+               misc_laser_aim(this);
+       }
+}
+
+void laser_use(entity this, entity actor, entity trigger)
+{
+       this.setactive(this, ACTIVE_TOGGLE);
+}
+
+spawnfunc(misc_laser)
+{
+       if(this.mdl)
+       {
+               if(this.mdl == "none")
+                       this.cnt = -1;
+               else
+               {
+                       this.cnt = _particleeffectnum(this.mdl);
+                       if(this.cnt < 0 && this.dmg)
+                this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
+               }
+       }
+       else if(!this.cnt)
+       {
+               if(this.dmg)
+                       this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
+               else
+                       this.cnt = -1;
+       }
+       if(this.cnt < 0)
+               this.cnt = -1;
+
+       if(!this.beam_color && this.colormod)
+       {
+               LOG_WARN("misc_laser uses legacy field 'colormod', please use 'beam_color' instead");
+               this.beam_color = this.colormod;
+       }
+
+       if(this.beam_color == '0 0 0')
+       {
+               if(!this.alpha)
+                       this.beam_color = '1 0 0';
+       }
+
+       if(this.message == "")
+       {
+               this.message = "saw the light";
+       }
+       if (this.message2 == "")
+       {
+               this.message2 = "was pushed into a laser by";
+       }
+       if(!this.scale)
+       {
+               this.scale = 1;
+       }
+       if(!this.modelscale)
+       {
+               this.modelscale = 1;
+       }
+       else if(this.modelscale < 0)
+       {
+               this.modelscale = 0;
+       }
+       setthink(this, misc_laser_think);
+       this.nextthink = time;
+       InitializeEntity(this, misc_laser_init, INITPRIO_FINDTARGET);
+
+       this.mangle = this.angles;
+
+       Net_LinkEntity(this, false, 0, laser_SendEntity);
+
+       this.setactive = laser_setactive;
+
+       IFTARGETED
+       {
+               // backwards compatibility
+               this.use = laser_use;
+       }
+
+       this.reset = generic_netlinked_reset;
+       this.reset(this);
+}
+#elif defined(CSQC)
+
+// a laser goes from origin in direction angles
+// it has color 'beam_color'
+// and stops when something is in the way
+entityclass(Laser);
+classfield(Laser) .int cnt; // end effect
+classfield(Laser) .vector colormod;
+classfield(Laser) .int state; // on-off
+classfield(Laser) .int count; // flags for the laser
+classfield(Laser) .vector velocity; // laser endpoint if it is FINITE
+classfield(Laser) .float alpha;
+classfield(Laser) .float scale; // scaling factor of the thickness
+classfield(Laser) .float modelscale; // scaling factor of the dlight
+
+void Draw_Laser(entity this)
+{
+       if(this.active == ACTIVE_NOT)
+               return;
+       InterpolateOrigin_Do(this);
+       if(this.count & SF_LASER_FINITE)
+       {
+               if(this.count & SF_LASER_NOTRACE)
+               {
+                       trace_endpos = this.velocity;
+                       trace_dphitq3surfaceflags = 0;
+               }
+               else
+                       traceline(this.origin, this.velocity, 0, this);
+       }
+       else
+       {
+               if(this.count & SF_LASER_NOTRACE)
+               {
+                       makevectors(this.angles);
+                       trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
+                       trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
+               }
+               else
+               {
+                       makevectors(this.angles);
+                       traceline(this.origin, this.origin + v_forward * LASER_BEAM_MAXLENGTH, 0, this);
+                       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
+                               trace_endpos = this.origin + v_forward * LASER_BEAM_MAXWORLDSIZE;
+               }
+       }
+       if(this.scale != 0)
+       {
+               if(this.alpha)
+               {
+                       Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, this.alpha, DRAWFLAG_NORMAL, view_origin);
+               }
+               else
+               {
+                       Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.beam_color, 0.5, DRAWFLAG_ADDITIVE, view_origin);
+               }
+       }
+       if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
+       {
+               if(this.cnt >= 0)
+                       __pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
+               if(this.beam_color != '0 0 0' && this.modelscale != 0)
+                       adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.beam_color * 5);
+       }
+}
+
+NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
+{
+       InterpolateOrigin_Undo(this);
+
+       // 30 bytes, or 13 bytes for just moving
+       int sendflags = ReadByte();
+       this.count = (sendflags & 0xF0);
+
+       if(this.count & SF_LASER_FINITE)
+               this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
+       else
+               this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
+
+       if(sendflags & SF_LASER_UPDATE_ORIGIN)
+       {
+               this.origin = ReadVector();
+               setorigin(this, this.origin);
+       }
+       if(sendflags & SF_LASER_UPDATE_EFFECT)
+       {
+               this.beam_color.x = ReadByte() / 255.0;
+               this.beam_color.y = ReadByte() / 255.0;
+               this.beam_color.z = ReadByte() / 255.0;
+               if(sendflags & SF_LASER_ALPHA)
+                       this.alpha = ReadByte() / 255.0;
+               else
+                       this.alpha = 0;
+               this.scale = 2; // NOTE: why 2?
+               this.modelscale = 50; // NOTE: why 50?
+               if(sendflags & SF_LASER_SCALE)
+               {
+                       this.scale *= ReadByte() / 16.0; // beam radius
+                       this.modelscale *= ReadByte() / 16.0; // dlight radius
+               }
+               if((sendflags & SF_LASER_FINITE) || !(sendflags & SF_LASER_NOTRACE))
+                       this.cnt = ReadShort(); // effect number
+               else
+                       this.cnt = 0;
+       }
+       if(sendflags & SF_LASER_UPDATE_TARGET)
+       {
+               if(sendflags & SF_LASER_FINITE)
+               {
+                       this.velocity = ReadVector();
+               }
+               else
+               {
+                       this.angles_x = ReadAngle();
+                       this.angles_y = ReadAngle();
+               }
+       }
+       if(sendflags & SF_LASER_UPDATE_ACTIVE)
+               this.active = ReadByte();
+
+       return = true;
+
+       InterpolateOrigin_Note(this);
+       this.draw = Draw_Laser;
+       if (isnew) IL_PUSH(g_drawables, this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/misc/laser.qh b/qcsrc/common/mapobjects/misc/laser.qh
new file mode 100644 (file)
index 0000000..0ff5764
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+
+const int LASER_FINITE = BIT(1);
+const int LASER_NOTRACE = BIT(2);
+const int LASER_INVERT_TEAM = BIT(3);
+
+const int SF_LASER_UPDATE_ORIGIN = BIT(0);
+const int SF_LASER_UPDATE_TARGET = BIT(1);
+const int SF_LASER_UPDATE_ACTIVE = BIT(2);
+const int SF_LASER_UPDATE_EFFECT = BIT(3);
+
+const int SF_LASER_NOTRACE = BIT(4);
+const int SF_LASER_SCALE = BIT(5);
+const int SF_LASER_ALPHA = BIT(6);
+const int SF_LASER_FINITE = BIT(7);
+
+.vector beam_color;
+
+const float LASER_BEAM_MAXLENGTH = 32768; // maximum length of a beam trace
+// TODO: find a better way to do this
+const float LASER_BEAM_MAXWORLDSIZE = 1048576; // to make sure the endpoint of the beam is not visible inside
diff --git a/qcsrc/common/mapobjects/misc/teleport_dest.qc b/qcsrc/common/mapobjects/misc/teleport_dest.qc
new file mode 100644 (file)
index 0000000..126a20e
--- /dev/null
@@ -0,0 +1,89 @@
+#include "teleport_dest.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_TELEPORT_DEST)
+
+#ifdef SVQC
+
+bool teleport_dest_send(entity this, entity to, int sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TELEPORT_DEST);
+       WriteByte(MSG_ENTITY, sendflags);
+
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               WriteByte(MSG_ENTITY, this.cnt);
+               WriteCoord(MSG_ENTITY, this.speed);
+               WriteString(MSG_ENTITY, this.targetname);
+               WriteVector(MSG_ENTITY, this.origin);
+
+               WriteAngle(MSG_ENTITY, this.mangle_x);
+               WriteAngle(MSG_ENTITY, this.mangle_y);
+               WriteAngle(MSG_ENTITY, this.mangle_z);
+       }
+
+       return true;
+}
+
+void teleport_dest_link(entity this)
+{
+       Net_LinkEntity(this, false, 0, teleport_dest_send);
+       this.SendFlags |= SF_TRIGGER_INIT;
+}
+
+spawnfunc(info_teleport_destination)
+{
+       this.classname = "info_teleport_destination";
+
+       this.mangle = this.angles;
+       this.angles = '0 0 0';
+
+       //setorigin(this, this.origin + '0 0 27');      // To fix a mappers' habit as old as Quake
+       setorigin(this, this.origin);
+
+       IFTARGETED
+       {
+       }
+       else
+               objerror (this, "^3Teleport destination without a targetname");
+
+       teleport_dest_link(this);
+}
+
+spawnfunc(misc_teleporter_dest)
+{
+       spawnfunc_info_teleport_destination(this);
+}
+
+#elif defined(CSQC)
+
+void teleport_dest_remove(entity this)
+{
+    // strfree(this.classname);
+    strfree(this.targetname);
+}
+
+NET_HANDLE(ENT_CLIENT_TELEPORT_DEST, bool isnew)
+{
+       int sendflags = ReadByte();
+
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               this.classname = "info_teleport_destination";
+               this.cnt = ReadByte();
+               this.speed = ReadCoord();
+               this.targetname = strzone(ReadString());
+               this.origin = ReadVector();
+
+               this.mangle_x = ReadAngle();
+               this.mangle_y = ReadAngle();
+               this.mangle_z = ReadAngle();
+
+               setorigin(this, this.origin);
+
+               this.drawmask = MASK_NORMAL;
+               this.entremove = teleport_dest_remove;
+       }
+
+       return = true;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/misc/teleport_dest.qh b/qcsrc/common/mapobjects/misc/teleport_dest.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/models.qc b/qcsrc/common/mapobjects/models.qc
new file mode 100644 (file)
index 0000000..92ff464
--- /dev/null
@@ -0,0 +1,413 @@
+#include "models.qh"
+
+#ifdef SVQC
+#include <server/defs.qh>
+#include <server/miscfunctions.qh>
+#include <common/net_linked.qh>
+#include "subs.qh"
+#include "triggers.qh"
+
+entityclass(BGMScript);
+classfield(BGMScript) .string bgmscript;
+classfield(BGMScript) .float bgmscriptattack;
+classfield(BGMScript) .float bgmscriptdecay;
+classfield(BGMScript) .float bgmscriptsustain;
+classfield(BGMScript) .float bgmscriptrelease;
+
+#include <common/constants.qh>
+#include "../../lib/csqcmodel/sv_model.qh"
+
+.float modelscale;
+
+void g_model_setcolormaptoactivator(entity this, entity actor, entity trigger)
+{
+       if(teamplay)
+       {
+               if(actor.team)
+                       this.colormap = (actor.team - 1) * 0x11;
+               else
+                       this.colormap = 0x00;
+       }
+       else
+               this.colormap = floor(random() * 256);
+       this.colormap |= BIT(10); // RENDER_COLORMAPPED
+}
+
+void g_clientmodel_setcolormaptoactivator(entity this, entity actor, entity trigger)
+{
+       g_model_setcolormaptoactivator(this, actor, trigger);
+       this.SendFlags |= (BIT(3) | BIT(0));
+}
+
+void g_clientmodel_use(entity this, entity actor, entity trigger)
+{
+       if (this.antiwall_flag == 1)
+       {
+               this.inactive = 1;
+               this.solid = SOLID_NOT;
+       }
+       else if (this.antiwall_flag == 2)
+       {
+               this.inactive = 0;
+               this.solid = this.default_solid;
+       }
+       g_clientmodel_setcolormaptoactivator(this, actor, trigger);
+}
+
+void g_model_dropbyspawnflags(entity this)
+{
+       if((this.spawnflags & 3) == 1) // ALIGN_ORIGIN
+       {
+               traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
+               setorigin(this, trace_endpos);
+       }
+       else if((this.spawnflags & 3) == 2) // ALIGN_BOTTOM
+       {
+               tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
+               setorigin(this, trace_endpos);
+       }
+       else if((this.spawnflags & 3) == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
+       {
+               traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
+               setorigin(this, trace_endpos - '0 0 1' * this.mins.z);
+       }
+}
+
+void g_clientmodel_dropbyspawnflags(entity this)
+{
+       vector o0;
+       o0 = this.origin;
+       g_model_dropbyspawnflags(this);
+       if(this.origin != o0)
+               this.SendFlags |= 2;
+}
+
+bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
+{
+       sf = sf & 0x0F;
+       if(this.angles != '0 0 0')
+               sf |= 0x10;
+       if(this.mins != '0 0 0' || this.maxs != '0 0 0')
+               sf |= 0x20;
+       if(this.colormap != 0)
+               sf |= 0x40;
+       if(this.lodmodelindex1)
+               sf |= 0x80;
+
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
+       WriteByte(MSG_ENTITY, sf);
+
+       if(sf & BIT(0))
+       {
+               if(sf & 0x40)
+                       WriteShort(MSG_ENTITY, this.colormap);
+               WriteByte(MSG_ENTITY, this.skin);
+       }
+
+       if(sf & BIT(1))
+       {
+               WriteVector(MSG_ENTITY, this.origin);
+       }
+
+       if(sf & BIT(2))
+       {
+               if(sf & 0x10)
+               {
+                       WriteAngle(MSG_ENTITY, this.angles.x);
+                       WriteAngle(MSG_ENTITY, this.angles.y);
+                       WriteAngle(MSG_ENTITY, this.angles.z);
+               }
+       }
+
+       if(sf & BIT(3))
+       {
+               if(sf & 0x80)
+               {
+                       WriteShort(MSG_ENTITY, this.lodmodelindex0);
+                       WriteShort(MSG_ENTITY, bound(0, this.loddistance1, 65535));
+                       WriteShort(MSG_ENTITY, this.lodmodelindex1);
+                       WriteShort(MSG_ENTITY, bound(0, this.loddistance2, 65535));
+                       WriteShort(MSG_ENTITY, this.lodmodelindex2);
+               }
+               else
+                       WriteShort(MSG_ENTITY, this.modelindex);
+               WriteByte(MSG_ENTITY, this.solid);
+               WriteShort(MSG_ENTITY, floor(this.scale * 256));
+               if(sf & 0x20)
+               {
+                       WriteVector(MSG_ENTITY, this.mins);
+                       WriteVector(MSG_ENTITY, this.maxs);
+               }
+               WriteString(MSG_ENTITY, this.bgmscript);
+               if(this.bgmscript != "")
+               {
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
+                       WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
+                       WriteVector(MSG_ENTITY, this.movedir);
+                       WriteByte(MSG_ENTITY, floor(this.lip * 255));
+               }
+               WriteByte(MSG_ENTITY, this.fade_start);
+               WriteByte(MSG_ENTITY, this.fade_end);
+               WriteByte(MSG_ENTITY, this.alpha_max);
+               WriteByte(MSG_ENTITY, this.alpha_min);
+               WriteByte(MSG_ENTITY, this.inactive);
+               WriteShort(MSG_ENTITY, this.fade_vertical_offset);
+       }
+
+       return true;
+}
+
+
+#define G_MODEL_INIT(ent,sol) \
+       if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
+       if(!ent.scale) ent.scale = ent.modelscale; \
+       SetBrushEntityModel(ent); \
+       ent.use = g_model_setcolormaptoactivator; \
+       InitializeEntity(ent, g_model_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
+       if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT;
+
+#define G_CLIENTMODEL_INIT(ent,sol) \
+       if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
+       if(!ent.scale) ent.scale = ent.modelscale; \
+       SetBrushEntityModel(ent); \
+       ent.use = g_clientmodel_use; \
+       InitializeEntity(ent, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
+       if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT; \
+       if(!ent.bgmscriptsustain) ent.bgmscriptsustain = 1; else if(ent.bgmscriptsustain < 0) ent.bgmscriptsustain = 0; \
+       Net_LinkEntity(ent, true, 0, g_clientmodel_genericsendentity); \
+       ent.default_solid = sol;
+
+// non-solid model entities:
+spawnfunc(misc_gamemodel)         { this.angles_x = -this.angles.x; G_MODEL_INIT      (this, SOLID_NOT) } // model entity
+spawnfunc(misc_clientmodel)       { this.angles_x = -this.angles.x; G_CLIENTMODEL_INIT(this, SOLID_NOT) } // model entity
+spawnfunc(misc_models)            { this.angles_x = -this.angles.x; G_MODEL_INIT      (this, SOLID_NOT) } // DEPRECATED old compat entity with confusing name, do not use
+
+// non-solid brush entities:
+spawnfunc(func_illusionary)       { G_MODEL_INIT      (this, SOLID_NOT) } // Q1 name (WARNING: MISPREDICTED)
+spawnfunc(func_clientillusionary) { G_CLIENTMODEL_INIT(this, SOLID_NOT) } // brush entity
+spawnfunc(func_static)            { G_MODEL_INIT      (this, SOLID_NOT) } // DEPRECATED old alias name from some other game
+
+// solid brush entities
+spawnfunc(func_wall)              { G_MODEL_INIT      (this, SOLID_BSP) } // Q1 name
+spawnfunc(func_clientwall)        { G_CLIENTMODEL_INIT(this, SOLID_BSP) } // brush entity (WARNING: MISPREDICTED)
+#elif defined(CSQC)
+.float alpha;
+.float scale;
+.vector movedir;
+
+void Ent_Wall_PreDraw(entity this)
+{
+       if (this.inactive)
+       {
+               this.alpha = 0;
+       }
+       else
+       {
+               vector org = getpropertyvec(VF_ORIGIN);
+               if(!checkpvs(org, this))
+                       this.alpha = 0;
+               else if(this.fade_start || this.fade_end) {
+                       vector offset = '0 0 0';
+                       offset_z = this.fade_vertical_offset;
+                       float player_dist = vlen(org - this.origin - 0.5 * (this.mins + this.maxs) + offset);
+                       if (this.fade_end == this.fade_start)
+                       {
+                               if (player_dist >= this.fade_start)
+                                       this.alpha = 0;
+                               else
+                                       this.alpha = 1;
+                       }
+                       else
+                       {
+                               this.alpha = (this.alpha_min + this.alpha_max * bound(0,
+                                                          (this.fade_end - player_dist)
+                                                          / (this.fade_end - this.fade_start), 1)) / 100.0;
+                       }
+               }
+               else
+               {
+                       this.alpha = 1;
+               }
+       }
+       if(this.alpha <= 0)
+               this.drawmask = 0;
+       else
+               this.drawmask = MASK_NORMAL;
+}
+
+void Ent_Wall_Draw(entity this)
+{
+       float f;
+       var .vector fld;
+
+       if(this.bgmscriptangular)
+               fld = angles;
+       else
+               fld = origin;
+       this.(fld) = this.saved;
+
+       if(this.lodmodelindex1)
+       {
+               if(autocvar_cl_modeldetailreduction <= 0)
+               {
+                       if(this.lodmodelindex2 && autocvar_cl_modeldetailreduction <= -2)
+                               this.modelindex = this.lodmodelindex2;
+                       else if(autocvar_cl_modeldetailreduction <= -1)
+                               this.modelindex = this.lodmodelindex1;
+                       else
+                               this.modelindex = this.lodmodelindex0;
+               }
+               else
+               {
+                       float distance = vlen(NearestPointOnBox(this, view_origin) - view_origin);
+                       f = (distance * current_viewzoom + 100.0) * autocvar_cl_modeldetailreduction;
+                       f *= 1.0 / bound(0.01, view_quality, 1);
+                       if(this.lodmodelindex2 && f > this.loddistance2)
+                               this.modelindex = this.lodmodelindex2;
+                       else if(f > this.loddistance1)
+                               this.modelindex = this.lodmodelindex1;
+                       else
+                               this.modelindex = this.lodmodelindex0;
+               }
+       }
+
+       InterpolateOrigin_Do(this);
+
+       this.saved = this.(fld);
+
+       f = doBGMScript(this);
+       if(f >= 0)
+       {
+               if(this.lip < 0) // < 0: alpha goes from 1 to 1-|lip| when toggled (toggling subtracts lip)
+                       this.alpha = 1 + this.lip * f;
+               else // > 0: alpha goes from 1-|lip| to 1 when toggled (toggling adds lip)
+                       this.alpha = 1 - this.lip * (1 - f);
+               this.(fld) = this.(fld) + this.movedir * f;
+       }
+       else
+               this.alpha = 1;
+
+       if(this.alpha >= ALPHA_MIN_VISIBLE)
+               this.drawmask = MASK_NORMAL;
+       else
+               this.drawmask = 0;
+}
+
+void Ent_Wall_Remove(entity this)
+{
+       strfree(this.bgmscript);
+}
+
+NET_HANDLE(ENT_CLIENT_WALL, bool isnew)
+{
+       int f;
+       var .vector fld;
+
+       InterpolateOrigin_Undo(this);
+       this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
+
+       if(this.bgmscriptangular)
+               fld = angles;
+       else
+               fld = origin;
+       this.(fld) = this.saved;
+
+       f = ReadByte();
+
+       if(f & 1)
+       {
+               if(f & 0x40)
+                       this.colormap = ReadShort();
+               else
+                       this.colormap = 0;
+               this.skin = ReadByte();
+       }
+
+       if(f & 2)
+       {
+               this.origin = ReadVector();
+               setorigin(this, this.origin);
+       }
+
+       if(f & 4)
+       {
+               if(f & 0x10)
+               {
+                       this.angles_x = ReadAngle();
+                       this.angles_y = ReadAngle();
+                       this.angles_z = ReadAngle();
+               }
+               else
+                       this.angles = '0 0 0';
+       }
+
+       if(f & 8)
+       {
+               if(f & 0x80)
+               {
+                       this.lodmodelindex0 = ReadShort();
+                       this.loddistance1 = ReadShort();
+                       this.lodmodelindex1 = ReadShort();
+                       this.loddistance2 = ReadShort();
+                       this.lodmodelindex2 = ReadShort();
+               }
+               else
+               {
+                       this.modelindex = ReadShort();
+                       this.loddistance1 = 0;
+                       this.loddistance2 = 0;
+               }
+               this.solid = ReadByte();
+               this.scale = ReadShort() / 256.0;
+               if(f & 0x20)
+               {
+                       this.mins = ReadVector();
+                       this.maxs = ReadVector();
+               }
+               else
+                       this.mins = this.maxs = '0 0 0';
+               setsize(this, this.mins, this.maxs);
+
+               string s = ReadString();
+               if(substring(s, 0, 1) == "<")
+               {
+                       strcpy(this.bgmscript, substring(s, 1, -1));
+                       this.bgmscriptangular = 1;
+               }
+               else
+               {
+                       strcpy(this.bgmscript, s);
+                       this.bgmscriptangular = 0;
+               }
+               if(this.bgmscript != "")
+               {
+                       this.bgmscriptattack = ReadByte() / 64.0;
+                       this.bgmscriptdecay = ReadByte() / 64.0;
+                       this.bgmscriptsustain = ReadByte() / 255.0;
+                       this.bgmscriptrelease = ReadByte() / 64.0;
+                       this.movedir = ReadVector();
+                       this.lip = ReadByte() / 255.0;
+               }
+               this.fade_start = ReadByte();
+               this.fade_end = ReadByte();
+               this.alpha_max = ReadByte();
+               this.alpha_min = ReadByte();
+               this.inactive = ReadByte();
+               this.fade_vertical_offset = ReadShort();
+               BGMScript_InitEntity(this);
+       }
+
+       return = true;
+
+       InterpolateOrigin_Note(this);
+
+       this.saved = this.(fld);
+
+       this.entremove = Ent_Wall_Remove;
+       this.draw = Ent_Wall_Draw;
+       if (isnew) IL_PUSH(g_drawables, this);
+       setpredraw(this, Ent_Wall_PreDraw);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/models.qh b/qcsrc/common/mapobjects/models.qh
new file mode 100644 (file)
index 0000000..50170e2
--- /dev/null
@@ -0,0 +1,22 @@
+#pragma once
+
+#ifdef CSQC
+entityclass(Wall);
+classfield(Wall) .float lip;
+classfield(Wall) .float bgmscriptangular;
+classfield(Wall) .int lodmodelindex0, lodmodelindex1, lodmodelindex2;
+classfield(Wall) .float loddistance1, loddistance2;
+classfield(Wall) .vector saved;
+
+// Needed for interactive clientwalls
+.float inactive; // Clientwall disappears when inactive
+.float alpha_max, alpha_min;
+// If fade_start > fade_end, fadeout will be inverted
+// fade_vertical_offset is a vertival offset for player position
+.float fade_start, fade_end, fade_vertical_offset;
+.float default_solid;
+
+void Ent_Wall_Draw(entity this);
+
+void Ent_Wall_Remove(entity this);
+#endif
diff --git a/qcsrc/common/mapobjects/platforms.qc b/qcsrc/common/mapobjects/platforms.qc
new file mode 100644 (file)
index 0000000..4747877
--- /dev/null
@@ -0,0 +1,227 @@
+#include "platforms.qh"
+void generic_plat_blocked(entity this, entity blocker)
+{
+#ifdef SVQC
+       if(this.dmg && blocker.takedamage != DAMAGE_NO)
+       {
+               if(this.dmgtime2 < time)
+               {
+                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+                       this.dmgtime2 = time + this.dmgtime;
+               }
+
+               // Gib dead/dying stuff
+               if(IS_DEAD(blocker))
+                       Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+       }
+#endif
+}
+
+void plat_spawn_inside_trigger(entity this)
+{
+       entity trigger;
+       vector tmin, tmax;
+
+       trigger = spawn();
+       settouch(trigger, plat_center_touch);
+       set_movetype(trigger, MOVETYPE_NONE);
+       trigger.solid = SOLID_TRIGGER;
+       trigger.enemy = this;
+
+       tmin = this.absmin + '25 25 0';
+       tmax = this.absmax - '25 25 -8';
+       tmin_z = tmax_z - (this.pos1_z - this.pos2_z + 8);
+       if (this.spawnflags & PLAT_LOW_TRIGGER)
+               tmax_z = tmin_z + 8;
+
+       if (this.size_x <= 50)
+       {
+               tmin_x = (this.mins_x + this.maxs_x) / 2;
+               tmax_x = tmin_x + 1;
+       }
+       if (this.size_y <= 50)
+       {
+               tmin_y = (this.mins_y + this.maxs_y) / 2;
+               tmax_y = tmin_y + 1;
+       }
+
+       if(tmin_x < tmax_x)
+               if(tmin_y < tmax_y)
+                       if(tmin_z < tmax_z)
+                       {
+                               setsize (trigger, tmin, tmax);
+                               return;
+                       }
+
+       // otherwise, something is fishy...
+       delete(trigger);
+       objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
+}
+
+void plat_hit_top(entity this)
+{
+       _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_TOP;
+
+       setthink(this, plat_go_down);
+       this.nextthink = this.ltime + 3;
+}
+
+void plat_hit_bottom(entity this)
+{
+       _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_BOTTOM;
+}
+
+void plat_go_down(entity this)
+{
+       _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_DOWN;
+       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, plat_hit_bottom);
+}
+
+void plat_go_up(entity this)
+{
+       _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
+       this.state = STATE_UP;
+       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, plat_hit_top);
+}
+
+void plat_center_touch(entity this, entity toucher)
+{
+#ifdef SVQC
+       if (!toucher.iscreature)
+               return;
+
+       if (toucher.health <= 0)
+               return;
+#elif defined(CSQC)
+       if (!IS_PLAYER(toucher))
+               return;
+       if(IS_DEAD(toucher))
+               return;
+#endif
+
+       if (this.enemy.state == STATE_BOTTOM) {
+               plat_go_up(this.enemy);
+       } else if (this.enemy.state == STATE_TOP)
+               this.enemy.nextthink = this.enemy.ltime + 1;
+}
+
+void plat_outside_touch(entity this, entity toucher)
+{
+#ifdef SVQC
+       if (!toucher.iscreature)
+               return;
+
+       if (toucher.health <= 0)
+               return;
+#elif defined(CSQC)
+       if (!IS_PLAYER(toucher))
+               return;
+#endif
+
+       if (this.enemy.state == STATE_TOP) {
+           entity e = this.enemy;
+               plat_go_down(e);
+    }
+}
+
+void plat_trigger_use(entity this, entity actor, entity trigger)
+{
+       if (getthink(this))
+               return;         // already activated
+       plat_go_down(this);
+}
+
+
+void plat_crush(entity this, entity blocker)
+{
+       if((this.spawnflags & CRUSH) && (blocker.takedamage != DAMAGE_NO))
+       { // KIll Kill Kill!!
+#ifdef SVQC
+               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+       }
+       else
+       {
+#ifdef SVQC
+               if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
+               {   // Shall we bite?
+                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+                       // Gib dead/dying stuff
+                       if(IS_DEAD(blocker))
+                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+               }
+#endif
+
+               if (this.state == STATE_UP)
+                       plat_go_down (this);
+               else if (this.state == STATE_DOWN)
+                       plat_go_up (this);
+       // when in other states, then the plat_crush event came delayed after
+       // plat state already had changed
+       // this isn't a bug per se!
+       }
+}
+
+void plat_use(entity this, entity actor, entity trigger)
+{
+       this.use = func_null;
+       if (this.state != STATE_UP)
+               objerror (this, "plat_use: not in up state");
+       plat_go_down(this);
+}
+
+// WARNING: backwards compatibility because people don't use already existing fields :(
+// TODO: Check if any maps use these fields and remove these fields if it doesn't break maps
+.string sound1, sound2;
+
+void plat_reset(entity this)
+{
+       IFTARGETED
+       {
+               setorigin(this, this.pos1);
+               this.state = STATE_UP;
+               this.use = plat_use;
+       }
+       else
+       {
+               setorigin(this, this.pos2);
+               this.state = STATE_BOTTOM;
+               this.use = plat_trigger_use;
+       }
+
+#ifdef SVQC
+       this.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+.float platmovetype_start_default, platmovetype_end_default;
+bool set_platmovetype(entity e, string s)
+{
+       // sets platmovetype_start and platmovetype_end based on a string consisting of two values
+
+       int n = tokenize_console(s);
+       if(n > 0)
+               e.platmovetype_start = stof(argv(0));
+       else
+               e.platmovetype_start = 0;
+
+       if(n > 1)
+               e.platmovetype_end = stof(argv(1));
+       else
+               e.platmovetype_end = e.platmovetype_start;
+
+       if(n > 2)
+               if(argv(2) == "force")
+                       return true; // no checking, return immediately
+
+       if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
+       {
+               objerror(e, "Invalid platform move type; platform would go in reverse, which is not allowed.");
+               return false;
+       }
+
+       return true;
+}
diff --git a/qcsrc/common/mapobjects/platforms.qh b/qcsrc/common/mapobjects/platforms.qh
new file mode 100644 (file)
index 0000000..346cebc
--- /dev/null
@@ -0,0 +1,15 @@
+#pragma once
+
+
+const int PLAT_LOW_TRIGGER = BIT(0);
+
+.float dmgtime2;
+
+void plat_center_touch(entity this, entity toucher);
+void plat_outside_touch(entity this, entity toucher);
+void plat_trigger_use(entity this, entity actor, entity trigger);
+void plat_go_up(entity this);
+void plat_go_down(entity this);
+void plat_crush(entity this, entity blocker);
+
+.float dmg;
diff --git a/qcsrc/common/mapobjects/subs.qc b/qcsrc/common/mapobjects/subs.qc
new file mode 100644 (file)
index 0000000..4877d0f
--- /dev/null
@@ -0,0 +1,588 @@
+#include "subs.qh"
+void SUB_NullThink(entity this) { }
+
+void SUB_CalcMoveDone(entity this);
+void SUB_CalcAngleMoveDone(entity this);
+
+#ifdef SVQC
+spawnfunc(info_null)
+{
+       delete(this);
+       // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
+}
+#endif
+
+/*
+==================
+SUB_Friction
+
+Applies some friction to this
+==================
+*/
+.float friction;
+void SUB_Friction (entity this)
+{
+       this.nextthink = time;
+       if(IS_ONGROUND(this))
+               this.velocity = this.velocity * (1 - frametime * this.friction);
+}
+
+/*
+==================
+SUB_VanishOrRemove
+
+Makes client invisible or removes non-client
+==================
+*/
+void SUB_VanishOrRemove (entity ent)
+{
+       if (IS_CLIENT(ent))
+       {
+               // vanish
+               ent.alpha = -1;
+               ent.effects = 0;
+#ifdef SVQC
+               ent.glow_size = 0;
+               ent.pflags = 0;
+#endif
+       }
+       else
+       {
+               // remove
+               delete(ent);
+       }
+}
+
+void SUB_SetFade_Think (entity this)
+{
+       if(this.alpha == 0)
+               this.alpha = 1;
+       setthink(this, SUB_SetFade_Think);
+       this.nextthink = time;
+       this.alpha -= frametime * this.fade_rate;
+       if (this.alpha < 0.01)
+               SUB_VanishOrRemove(this);
+       else
+               this.nextthink = time;
+}
+
+/*
+==================
+SUB_SetFade
+
+Fade 'ent' out when time >= 'when'
+==================
+*/
+void SUB_SetFade (entity ent, float when, float fading_time)
+{
+       ent.fade_rate = 1/fading_time;
+       setthink(ent, SUB_SetFade_Think);
+       ent.nextthink = when;
+}
+
+/*
+=============
+SUB_CalcMove
+
+calculate this.velocity and this.nextthink to reach dest from
+this.origin traveling at speed
+===============
+*/
+void SUB_CalcMoveDone(entity this)
+{
+       // After moving, set origin to exact final destination
+
+       setorigin (this, this.finaldest);
+       this.velocity = '0 0 0';
+       this.nextthink = -1;
+       if (this.think1 && this.think1 != SUB_CalcMoveDone)
+               this.think1 (this);
+}
+
+.float platmovetype_turn;
+void SUB_CalcMove_controller_think (entity this)
+{
+       float traveltime;
+       float phasepos;
+       float nexttick;
+       vector delta;
+       vector delta2;
+       vector veloc;
+       vector angloc;
+       vector nextpos;
+       delta = this.destvec;
+       delta2 = this.destvec2;
+       if(time < this.animstate_endtime)
+       {
+               nexttick = time + PHYS_INPUT_FRAMETIME;
+
+               traveltime = this.animstate_endtime - this.animstate_starttime;
+               phasepos = (nexttick - this.animstate_starttime) / traveltime; // range: [0, 1]
+               phasepos = cubic_speedfunc(this.platmovetype_start, this.platmovetype_end, phasepos);
+               nextpos = this.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
+               // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
+
+               if(this.owner.platmovetype_turn)
+               {
+                       vector destangle;
+                       destangle = delta + 2 * delta2 * phasepos;
+                       destangle = vectoangles(destangle);
+                       destangle_x = -destangle_x; // flip up / down orientation
+
+                       // take the shortest distance for the angles
+                       vector v = this.owner.angles;
+                       v.x -= 360 * floor((v.x - destangle_x) / 360 + 0.5);
+                       v.y -= 360 * floor((v.y - destangle_y) / 360 + 0.5);
+                       v.z -= 360 * floor((v.z - destangle_z) / 360 + 0.5);
+                       this.owner.angles = v;
+                       angloc = destangle - this.owner.angles;
+                       angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
+                       this.owner.avelocity = angloc;
+               }
+               if(nexttick < this.animstate_endtime)
+                       veloc = nextpos - this.owner.origin;
+               else
+                       veloc = this.finaldest - this.owner.origin;
+               veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
+
+               this.owner.velocity = veloc;
+               this.nextthink = nexttick;
+       }
+       else
+       {
+               // derivative: delta + 2 * delta2 (e.g. for angle positioning)
+               entity own = this.owner;
+               setthink(own, this.think1);
+               // set the owner's reference to this entity to NULL
+               own.move_controller = NULL;
+               delete(this);
+               getthink(own)(own);
+       }
+}
+
+void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
+       // 2 * control * t - 2 * control * t * t + destin * t * t
+       // 2 * control * t + (destin - 2 * control) * t * t
+
+       setorigin(controller, org);
+       control -= org;
+       destin -= org;
+
+       controller.destvec = 2 * control; // control point
+       controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
+       // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
+}
+
+void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
+{
+       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
+       // 2 * control * t - 2 * control * t * t + destin * t * t
+       // 2 * control * t + (destin - 2 * control) * t * t
+
+       setorigin(controller, org);
+       destin -= org;
+
+       controller.destvec = destin; // end point
+       controller.destvec2 = '0 0 0';
+}
+
+void SUB_CalcMove_Bezier (entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
+{
+       float   traveltime;
+       entity controller;
+
+       if (!tspeed)
+               objerror (this, "No speed is defined!");
+
+       this.think1 = func;
+       this.finaldest = tdest;
+       setthink(this, SUB_CalcMoveDone);
+
+       switch(tspeedtype)
+       {
+               default:
+               case TSPEED_START:
+                       traveltime = 2 * vlen(tcontrol - this.origin) / tspeed;
+                       break;
+               case TSPEED_END:
+                       traveltime = 2 * vlen(tcontrol - tdest)       / tspeed;
+                       break;
+               case TSPEED_LINEAR:
+                       traveltime = vlen(tdest - this.origin)        / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
+       }
+
+       if (traveltime < 0.1) // useless anim
+       {
+               this.velocity = '0 0 0';
+               this.nextthink = this.ltime + 0.1;
+               return;
+       }
+
+       // delete the previous controller, otherwise changing movement midway is glitchy
+       if (this.move_controller != NULL)
+       {
+               delete(this.move_controller);
+       }
+       controller = new(SUB_CalcMove_controller);
+       controller.owner = this;
+       this.move_controller = controller;
+       controller.platmovetype = this.platmovetype;
+       controller.platmovetype_start = this.platmovetype_start;
+       controller.platmovetype_end = this.platmovetype_end;
+       SUB_CalcMove_controller_setbezier(controller, this.origin, tcontrol, tdest);
+       controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
+       controller.animstate_starttime = time;
+       controller.animstate_endtime = time + traveltime;
+       setthink(controller, SUB_CalcMove_controller_think);
+       controller.think1 = getthink(this);
+
+       // the thinking is now done by the controller
+       setthink(this, SUB_NullThink); // for PushMove
+       this.nextthink = this.ltime + traveltime;
+
+       // invoke controller
+       getthink(controller)(controller);
+}
+
+void SUB_CalcMove (entity this, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
+{
+       vector  delta;
+       float   traveltime;
+
+       if (!tspeed)
+               objerror (this, "No speed is defined!");
+
+       this.think1 = func;
+       this.finaldest = tdest;
+       setthink(this, SUB_CalcMoveDone);
+
+       if (tdest == this.origin)
+       {
+               this.velocity = '0 0 0';
+               this.nextthink = this.ltime + 0.1;
+               return;
+       }
+
+       delta = tdest - this.origin;
+
+       switch(tspeedtype)
+       {
+               default:
+               case TSPEED_START:
+               case TSPEED_END:
+               case TSPEED_LINEAR:
+                       traveltime = vlen (delta) / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
+       }
+
+       // Very short animations don't really show off the effect
+       // of controlled animation, so let's just use linear movement.
+       // Alternatively entities can choose to specify non-controlled movement.
+        // The only currently implemented alternative movement is linear (value 1)
+       if (traveltime < 0.15 || (this.platmovetype_start == 1 && this.platmovetype_end == 1)) // is this correct?
+       {
+               this.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
+               this.nextthink = this.ltime + traveltime;
+               return;
+       }
+
+       // now just run like a bezier curve...
+       SUB_CalcMove_Bezier(this, (this.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
+}
+
+void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
+{
+       SUB_CalcMove(ent, tdest, tspeedtype, tspeed, func);
+}
+
+/*
+=============
+SUB_CalcAngleMove
+
+calculate this.avelocity and this.nextthink to reach destangle from
+this.angles rotating
+
+The calling function should make sure this.setthink is valid
+===============
+*/
+void SUB_CalcAngleMoveDone(entity this)
+{
+       // After rotating, set angle to exact final angle
+       this.angles = this.finalangle;
+       this.avelocity = '0 0 0';
+       this.nextthink = -1;
+       if (this.think1 && this.think1 != SUB_CalcAngleMoveDone) // avoid endless loops
+               this.think1 (this);
+}
+
+// FIXME: I fixed this function only for rotation around the main axes
+void SUB_CalcAngleMove (entity this, vector destangle, float tspeedtype, float tspeed, void(entity this) func)
+{
+       if (!tspeed)
+               objerror (this, "No speed is defined!");
+
+       // take the shortest distance for the angles
+       this.angles_x -= 360 * floor((this.angles_x - destangle_x) / 360 + 0.5);
+       this.angles_y -= 360 * floor((this.angles_y - destangle_y) / 360 + 0.5);
+       this.angles_z -= 360 * floor((this.angles_z - destangle_z) / 360 + 0.5);
+       vector delta = destangle - this.angles;
+       float traveltime;
+
+       switch(tspeedtype)
+       {
+               default:
+               case TSPEED_START:
+               case TSPEED_END:
+               case TSPEED_LINEAR:
+                       traveltime = vlen (delta) / tspeed;
+                       break;
+               case TSPEED_TIME:
+                       traveltime = tspeed;
+                       break;
+       }
+
+       this.think1 = func;
+       this.finalangle = destangle;
+       setthink(this, SUB_CalcAngleMoveDone);
+
+       if (traveltime < 0.1)
+       {
+               this.avelocity = '0 0 0';
+               this.nextthink = this.ltime + 0.1;
+               return;
+       }
+
+       this.avelocity = delta * (1 / traveltime);
+       this.nextthink = this.ltime + traveltime;
+}
+
+void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void(entity this) func)
+{
+       SUB_CalcAngleMove (ent, destangle, tspeedtype, tspeed, func);
+}
+
+#ifdef SVQC
+void ApplyMinMaxScaleAngles(entity e)
+{
+       if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
+       {
+               e.maxs = '1 1 1' * vlen(
+                       '1 0 0' * max(-e.mins.x, e.maxs.x) +
+                       '0 1 0' * max(-e.mins.y, e.maxs.y) +
+                       '0 0 1' * max(-e.mins.z, e.maxs.z)
+               );
+               e.mins = -e.maxs;
+       }
+       else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
+       {
+               e.maxs_x = vlen(
+                       '1 0 0' * max(-e.mins.x, e.maxs.x) +
+                       '0 1 0' * max(-e.mins.y, e.maxs.y)
+               );
+               e.maxs_y = e.maxs.x;
+               e.mins_x = -e.maxs.x;
+               e.mins_y = -e.maxs.x;
+       }
+       if(e.scale)
+               setsize(e, e.mins * e.scale, e.maxs * e.scale);
+       else
+               setsize(e, e.mins, e.maxs);
+}
+
+void SetBrushEntityModel(entity this)
+{
+       if(this.model != "")
+       {
+               precache_model(this.model);
+               if(this.mins != '0 0 0' || this.maxs != '0 0 0')
+               {
+                       vector mi = this.mins;
+                       vector ma = this.maxs;
+                       _setmodel(this, this.model); // no precision needed
+                       setsize(this, mi, ma);
+               }
+               else
+                       _setmodel(this, this.model); // no precision needed
+               InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
+       }
+       setorigin(this, this.origin);
+       ApplyMinMaxScaleAngles(this);
+}
+
+void SetBrushEntityModelNoLOD(entity this)
+{
+       if(this.model != "")
+       {
+               precache_model(this.model);
+               if(this.mins != '0 0 0' || this.maxs != '0 0 0')
+               {
+                       vector mi = this.mins;
+                       vector ma = this.maxs;
+                       _setmodel(this, this.model); // no precision needed
+                       setsize(this, mi, ma);
+               }
+               else
+                       _setmodel(this, this.model); // no precision needed
+       }
+       setorigin(this, this.origin);
+       ApplyMinMaxScaleAngles(this);
+}
+
+bool LOD_customize(entity this, entity client)
+{
+       if(autocvar_loddebug)
+       {
+               int d = autocvar_loddebug;
+               if(d == 1)
+                       this.modelindex = this.lodmodelindex0;
+               else if(d == 2 || !this.lodmodelindex2)
+                       this.modelindex = this.lodmodelindex1;
+               else // if(d == 3)
+                       this.modelindex = this.lodmodelindex2;
+               return true;
+       }
+
+       // TODO csqc network this so it only gets sent once
+       vector near_point = NearestPointOnBox(this, client.origin);
+       if(vdist(near_point - client.origin, <, this.loddistance1))
+               this.modelindex = this.lodmodelindex0;
+       else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
+               this.modelindex = this.lodmodelindex1;
+       else
+               this.modelindex = this.lodmodelindex2;
+
+       return true;
+}
+
+void LOD_uncustomize(entity this)
+{
+       this.modelindex = this.lodmodelindex0;
+}
+
+void LODmodel_attach(entity this)
+{
+       entity e;
+
+       if(!this.loddistance1)
+               this.loddistance1 = 1000;
+       if(!this.loddistance2)
+               this.loddistance2 = 2000;
+       this.lodmodelindex0 = this.modelindex;
+
+       if(this.lodtarget1 != "")
+       {
+               e = find(NULL, targetname, this.lodtarget1);
+               if(e)
+               {
+                       this.lodmodel1 = e.model;
+                       delete(e);
+               }
+       }
+       if(this.lodtarget2 != "")
+       {
+               e = find(NULL, targetname, this.lodtarget2);
+               if(e)
+               {
+                       this.lodmodel2 = e.model;
+                       delete(e);
+               }
+       }
+
+       if(autocvar_loddebug < 0)
+       {
+               this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
+       }
+
+       if(this.lodmodel1 != "")
+       {
+               vector mi, ma;
+               mi = this.mins;
+               ma = this.maxs;
+
+               precache_model(this.lodmodel1);
+               _setmodel(this, this.lodmodel1);
+               this.lodmodelindex1 = this.modelindex;
+
+               if(this.lodmodel2 != "")
+               {
+                       precache_model(this.lodmodel2);
+                       _setmodel(this, this.lodmodel2);
+                       this.lodmodelindex2 = this.modelindex;
+               }
+
+               this.modelindex = this.lodmodelindex0;
+               setsize(this, mi, ma);
+       }
+
+       if(this.lodmodelindex1)
+               if (!getSendEntity(this))
+                       SetCustomizer(this, LOD_customize, LOD_uncustomize);
+}
+
+/*
+================
+InitTrigger
+================
+*/
+
+void SetMovedir(entity this)
+{
+       if(this.movedir != '0 0 0')
+               this.movedir = normalize(this.movedir);
+       else
+       {
+               makevectors(this.angles);
+               this.movedir = v_forward;
+       }
+
+       this.angles = '0 0 0';
+}
+
+void InitTrigger(entity this)
+{
+// trigger angles are used for one-way touches.  An angle of 0 is assumed
+// to mean no restrictions, so use a yaw of 360 instead.
+       SetMovedir(this);
+       this.solid = SOLID_TRIGGER;
+       SetBrushEntityModel(this);
+       set_movetype(this, MOVETYPE_NONE);
+       this.modelindex = 0;
+       this.model = "";
+}
+
+void InitSolidBSPTrigger(entity this)
+{
+// trigger angles are used for one-way touches.  An angle of 0 is assumed
+// to mean no restrictions, so use a yaw of 360 instead.
+       SetMovedir(this);
+       this.solid = SOLID_BSP;
+       SetBrushEntityModel(this);
+       set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
+//     this.modelindex = 0;
+       this.model = "";
+}
+
+bool InitMovingBrushTrigger(entity this)
+{
+// trigger angles are used for one-way touches.  An angle of 0 is assumed
+// to mean no restrictions, so use a yaw of 360 instead.
+       this.solid = SOLID_BSP;
+       SetBrushEntityModel(this);
+       set_movetype(this, MOVETYPE_PUSH);
+       if(this.modelindex == 0)
+       {
+               objerror(this, "InitMovingBrushTrigger: no brushes found!");
+               return false;
+       }
+       return true;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/subs.qh b/qcsrc/common/mapobjects/subs.qh
new file mode 100644 (file)
index 0000000..0fa7db2
--- /dev/null
@@ -0,0 +1,170 @@
+#pragma once
+#include "defs.qh"
+
+.float friction;
+void SUB_Friction(entity this);
+
+void SUB_NullThink(entity this);
+
+/*
+==================
+SUB_VanishOrRemove
+
+Makes client invisible or removes non-client
+==================
+*/
+void SUB_VanishOrRemove(entity ent);
+
+void SUB_SetFade_Think(entity this);
+
+/*
+==================
+SUB_SetFade
+
+Fade 'ent' out when time >= 'when'
+==================
+*/
+void SUB_SetFade(entity ent, float when, float fading_time);
+
+.vector                finaldest, finalangle;          //plat.qc stuff
+.void(entity this) think1;
+.float state;
+.float         t_length, t_width;
+
+.vector destvec;
+.vector destvec2;
+
+.float delay;
+.float wait;
+.float lip;
+.float speed;
+.float sounds;
+.string  platmovetype;
+.float platmovetype_start, platmovetype_end;
+
+//entity activator;
+
+.string killtarget;
+
+.vector        pos1, pos2;
+.vector        mangle;
+
+.string target2;
+.string target3;
+.string target4;
+.string curvetarget;
+.float target_random;
+.float trigger_reverse;
+
+// Keys player is holding
+.float itemkeys;
+// message delay for func_door locked by keys and key locks
+// this field is used on player entities
+.float key_door_messagetime;
+
+.vector dest1, dest2;
+
+.entity move_controller;
+
+const int TSPEED_TIME = -1;
+const int TSPEED_LINEAR = 0;
+const int TSPEED_START = 1;
+const int TSPEED_END = 2;
+// TODO average too?
+
+#ifdef CSQC
+// this stuff is defined in the server side engine VM, so we must define it separately here
+.float takedamage;
+const int DAMAGE_NO = 0;
+const int DAMAGE_YES = 1;
+const int DAMAGE_AIM = 2;
+
+.string                noise, noise1, noise2, noise3;  // contains names of wavs to play
+
+.float         max_health;             // players maximum health is stored here
+#endif
+
+#ifdef SVQC
+spawnfunc(info_null);
+#endif
+
+/*
+=============
+SUB_CalcMove
+
+calculate this.velocity and this.nextthink to reach dest from
+this.origin traveling at speed
+===============
+*/
+void SUB_CalcMoveDone(entity this);
+
+.float platmovetype_turn;
+void SUB_CalcMove_controller_think (entity this);
+
+void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest);
+
+void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest);
+
+void SUB_CalcMove_Bezier (entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
+
+void SUB_CalcMove (entity this, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
+
+void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
+
+#ifdef SVQC
+void ApplyMinMaxScaleAngles(entity e);
+
+void SetBrushEntityModel(entity this);
+
+void SetBrushEntityModelNoLOD(entity this);
+
+int autocvar_loddebug;
+.string lodtarget1;
+.string lodtarget2;
+.string lodmodel1;
+.string lodmodel2;
+.float lodmodelindex0;
+.float lodmodelindex1;
+.float lodmodelindex2;
+.float loddistance1;
+.float loddistance2;
+
+bool LOD_customize(entity this, entity client);
+
+void LOD_uncustomize(entity this);
+
+void LODmodel_attach(entity this);
+#endif
+
+/*
+=============
+SUB_CalcAngleMove
+
+calculate this.avelocity and this.nextthink to reach destangle from
+this.angles rotating
+
+The calling function should make sure this.think is valid
+===============
+*/
+void SUB_CalcAngleMoveDone (entity this);
+
+// FIXME: I fixed this function only for rotation around the main axes
+void SUB_CalcAngleMove (entity this, vector destangle, float tspeedtype, float tspeed, void(entity this) func);
+
+void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void(entity this) func);
+
+/*
+================
+InitTrigger
+================
+*/
+
+#ifdef SVQC
+void SetMovedir(entity this);
+
+void InitTrigger(entity this);
+
+void InitSolidBSPTrigger(entity this);
+
+bool InitMovingBrushTrigger(entity this);
+#endif
diff --git a/qcsrc/common/mapobjects/target/_mod.inc b/qcsrc/common/mapobjects/target/_mod.inc
new file mode 100644 (file)
index 0000000..f9cc536
--- /dev/null
@@ -0,0 +1,10 @@
+// generated file; do not modify
+#include <common/mapobjects/target/changelevel.qc>
+#include <common/mapobjects/target/kill.qc>
+#include <common/mapobjects/target/levelwarp.qc>
+#include <common/mapobjects/target/location.qc>
+#include <common/mapobjects/target/music.qc>
+#include <common/mapobjects/target/spawn.qc>
+#include <common/mapobjects/target/spawnpoint.qc>
+#include <common/mapobjects/target/speaker.qc>
+#include <common/mapobjects/target/voicescript.qc>
diff --git a/qcsrc/common/mapobjects/target/_mod.qh b/qcsrc/common/mapobjects/target/_mod.qh
new file mode 100644 (file)
index 0000000..e3f4ced
--- /dev/null
@@ -0,0 +1,10 @@
+// generated file; do not modify
+#include <common/mapobjects/target/changelevel.qh>
+#include <common/mapobjects/target/kill.qh>
+#include <common/mapobjects/target/levelwarp.qh>
+#include <common/mapobjects/target/location.qh>
+#include <common/mapobjects/target/music.qh>
+#include <common/mapobjects/target/spawn.qh>
+#include <common/mapobjects/target/spawnpoint.qh>
+#include <common/mapobjects/target/speaker.qh>
+#include <common/mapobjects/target/voicescript.qh>
diff --git a/qcsrc/common/mapobjects/target/changelevel.qc b/qcsrc/common/mapobjects/target/changelevel.qc
new file mode 100644 (file)
index 0000000..114fd87
--- /dev/null
@@ -0,0 +1,55 @@
+#include "changelevel.qh"
+#ifdef SVQC
+.string chmap, gametype;
+.entity chlevel_targ;
+
+void target_changelevel_use(entity this, entity actor, entity trigger)
+{
+       if(this.spawnflags & CHANGELEVEL_MULTIPLAYER)
+       {
+               // simply don't react if a non-player triggers it
+               if(!IS_PLAYER(actor)) { return; }
+
+               actor.chlevel_targ = this;
+
+               int plnum = 0;
+               int realplnum = 0;
+               // let's not count bots
+               FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
+                       ++realplnum;
+                       if(it.chlevel_targ == this)
+                               ++plnum;
+               });
+               if(plnum < ceil(realplnum * min(1, this.count))) // 70% of players
+                       return;
+       }
+
+       if(this.gametype != "")
+               MapInfo_SwitchGameType(MapInfo_Type_FromString(this.gametype));
+
+       if (this.chmap == "")
+               localcmd("endmatch\n");
+       else
+               localcmd(strcat("changelevel ", this.chmap, "\n"));
+}
+
+/*target_changelevel
+Target to change/end level
+KEYS:
+chmap: map to switch to, leave empty for endmatch
+gametype: gametype for the next map
+count: fraction of real players that need to trigger this entity for levelchange
+SPAWNFLAGS:
+CHANGELEVEL_MULTIPLAYER: multiplayer support
+*/
+
+spawnfunc(target_changelevel)
+{
+       this.use = target_changelevel_use;
+
+       if(!this.count)
+       {
+               this.count = 0.7;
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/changelevel.qh b/qcsrc/common/mapobjects/target/changelevel.qh
new file mode 100644 (file)
index 0000000..f6e206e
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int CHANGELEVEL_MULTIPLAYER = BIT(1);
diff --git a/qcsrc/common/mapobjects/target/kill.qc b/qcsrc/common/mapobjects/target/kill.qc
new file mode 100644 (file)
index 0000000..2751c60
--- /dev/null
@@ -0,0 +1,26 @@
+#include "kill.qh"
+#include "location.qh"
+#ifdef SVQC
+
+void target_kill_use(entity this, entity actor, entity trigger)
+{
+       if(actor.takedamage == DAMAGE_NO)
+               return;
+
+       if(!actor.iscreature && !actor.damagedbytriggers)
+               return;
+
+       Damage(actor, this, trigger, 1000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, actor.origin, '0 0 0');
+}
+
+spawnfunc(target_kill)
+{
+    this.classname = "target_kill";
+
+    if (this.message == "")
+               this.message = "was in the wrong place";
+
+    this.use = target_kill_use;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/target/kill.qh b/qcsrc/common/mapobjects/target/kill.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/target/levelwarp.qc b/qcsrc/common/mapobjects/target/levelwarp.qc
new file mode 100644 (file)
index 0000000..21419cf
--- /dev/null
@@ -0,0 +1,21 @@
+#include "levelwarp.qh"
+
+#ifdef SVQC
+void target_levelwarp_use(entity this, entity actor, entity trigger)
+{
+       if(!autocvar_g_campaign)
+               return; // only in campaign
+
+       if(this.cnt)
+               CampaignLevelWarp(this.cnt - 1); // specific level
+       else
+               CampaignLevelWarp(-1); // next level
+}
+
+spawnfunc(target_levelwarp)
+{
+       // this.cnt is index (starting from 1) of the campaign level to warp to
+       // 0 means next level
+       this.use = target_levelwarp_use;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/levelwarp.qh b/qcsrc/common/mapobjects/target/levelwarp.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/target/location.qc b/qcsrc/common/mapobjects/target/location.qc
new file mode 100644 (file)
index 0000000..5774f45
--- /dev/null
@@ -0,0 +1,25 @@
+#include "location.qh"
+#ifdef SVQC
+void target_push_init(entity this);
+
+spawnfunc(target_location)
+{
+    this.classname = "target_location";
+    // location name in netname
+    // eventually support: count, teamgame selectors, line of sight?
+
+    target_push_init(this);
+
+    IL_PUSH(g_locations, this);
+}
+
+spawnfunc(info_location)
+{
+    this.classname = "target_location";
+    this.message = this.netname;
+
+    target_push_init(this);
+
+    IL_PUSH(g_locations, this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/location.qh b/qcsrc/common/mapobjects/target/location.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/target/music.qc b/qcsrc/common/mapobjects/target/music.qc
new file mode 100644 (file)
index 0000000..5a63872
--- /dev/null
@@ -0,0 +1,344 @@
+#include "music.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <common/constants.qh>
+    #include <common/net_linked.qh>
+    #include <server/constants.qh>
+    #include <server/defs.qh>
+#endif
+
+REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
+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
+//   targetname
+//   lifetime
+//   fade_time
+//   fade_rate
+// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
+// when targetname is not set, THIS ONE is default
+void target_music_sendto(entity this, int to, bool is)
+{
+       WriteHeader(to, TE_CSQC_TARGET_MUSIC);
+       WriteShort(to, etof(this));
+       WriteByte(to, this.volume * 255.0 * is);
+       WriteByte(to, this.fade_time * 16.0);
+       WriteByte(to, this.fade_rate * 16.0);
+       WriteByte(to, this.lifetime);
+       WriteString(to, this.noise);
+}
+void target_music_reset(entity this)
+{
+       if (this.targetname == "")
+       {
+               target_music_sendto(this, MSG_ALL, true);
+       }
+}
+void target_music_kill()
+{
+       IL_EACH(g_targetmusic_list, true,
+       {
+               it.volume = 0;
+        if (it.targetname == "")
+            target_music_sendto(it, MSG_ALL, true);
+        else
+            target_music_sendto(it, MSG_ALL, false);
+       });
+}
+void target_music_use(entity this, entity actor, entity trigger)
+{
+       if(!actor)
+               return;
+       if(IS_REAL_CLIENT(actor))
+       {
+               msg_entity = actor;
+               target_music_sendto(this, MSG_ONE, true);
+       }
+       FOREACH_CLIENT(IS_SPEC(it) && it.enemy == actor, {
+               msg_entity = it;
+               target_music_sendto(this, MSG_ONE, true);
+       });
+}
+spawnfunc(target_music)
+{
+       this.use = target_music_use;
+       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, true);
+       else
+               target_music_sendto(this, MSG_INIT, false);
+}
+void TargetMusic_RestoreGame()
+{
+       IL_EACH(g_targetmusic_list, true,
+       {
+               if(it.targetname == "")
+                       target_music_sendto(it, MSG_INIT, true);
+               else
+                       target_music_sendto(it, MSG_INIT, false);
+       });
+}
+// values:
+//   volume
+//   noise
+//   targetname
+//   fade_time
+// spawnflags:
+//   START_DISABLED
+// can be disabled/enabled for everyone with relays
+bool trigger_music_SendEntity(entity this, entity to, int sendflags)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
+       WriteByte(MSG_ENTITY, sendflags);
+       if(sendflags & SF_MUSIC_ORIGIN)
+       {
+               WriteVector(MSG_ENTITY, this.origin);
+       }
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               if(this.model != "null")
+               {
+                       WriteShort(MSG_ENTITY, this.modelindex);
+                       WriteVector(MSG_ENTITY, this.mins);
+                       WriteVector(MSG_ENTITY, this.maxs);
+               }
+               else
+               {
+                       WriteShort(MSG_ENTITY, 0);
+                       WriteVector(MSG_ENTITY, this.maxs);
+               }
+               WriteByte(MSG_ENTITY, this.volume * 255.0);
+               WriteByte(MSG_ENTITY, this.fade_time * 16.0);
+               WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
+               WriteString(MSG_ENTITY, this.noise);
+       }
+       if(sendflags & SF_TRIGGER_UPDATE)
+       {
+               WriteByte(MSG_ENTITY, this.active);
+       }
+       return true;
+}
+void trigger_music_reset(entity this)
+{
+       if(this.spawnflags & START_DISABLED)
+       {
+               this.setactive(this, ACTIVE_NOT);
+       }
+       else
+       {
+               this.setactive(this, ACTIVE_ACTIVE);
+       }
+}
+
+spawnfunc(trigger_music)
+{
+       if(this.model != "")
+       {
+               _setmodel(this, this.model);
+       }
+       if(!this.volume)
+       {
+               this.volume = 1;
+       }
+       if(!this.modelindex)
+       {
+               setorigin(this, this.origin + this.mins);
+               setsize(this, '0 0 0', this.maxs - this.mins);
+       }
+
+       this.setactive = generic_netlinked_setactive;
+       this.use = generic_netlinked_legacy_use; // backwards compatibility
+       this.reset = trigger_music_reset;
+       this.reset(this);
+
+       Net_LinkEntity(this, false, 0, trigger_music_SendEntity);
+}
+#elif defined(CSQC)
+
+entity TargetMusic_list;
+STATIC_INIT(TargetMusic_list)
+{
+       TargetMusic_list = LL_NEW();
+}
+
+void TargetMusic_Advance()
+{
+       // run AFTER all the thinks!
+       entity best = music_default;
+       if (music_target && time < music_target.lifetime)
+       {
+               best = music_target;
+       }
+       if (music_trigger)
+       {
+               best = music_trigger;
+       }
+       LL_EACH(TargetMusic_list, it.noise, {
+               const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
+               if (it == best)
+               {
+                       // increase volume
+                       it.state = (it.fade_time > 0) ? bound(0, it.state + frametime / it.fade_time, 1) : 1;
+               }
+               else
+               {
+                       // decrease volume
+                       it.state = (it.fade_rate > 0) ? bound(0, it.state - frametime / it.fade_rate, 1) : 0;
+               }
+               const float vol = it.state * it.volume * autocvar_bgmvolume;
+               if (vol != vol0)
+               {
+                       if(vol0 < 0)
+                               sound7(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE, 0, BIT(4)); // restart
+                       else
+                               sound7(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE, 0, BIT(4));
+                       it.lastvol = vol;
+               }
+       });
+       music_trigger = NULL;
+       bgmtime = (best) ? getsoundtime(best, CH_BGM_SINGLE) : gettime(GETTIME_CDTRACK);
+}
+
+NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
+{
+       Net_TargetMusic();
+       return true;
+}
+
+void Net_TargetMusic()
+{
+       const int id = ReadShort();
+       const float vol = ReadByte() / 255.0;
+       const float fai = ReadByte() / 16.0;
+       const float fao = ReadByte() / 16.0;
+       const float tim = ReadByte();
+       const string noi = ReadString();
+
+       entity e = NULL;
+       LL_EACH(TargetMusic_list, it.count == id, { e = it; break; });
+       if (!e)
+       {
+               LL_PUSH(TargetMusic_list, e = new_pure(TargetMusic));
+               e.count = id;
+       }
+       if(e.noise != noi)
+       {
+               strcpy(e.noise, noi);
+               precache_sound(e.noise);
+               _sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
+               if(getsoundtime(e, CH_BGM_SINGLE) < 0)
+               {
+                       LOG_TRACEF("Cannot initialize sound %s", e.noise);
+                       strfree(e.noise);
+               }
+       }
+       e.volume = vol;
+       e.fade_time = fai;
+       e.fade_rate = fao;
+       if(vol > 0)
+       {
+               if(tim == 0)
+               {
+                       music_default = e;
+                       if(!music_disabled)
+                       {
+                               e.state = 2;
+                               cvar_settemp("music_playlist_index", "-1"); // don't use playlists
+                               localcmd("cd stop\n"); // just in case
+                               music_disabled = 1;
+                       }
+               }
+               else
+               {
+                       music_target = e;
+                       e.lifetime = time + tim;
+               }
+       }
+}
+
+void Ent_TriggerMusic_Think(entity this)
+{
+       if(this.active == ACTIVE_NOT)
+       {
+               return;
+       }
+       vector org = (csqcplayer) ? csqcplayer.origin : view_origin;
+       if(WarpZoneLib_BoxTouchesBrush(org + STAT(PL_MIN), org + STAT(PL_MAX), this, NULL))
+       {
+               music_trigger = this;
+       }
+}
+
+void Ent_TriggerMusic_Remove(entity this)
+{
+    strfree(this.noise);
+}
+
+NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
+{
+       int sendflags = ReadByte();
+       if(sendflags & SF_MUSIC_ORIGIN)
+       {
+               this.origin = ReadVector();
+       }
+       if(sendflags & SF_TRIGGER_INIT)
+       {
+               this.modelindex = ReadShort();
+               if(this.modelindex)
+               {
+                       this.mins = ReadVector();
+                       this.maxs = ReadVector();
+               }
+               else
+               {
+                       this.mins    = '0 0 0';
+                       this.maxs = ReadVector();
+               }
+
+               this.volume = ReadByte() / 255.0;
+               this.fade_time = ReadByte() / 16.0;
+               this.fade_rate = ReadByte() / 16.0;
+               string s = this.noise;
+               strcpy(this.noise, ReadString());
+               if(this.noise != s)
+               {
+                       precache_sound(this.noise);
+                       sound7(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE, 0, BIT(4));
+                       if(getsoundtime(this, CH_BGM_SINGLE) < 0)
+                       {
+                               LOG_WARNF("Cannot initialize sound %s", this.noise);
+                               strfree(this.noise);
+                       }
+               }
+       }
+       if(sendflags & SF_TRIGGER_UPDATE)
+       {
+               this.active = ReadByte();
+       }
+
+       setorigin(this, this.origin);
+       setsize(this, this.mins, this.maxs);
+       this.draw = Ent_TriggerMusic_Think;
+       if(isnew)
+       {
+               LL_PUSH(TargetMusic_list, this);
+               IL_PUSH(g_drawables, this);
+       }
+       return true;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/target/music.qh b/qcsrc/common/mapobjects/target/music.qh
new file mode 100644 (file)
index 0000000..fac0015
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+.float lifetime;
+
+const int SF_MUSIC_ORIGIN = BIT(2);
+
+#ifdef CSQC
+float music_disabled;
+entity music_default;
+entity music_target;
+entity music_trigger;
+// FIXME also control bgmvolume here, to not require a target_music for the default track.
+
+entityclass(TargetMusic);
+classfield(TargetMusic) .int state;
+classfield(TargetMusic) .float lastvol;
+
+void TargetMusic_Advance();
+
+void Net_TargetMusic();
+
+void Ent_TriggerMusic_Think(entity this);
+
+void Ent_TriggerMusic_Remove(entity this);
+
+#elif defined(SVQC)
+void target_music_kill();
+
+void TargetMusic_RestoreGame();
+#endif
diff --git a/qcsrc/common/mapobjects/target/spawn.qc b/qcsrc/common/mapobjects/target/spawn.qc
new file mode 100644 (file)
index 0000000..9c999ed
--- /dev/null
@@ -0,0 +1,340 @@
+#include "spawn.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <common/util.qh>
+    #include <server/defs.qh>
+#endif
+
+#ifdef SVQC
+
+// spawner entity
+// "classname" "target_spawn"
+// "message" "fieldname value fieldname value ..."
+// "spawnflags"
+//   ON_MAPLOAD = trigger on map load
+
+float target_spawn_initialized;
+.void(entity this) target_spawn_spawnfunc;
+float target_spawn_spawnfunc_field;
+.entity target_spawn_activator;
+.float target_spawn_id;
+float target_spawn_count;
+
+void target_spawn_helper_setmodel(entity this)
+{
+       _setmodel(this, this.model);
+}
+
+void target_spawn_helper_setsize(entity this)
+{
+       setsize(this, this.mins, this.maxs);
+}
+
+void target_spawn_edit_entity(entity this, entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act, entity trigger)
+{
+       float i, n, valuefieldpos;
+       string key, value, valuefield, valueoffset, valueoffsetrandom;
+       entity valueent;
+       vector data, data2;
+
+       n = tokenize_console(msg);
+
+       for(i = 0; i < n-1; i += 2)
+       {
+               key = argv(i);
+               value = argv(i+1);
+               if(key == "$")
+               {
+                       data.x = -1;
+                       data.y = FIELD_STRING;
+               }
+               else
+               {
+                       data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
+                       if(data.y == 0) // undefined field, i.e., invalid type
+                       {
+                               LOG_INFO("target_spawn: invalid/unknown entity key ", key, " specified, ignored!");
+                               continue;
+                       }
+               }
+               if(substring(value, 0, 1) == "$")
+               {
+                       value = substring(value, 1, strlen(value) - 1);
+                       if(substring(value, 0, 1) == "$")
+                       {
+                               // deferred replacement
+                               // do nothing
+                               // useful for creating target_spawns with this!
+                       }
+                       else
+                       {
+                               // replace me!
+                               valuefieldpos = strstrofs(value, "+", 0);
+                               valueoffset = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+                                       value = substring(value, 0, valuefieldpos);
+                               }
+
+                               valuefieldpos = strstrofs(valueoffset, "+", 0);
+                               valueoffsetrandom = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
+                                       valueoffset = substring(valueoffset, 0, valuefieldpos);
+                               }
+
+                               valuefieldpos = strstrofs(value, ".", 0);
+                               valuefield = "";
+                               if(valuefieldpos != -1)
+                               {
+                                       valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
+                                       value = substring(value, 0, valuefieldpos);
+                               }
+
+                               if(value == "self")
+                               {
+                                       valueent = this;
+                                       value = "";
+                               }
+                               else if(value == "activator")
+                               {
+                                       valueent = act;
+                                       value = "";
+                               }
+                               else if(value == "other")
+                               {
+                                       valueent = trigger;
+                                       value = "";
+                               }
+                               else if(value == "pusher")
+                               {
+                                       if(time < act.pushltime)
+                                               valueent = act.pusher;
+                                       else
+                                               valueent = NULL;
+                                       value = "";
+                               }
+                               else if(value == "target")
+                               {
+                                       valueent = e;
+                                       value = "";
+                               }
+                               else if(value == "killtarget")
+                               {
+                                       valueent = kt;
+                                       value = "";
+                               }
+                               else if(value == "target2")
+                               {
+                                       valueent = t2;
+                                       value = "";
+                               }
+                               else if(value == "target3")
+                               {
+                                       valueent = t3;
+                                       value = "";
+                               }
+                               else if(value == "target4")
+                               {
+                                       valueent = t4;
+                                       value = "";
+                               }
+                               else if(value == "time")
+                               {
+                                       valueent = NULL;
+                                       value = ftos(time);
+                               }
+                               else
+                               {
+                                       LOG_INFO("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!");
+                                       continue;
+                               }
+
+                               if(valuefield == "")
+                               {
+                                       if(value == "")
+                                               value = ftos(etof(valueent));
+                               }
+                               else
+                               {
+                                       if(value != "")
+                                       {
+                                               LOG_INFO("target_spawn: try to get a field of a non-entity, ignored!");
+                                               continue;
+                                       }
+                                       data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
+                                       if(data2_y == 0) // undefined field, i.e., invalid type
+                                       {
+                                               LOG_INFO("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!");
+                                               continue;
+                                       }
+                                       value = getentityfieldstring(data2_x, valueent);
+                               }
+
+                               if(valueoffset != "")
+                               {
+                                       switch(data.y)
+                                       {
+                                               case FIELD_STRING:
+                                                       value = strcat(value, valueoffset);
+                                                       break;
+                                               case FIELD_FLOAT:
+                                                       value = ftos(stof(value) + stof(valueoffset));
+                                                       break;
+                                               case FIELD_VECTOR:
+                                                       value = vtos(stov(value) + stov(valueoffset));
+                                                       break;
+                                               default:
+                                                       LOG_INFO("target_spawn: only string, float and vector fields can do calculations, calculation ignored!");
+                                                       break;
+                                       }
+                               }
+
+                               if(valueoffsetrandom != "")
+                               {
+                                       switch(data.y)
+                                       {
+                                               case FIELD_FLOAT:
+                                                       value = ftos(stof(value) + random() * stof(valueoffsetrandom));
+                                                       break;
+                                               case FIELD_VECTOR:
+                                                       data2 = stov(valueoffsetrandom);
+                                                       value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
+                                                       break;
+                                               default:
+                                                       LOG_INFO("target_spawn: only float and vector fields can do random calculations, calculation ignored!");
+                                                       break;
+                                       }
+                               }
+                       }
+               }
+               if(key == "$")
+               {
+                       if(substring(value, 0, 1) == "_")
+                               value = strcat("target_spawn_helper", value);
+                       putentityfieldstring(target_spawn_spawnfunc_field, e, value);
+
+                       e.target_spawn_spawnfunc(e);
+
+                       // We called an external function, so we have to re-tokenize msg.
+                       n = tokenize_console(msg);
+               }
+               else
+               {
+                       if(data.y == FIELD_VECTOR)
+                               value = strreplace("'", "", value); // why?!?
+                       putentityfieldstring(data.x, e, value);
+               }
+       }
+}
+
+void target_spawn_useon(entity e, entity this, entity actor, entity trigger)
+{
+       this.target_spawn_activator = actor;
+       target_spawn_edit_entity(
+               this,
+               e,
+               this.message,
+               find(NULL, targetname, this.killtarget),
+               find(NULL, targetname, this.target2),
+               find(NULL, targetname, this.target3),
+               find(NULL, targetname, this.target4),
+               actor,
+               trigger
+       );
+}
+
+bool target_spawn_cancreate(entity this)
+{
+       float c;
+       entity e;
+
+       c = this.count;
+       if(c == 0) // no limit?
+               return true;
+
+       ++c; // increase count to not include MYSELF
+       for(e = NULL; (e = findfloat(e, target_spawn_id, this.target_spawn_id)); --c)
+               ;
+
+       // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
+       if(c == 0)
+               return false;
+       return true;
+}
+
+void target_spawn_use(entity this, entity actor, entity trigger)
+{
+       if(this.target == "")
+       {
+               // spawn new entity
+               if(!target_spawn_cancreate(this))
+                       return;
+               entity e = spawn();
+               e.spawnfunc_checked = true;
+               target_spawn_useon(e, this, actor, trigger);
+               e.target_spawn_id = this.target_spawn_id;
+       }
+       else if(this.target == "*activator")
+       {
+               // edit entity
+               if(actor)
+                       target_spawn_useon(actor, this, actor, trigger);
+       }
+       else
+       {
+               // edit entity
+               FOREACH_ENTITY_STRING(targetname, this.target,
+               {
+                       target_spawn_useon(it, this, actor, trigger);
+               });
+       }
+}
+
+void target_spawn_spawnfirst(entity this)
+{
+       entity act = this.target_spawn_activator;
+       if(this.spawnflags & ON_MAPLOAD)
+               target_spawn_use(this, act, NULL);
+}
+
+void initialize_field_db()
+{
+       if(!target_spawn_initialized)
+       {
+               float n, i;
+               string fn;
+               vector prev, next;
+               float ft;
+
+               n = numentityfields();
+               for(i = 0; i < n; ++i)
+               {
+                       fn = entityfieldname(i);
+                       ft = entityfieldtype(i);
+                       next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
+                       prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
+                       if(prev.y == 0)
+                       {
+                               db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
+                               if(fn == "target_spawn_spawnfunc")
+                                       target_spawn_spawnfunc_field = i;
+                       }
+               }
+
+               target_spawn_initialized = 1;
+       }
+}
+
+spawnfunc(target_spawn)
+{
+       initialize_field_db();
+       this.use = target_spawn_use;
+       this.message = strzone(strreplace("'", "\"", this.message));
+       this.target_spawn_id = ++target_spawn_count;
+       InitializeEntity(this, target_spawn_spawnfirst, INITPRIO_LAST);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/spawn.qh b/qcsrc/common/mapobjects/target/spawn.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/target/spawnpoint.qc b/qcsrc/common/mapobjects/target/spawnpoint.qc
new file mode 100644 (file)
index 0000000..fe15385
--- /dev/null
@@ -0,0 +1,24 @@
+#include "spawnpoint.qh"
+
+#ifdef SVQC
+void target_spawnpoint_use(entity this, entity actor, entity trigger)
+{
+       if(this.active != ACTIVE_ACTIVE)
+               return;
+
+       actor.spawnpoint_targ = this;
+}
+
+void target_spawnpoint_reset(entity this)
+{
+       this.active = ACTIVE_ACTIVE;
+}
+
+// TODO: persistent spawnflag?
+spawnfunc(target_spawnpoint)
+{
+       this.active = ACTIVE_ACTIVE;
+       this.use = target_spawnpoint_use;
+       this.reset = target_spawnpoint_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/spawnpoint.qh b/qcsrc/common/mapobjects/target/spawnpoint.qh
new file mode 100644 (file)
index 0000000..2eeb8da
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+#ifdef SVQC
+.entity spawnpoint_targ;
+#endif
diff --git a/qcsrc/common/mapobjects/target/speaker.qc b/qcsrc/common/mapobjects/target/speaker.qc
new file mode 100644 (file)
index 0000000..11c9ad7
--- /dev/null
@@ -0,0 +1,138 @@
+#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);
+void target_speaker_use_activator(entity this, entity actor, entity trigger)
+{
+       if (!IS_REAL_CLIENT(actor))
+               return;
+       string snd;
+       if(substring(this.noise, 0, 1) == "*")
+       {
+               var .string sample = GetVoiceMessageSampleField(substring(this.noise, 1, -1));
+               if(GetPlayerSoundSampleField_notFound)
+                       snd = SND(Null);
+               else if(actor.(sample) == "")
+                       snd = SND(Null);
+               else
+               {
+                       tokenize_console(actor.(sample));
+                       float n;
+                       n = stof(argv(1));
+                       if(n > 0)
+                               snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+                       else
+                               snd = strcat(argv(0), ".wav"); // randomization
+               }
+       }
+       else
+               snd = this.noise;
+       msg_entity = actor;
+       soundto(MSG_ONE, this, CH_TRIGGER, snd, VOL_BASE * this.volume, this.atten);
+}
+void target_speaker_use_on(entity this, entity actor, entity trigger)
+{
+       string snd;
+       if(substring(this.noise, 0, 1) == "*")
+       {
+               var .string sample = GetVoiceMessageSampleField(substring(this.noise, 1, -1));
+               if(GetPlayerSoundSampleField_notFound)
+                       snd = SND(Null);
+               else if(actor.(sample) == "")
+                       snd = SND(Null);
+               else
+               {
+                       tokenize_console(actor.(sample));
+                       float n;
+                       n = stof(argv(1));
+                       if(n > 0)
+                               snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
+                       else
+                               snd = strcat(argv(0), ".wav"); // randomization
+               }
+       }
+       else
+               snd = this.noise;
+       _sound(this, CH_TRIGGER_SINGLE, snd, VOL_BASE * this.volume, this.atten);
+       if(this.spawnflags & (SPEAKER_LOOPED_ON + SPEAKER_LOOPED_OFF))
+               this.use = target_speaker_use_off;
+}
+void target_speaker_use_off(entity this, entity actor, entity trigger)
+{
+       sound(this, CH_TRIGGER_SINGLE, SND_Null, VOL_BASE * this.volume, this.atten);
+       this.use = target_speaker_use_on;
+}
+void target_speaker_reset(entity this)
+{
+       if(this.spawnflags & SPEAKER_LOOPED_ON)
+       {
+               if(this.use == target_speaker_use_on)
+                       target_speaker_use_on(this, NULL, NULL);
+       }
+       else if(this.spawnflags & SPEAKER_LOOPED_OFF)
+       {
+               if(this.use == target_speaker_use_off)
+                       target_speaker_use_off(this, NULL, NULL);
+       }
+}
+
+spawnfunc(target_speaker)
+{
+       // TODO: "*" prefix to sound file name
+       // TODO: wait and random (just, HOW? random is not a field)
+       if(this.noise)
+               precache_sound (this.noise);
+
+       if(!this.atten && (this.spawnflags & SPEAKER_GLOBAL))
+       {
+               LOG_WARN("target_speaker uses legacy spawnflag GLOBAL (BIT(2)), please set atten to -1 instead");
+               this.atten = -1;
+       }
+
+       if(!this.atten)
+       {
+               IFTARGETED
+                       this.atten = ATTEN_NORM;
+               else
+                       this.atten = ATTEN_STATIC;
+       }
+       else if(this.atten < 0)
+               this.atten = 0;
+
+       if(!this.volume)
+               this.volume = 1;
+
+       IFTARGETED
+       {
+               if(this.spawnflags & SPEAKER_ACTIVATOR)
+                       this.use = target_speaker_use_activator;
+               else if(this.spawnflags & SPEAKER_LOOPED_ON)
+               {
+                       target_speaker_use_on(this, NULL, NULL);
+                       this.reset = target_speaker_reset;
+               }
+               else if(this.spawnflags & SPEAKER_LOOPED_OFF)
+               {
+                       this.use = target_speaker_use_on;
+                       this.reset = target_speaker_reset;
+               }
+               else
+                       this.use = target_speaker_use_on;
+       }
+       else if(this.spawnflags & SPEAKER_LOOPED_ON)
+       {
+               ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
+               delete(this);
+       }
+       else if(this.spawnflags & SPEAKER_LOOPED_OFF)
+       {
+               objerror(this, "This sound entity can never be activated");
+       }
+       else
+       {
+               // Quake/Nexuiz fallback
+               ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
+               delete(this);
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/speaker.qh b/qcsrc/common/mapobjects/target/speaker.qh
new file mode 100644 (file)
index 0000000..53e0194
--- /dev/null
@@ -0,0 +1,7 @@
+#pragma once
+
+
+const int SPEAKER_LOOPED_ON = BIT(0);
+const int SPEAKER_LOOPED_OFF = BIT(1);
+const int SPEAKER_GLOBAL = BIT(2); // legacy, set speaker atten to -1 instead
+const int SPEAKER_ACTIVATOR = BIT(3);
diff --git a/qcsrc/common/mapobjects/target/voicescript.qc b/qcsrc/common/mapobjects/target/voicescript.qc
new file mode 100644 (file)
index 0000000..6dfb568
--- /dev/null
@@ -0,0 +1,102 @@
+#include "voicescript.qh"
+#ifdef SVQC
+.entity voicescript; // attached voice script
+.float voicescript_index; // index of next voice, or -1 to use the randomized ones
+.float voicescript_nextthink; // time to play next voice
+.float voicescript_voiceend; // time when this voice ends
+
+void target_voicescript_clear(entity pl)
+{
+       pl.voicescript = NULL;
+}
+
+void target_voicescript_use(entity this, entity actor, entity trigger)
+{
+       if(actor.voicescript != this)
+       {
+               actor.voicescript = this;
+               actor.voicescript_index = 0;
+               actor.voicescript_nextthink = time + this.delay;
+       }
+}
+
+void target_voicescript_next(entity pl)
+{
+       entity vs;
+       float i, n, dt;
+
+       vs = pl.voicescript;
+       if(!vs)
+               return;
+       if(vs.message == "")
+               return;
+       if (!IS_PLAYER(pl))
+               return;
+       if(game_stopped)
+               return;
+
+       if(time >= pl.voicescript_voiceend)
+       {
+               if(time >= pl.voicescript_nextthink)
+               {
+                       // get the next voice...
+                       n = tokenize_console(vs.message);
+
+                       if(pl.voicescript_index < vs.cnt)
+                               i = pl.voicescript_index * 2;
+                       else if(n > vs.cnt * 2)
+                               i = ((pl.voicescript_index - vs.cnt) % ((n - vs.cnt * 2 - 1) / 2)) * 2 + vs.cnt * 2 + 1;
+                       else
+                               i = -1;
+
+                       if(i >= 0)
+                       {
+                               play2(pl, strcat(vs.netname, "/", argv(i), ".wav"));
+                               dt = stof(argv(i + 1));
+                               if(dt >= 0)
+                               {
+                                       pl.voicescript_voiceend = time + dt;
+                                       pl.voicescript_nextthink = pl.voicescript_voiceend + vs.wait * (0.5 + random());
+                               }
+                               else
+                               {
+                                       pl.voicescript_voiceend = time - dt;
+                                       pl.voicescript_nextthink = pl.voicescript_voiceend;
+                               }
+
+                               pl.voicescript_index += 1;
+                       }
+                       else
+                       {
+                               pl.voicescript = NULL; // stop trying then
+                       }
+               }
+       }
+}
+
+spawnfunc(target_voicescript)
+{
+       // netname: directory of the sound files
+       // message: list of "sound file" duration "sound file" duration, a *, and again a list
+       //          foo1 4.1 foo2 4.0 foo3 -3.1 * fool1 1.1 fool2 7.1 fool3 9.1 fool4 3.7
+       //          Here, a - in front of the duration means that no delay is to be
+       //          added after this message
+       // wait: average time between messages
+       // delay: initial delay before the first message
+
+       float i, n;
+       this.use = target_voicescript_use;
+
+       n = tokenize_console(this.message);
+       this.cnt = n / 2;
+       for(i = 0; i+1 < n; i += 2)
+       {
+               if(argv(i) == "*")
+               {
+                       this.cnt = i / 2;
+                       ++i;
+               }
+               precache_sound(strcat(this.netname, "/", argv(i), ".wav"));
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/target/voicescript.qh b/qcsrc/common/mapobjects/target/voicescript.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/teleporters.qc b/qcsrc/common/mapobjects/teleporters.qc
new file mode 100644 (file)
index 0000000..ec6a26d
--- /dev/null
@@ -0,0 +1,315 @@
+#include "teleporters.qh"
+
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <lib/warpzone/common.qh>
+    #include <lib/warpzone/util_server.qh>
+    #include <lib/warpzone/server.qh>
+    #include "../constants.qh"
+       #include "../mapobjects/subs.qh"
+    #include "../util.qh"
+    #include <server/weapons/csqcprojectile.qh>
+    #include <server/autocvars.qh>
+    #include <server/constants.qh>
+    #include <server/defs.qh>
+    #include "../deathtypes/all.qh"
+    #include "../turrets/sv_turrets.qh"
+    #include "../vehicles/all.qh"
+    #include "../mapinfo.qh"
+    #include <server/anticheat.qh>
+#endif
+
+#ifdef SVQC
+float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
+{
+       if (IS_PLAYER(player) && !IS_DEAD(player))
+       {
+               TDEATHLOOP(org)
+               {
+               #ifdef SVQC
+                       if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+               #endif
+                               if(IS_PLAYER(head))
+                                       if(!IS_DEAD(head))
+                                               return 1;
+               }
+       }
+       return 0;
+}
+
+void trigger_teleport_link(entity this);
+
+void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
+{
+       TDEATHLOOP(player.origin)
+       {
+               if (IS_PLAYER(player) && player.health >= 1)
+               {
+                       if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+                       {
+                               if(IS_PLAYER(head))
+                                       if(head.health >= 1)
+                                               ++tdeath_hit;
+                               Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, head.origin, '0 0 0');
+                       }
+               }
+               else // dead bodies and monsters gib themselves instead of telefragging
+                       Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, telefragger.origin, '0 0 0');
+       }
+}
+
+void spawn_tdeath(vector v0, entity e, vector v)
+{
+       tdeath(e, e, e, '0 0 0', '0 0 0');
+}
+#endif
+
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
+{
+       entity telefragger;
+       vector from;
+
+       if(teleporter.owner)
+               telefragger = teleporter.owner;
+       else
+               telefragger = player;
+
+       makevectors (to_angles);
+
+#ifdef SVQC
+       if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
+       {
+               if(teleporter.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
+               {
+                       if(tflags & TELEPORT_FLAG_SOUND)
+                       {
+                               string thesound = SND(TELEPORT);
+                               if(teleporter.noise != "")
+                               {
+                                       RandomSelection_Init();
+                                       FOREACH_WORD(teleporter.noise, true,
+                                       {
+                                               RandomSelection_AddString(it, 1, 1);
+                                       });
+                                       thesound = RandomSelection_chosen_string;
+                               }
+                               _sound (player, CH_TRIGGER, thesound, VOL_BASE, ATTEN_NORM);
+                       }
+                       if(tflags & TELEPORT_FLAG_PARTICLES)
+                       {
+                               Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
+                               Send_Effect(EFFECT_TELEPORT, to + v_forward * 32, '0 0 0', 1);
+                       }
+                       teleporter.pushltime = time + 0.2;
+               }
+       }
+#endif
+
+       // Relocate the player
+       // assuming to allows PL_MIN to PL_MAX box and some more
+#ifdef SVQC
+       from = player.origin;
+       setorigin(player, to);
+       player.oldorigin = to; // don't undo the teleport by unsticking
+       player.angles = to_angles;
+       player.fixangle = true;
+       player.velocity = to_velocity;
+       BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+
+       makevectors(player.angles);
+       Reset_ArcBeam(player, v_forward);
+       UpdateCSQCProjectileAfterTeleport(player);
+       UpdateItemAfterTeleport(player);
+#elif defined(CSQC)
+       from = player.origin;
+       setorigin(player, to);
+       player.angles = to_angles;
+       player.velocity = to_velocity;
+       UNSET_ONGROUND(player);
+       player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
+       player.csqcmodel_teleported = 1;
+       player.v_angle = to_angles;
+
+       if(player == csqcplayer) // not for anything but the main player
+       {
+               setproperty(VF_ANGLES, player.angles);
+               setproperty(VF_CL_VIEWANGLES, player.angles);
+       }
+#endif
+
+#ifdef SVQC
+       if(IS_PLAYER(player))
+       {
+               if(tflags & TELEPORT_FLAG_TDEATH)
+                       if(player.takedamage && !IS_DEAD(player) && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
+                               tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
+
+               // player no longer is on ground
+               UNSET_ONGROUND(player);
+
+               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+               player.oldvelocity = player.velocity;
+
+               // reset tracking of who pushed you into a hazard (for kill credit)
+               if(teleporter.owner)
+               {
+                       player.pusher = teleporter.owner;
+                       player.pushltime = time + autocvar_g_maxpushtime;
+                       player.istypefrag = PHYS_INPUT_BUTTON_CHAT(player);
+               }
+               else
+               {
+                       player.pushltime = 0;
+                       player.istypefrag = 0;
+               }
+
+               player.lastteleporttime = time;
+               player.lastteleport_origin = from;
+       }
+#endif
+}
+
+entity Simple_TeleportPlayer(entity teleporter, entity player)
+{
+       vector locout;
+       entity e = NULL;
+
+       // Find the output teleporter
+       if(teleporter.enemy)
+       {
+               e = teleporter.enemy;
+       }
+       else
+       {
+               // sorry CSQC, random stuff ain't gonna happen
+#ifdef SVQC
+               RandomSelection_Init();
+               FOREACH_ENTITY_STRING(targetname, teleporter.target,
+               {
+                       bool p = true;
+                       if(STAT(TELEPORT_TELEFRAG_AVOID, player))
+                       {
+                       #ifdef SVQC
+                               locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
+                       #elif defined(CSQC)
+                               locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
+                       #endif
+                               if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
+                                       p = false;
+                       }
+                       RandomSelection_AddEnt(it, (it.cnt ? it.cnt : 1), p);
+               });
+               e = RandomSelection_chosen_ent;
+#endif
+       }
+
+#ifdef SVQC
+       if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
+#elif defined(CSQC)
+       if(!e) { LOG_INFO("Teleport destination could not be found from CSQC."); }
+#endif
+
+       makevectors(e.mangle);
+
+       if(e.speed)
+               if(vdist(player.velocity, >, e.speed))
+                       player.velocity = normalize(player.velocity) * max(0, e.speed);
+
+       if(STAT(TELEPORT_MAXSPEED, player))
+               if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
+                       player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
+
+       locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+
+       TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+
+       return e;
+}
+
+void teleport_findtarget(entity this)
+{
+       bool istrigger = (this.solid == SOLID_TRIGGER);
+
+       int n = 0;
+       for(entity e = NULL; (e = find(e, targetname, this.target)); )
+       {
+               ++n;
+#ifdef SVQC
+               if(e.move_movetype == MOVETYPE_NONE)
+               {
+                       entity tracetest_ent = spawn();
+                       setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
+                       tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+                       waypoint_spawnforteleporter(this, e.origin, 0, tracetest_ent);
+                       delete(tracetest_ent);
+               }
+               if(e.classname != "info_teleport_destination")
+                       LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.");
+#endif
+       }
+
+       if(n == 0)
+       {
+               // no dest!
+               objerror (this, "Teleporter with nonexistant target");
+               return;
+       }
+       else if(n == 1)
+       {
+               // exactly one dest - bots love that
+               this.enemy = find(NULL, targetname, this.target);
+       }
+       else
+       {
+               // have to use random selection every single time
+               this.enemy = NULL;
+       }
+
+       // now enable touch
+       if(istrigger)
+               settouch(this, Teleport_Touch);
+#ifdef SVQC
+       if(istrigger)
+               trigger_teleport_link(this);
+#endif
+}
+
+entity Teleport_Find(vector mi, vector ma)
+{
+       IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+       {
+               return it;
+       });
+       return NULL;
+}
+
+void WarpZone_PostTeleportPlayer_Callback(entity pl)
+{
+#ifdef SVQC
+       makevectors(pl.angles);
+       Reset_ArcBeam(pl, v_forward);
+       UpdateCSQCProjectileAfterTeleport(pl);
+       UpdateItemAfterTeleport(pl);
+    if (IS_PLAYER(pl)) anticheat_fixangle(pl);
+#endif
+       // "disown" projectiles after teleport
+       if(pl.owner)
+       if(pl.owner == pl.realowner)
+       {
+       #ifdef SVQC
+               if(!(pl.flags & FL_PROJECTILE))
+       #elif defined(CSQC)
+               if(!(pl.flags & BIT(15))) // FL_PROJECTILE
+       #endif
+                       LOG_INFO("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".");
+               pl.owner = NULL;
+       }
+       if(IS_PLAYER(pl))
+       {
+               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+       #ifdef SVQC
+               pl.oldvelocity = pl.velocity;
+       #endif
+       }
+}
diff --git a/qcsrc/common/mapobjects/teleporters.qh b/qcsrc/common/mapobjects/teleporters.qh
new file mode 100644 (file)
index 0000000..68c5114
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma once
+#include "defs.qh"
+
+IntrusiveList g_teleporters;
+STATIC_INIT(g_teleporters) { g_teleporters = IL_NEW(); }
+
+.entity pusher;
+
+const int TELEPORT_FLAG_SOUND = BIT(0);
+const int TELEPORT_FLAG_PARTICLES = BIT(1);
+const int TELEPORT_FLAG_TDEATH = BIT(2);
+const int TELEPORT_FLAG_FORCE_TDEATH = BIT(3);
+
+#define TELEPORT_FLAGS_WARPZONE   0
+#define TELEPORT_FLAGS_PORTAL     (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
+#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
+
+// types for .teleportable entity setting
+const int TELEPORT_NORMAL = 1; // play sounds/effects etc
+const int TELEPORT_SIMPLE = 2; // only do teleport, nothing special
+
+entity Simple_TeleportPlayer(entity teleporter, entity player);
+
+void Teleport_Touch(entity this, entity toucher);
+
+void teleport_findtarget(entity this);
+
+entity Teleport_Find(vector mi, vector ma);
+
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
+
+#ifdef SVQC
+
+void trigger_teleport_use(entity this, entity actor, entity trigger);
+
+#define TDEATHLOOP(o) \
+       entity head; \
+       vector deathmin; \
+       vector deathmax; \
+       float deathradius; \
+       deathmin = (o) + player.mins; \
+       deathmax = (o) + player.maxs; \
+       if(telefragmin != telefragmax) \
+       { \
+               if(deathmin.x > telefragmin.x) deathmin.x = telefragmin.x; \
+               if(deathmin.y > telefragmin.y) deathmin.y = telefragmin.y; \
+               if(deathmin.z > telefragmin.z) deathmin.z = telefragmin.z; \
+               if(deathmax.x < telefragmax.x) deathmax.x = telefragmax.x; \
+               if(deathmax.y < telefragmax.y) deathmax.y = telefragmax.y; \
+               if(deathmax.z < telefragmax.z) deathmax.z = telefragmax.z; \
+       } \
+       deathradius = max(vlen(deathmin), vlen(deathmax)); \
+       for(head = findradius(o, deathradius); head; head = head.chain) \
+               if(head != player) \
+                       if(head.takedamage) \
+                               if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
+
+float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax);
+float tdeath_hit;
+void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax);
+
+void spawn_tdeath(vector v0, entity e, vector v);
+
+void Reset_ArcBeam(entity player, vector forward);
+
+#endif
+
+void WarpZone_PostTeleportPlayer_Callback(entity pl);
+
+#ifdef CSQC
+.entity realowner;
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/_mod.inc b/qcsrc/common/mapobjects/trigger/_mod.inc
new file mode 100644 (file)
index 0000000..c2a663f
--- /dev/null
@@ -0,0 +1,24 @@
+// generated file; do not modify
+#include <common/mapobjects/trigger/counter.qc>
+#include <common/mapobjects/trigger/delay.qc>
+#include <common/mapobjects/trigger/disablerelay.qc>
+#include <common/mapobjects/trigger/flipflop.qc>
+#include <common/mapobjects/trigger/gamestart.qc>
+#include <common/mapobjects/trigger/gravity.qc>
+#include <common/mapobjects/trigger/heal.qc>
+#include <common/mapobjects/trigger/hurt.qc>
+#include <common/mapobjects/trigger/impulse.qc>
+#include <common/mapobjects/trigger/jumppads.qc>
+#include <common/mapobjects/trigger/keylock.qc>
+#include <common/mapobjects/trigger/magicear.qc>
+#include <common/mapobjects/trigger/monoflop.qc>
+#include <common/mapobjects/trigger/multi.qc>
+#include <common/mapobjects/trigger/multivibrator.qc>
+#include <common/mapobjects/trigger/relay.qc>
+#include <common/mapobjects/trigger/relay_activators.qc>
+#include <common/mapobjects/trigger/relay_if.qc>
+#include <common/mapobjects/trigger/relay_teamcheck.qc>
+#include <common/mapobjects/trigger/secret.qc>
+#include <common/mapobjects/trigger/swamp.qc>
+#include <common/mapobjects/trigger/teleport.qc>
+#include <common/mapobjects/trigger/viewloc.qc>
diff --git a/qcsrc/common/mapobjects/trigger/_mod.qh b/qcsrc/common/mapobjects/trigger/_mod.qh
new file mode 100644 (file)
index 0000000..08a6e5a
--- /dev/null
@@ -0,0 +1,24 @@
+// generated file; do not modify
+#include <common/mapobjects/trigger/counter.qh>
+#include <common/mapobjects/trigger/delay.qh>
+#include <common/mapobjects/trigger/disablerelay.qh>
+#include <common/mapobjects/trigger/flipflop.qh>
+#include <common/mapobjects/trigger/gamestart.qh>
+#include <common/mapobjects/trigger/gravity.qh>
+#include <common/mapobjects/trigger/heal.qh>
+#include <common/mapobjects/trigger/hurt.qh>
+#include <common/mapobjects/trigger/impulse.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/keylock.qh>
+#include <common/mapobjects/trigger/magicear.qh>
+#include <common/mapobjects/trigger/monoflop.qh>
+#include <common/mapobjects/trigger/multi.qh>
+#include <common/mapobjects/trigger/multivibrator.qh>
+#include <common/mapobjects/trigger/relay.qh>
+#include <common/mapobjects/trigger/relay_activators.qh>
+#include <common/mapobjects/trigger/relay_if.qh>
+#include <common/mapobjects/trigger/relay_teamcheck.qh>
+#include <common/mapobjects/trigger/secret.qh>
+#include <common/mapobjects/trigger/swamp.qh>
+#include <common/mapobjects/trigger/teleport.qh>
+#include <common/mapobjects/trigger/viewloc.qh>
diff --git a/qcsrc/common/mapobjects/trigger/counter.qc b/qcsrc/common/mapobjects/trigger/counter.qc
new file mode 100644 (file)
index 0000000..4c89c4c
--- /dev/null
@@ -0,0 +1,67 @@
+#include "counter.qh"
+#ifdef SVQC
+void counter_reset(entity this);
+
+void counter_use(entity this, entity actor, entity trigger)
+{
+       this.count -= 1;
+       if (this.count < 0)
+               return;
+
+       bool doactivate = (this.spawnflags & COUNTER_FIRE_AT_COUNT);
+
+       if (this.count == 0)
+       {
+               if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE))
+                       Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COMPLETED);
+
+               doactivate = true;
+
+               if(this.respawntime)
+               {
+                       setthink(this, counter_reset);
+                       this.nextthink = time + this.respawntime;
+               }
+       }
+       else
+       {
+               if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE))
+               {
+                       if(this.count >= 4)
+                               Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER);
+                       else
+                               Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, this.count);
+               }
+       }
+
+       if(doactivate)
+               SUB_UseTargets(this, actor, trigger);
+}
+
+void counter_reset(entity this)
+{
+       setthink(this, func_null);
+       this.nextthink = 0;
+       this.count = this.cnt;
+}
+
+/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage COUNTER_FIRE_AT_COUNT
+Acts as an intermediary for an action that takes multiple inputs.
+
+If nomessage is not set, it will print "1 more.. " etc when triggered and "sequence complete" when finished.
+If COUNTER_FIRE_AT_COUNT is set, it will also fire all of its targets at countdown, making it behave like trigger_mulitple with limited shots
+
+If respawntime is set, it will re-enable itself after the time once the sequence has been completed
+
+After the counter has been triggered "count" times (default 2), it will fire all of its targets.
+*/
+spawnfunc(trigger_counter)
+{
+       if (!this.count)
+               this.count = 2;
+       this.cnt = this.count;
+
+       this.use = counter_use;
+       this.reset = counter_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/counter.qh b/qcsrc/common/mapobjects/trigger/counter.qh
new file mode 100644 (file)
index 0000000..394d154
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int COUNTER_FIRE_AT_COUNT = BIT(2);
diff --git a/qcsrc/common/mapobjects/trigger/delay.qc b/qcsrc/common/mapobjects/trigger/delay.qc
new file mode 100644 (file)
index 0000000..2cd4cfd
--- /dev/null
@@ -0,0 +1,32 @@
+#include "delay.qh"
+#ifdef SVQC
+void delay_delayeduse(entity this)
+{
+       SUB_UseTargets(this, this.enemy, this.goalentity);
+       this.enemy = this.goalentity = NULL;
+}
+
+void delay_use(entity this, entity actor, entity trigger)
+{
+       this.enemy = actor;
+       this.goalentity = trigger;
+       setthink(this, delay_delayeduse);
+       this.nextthink = time + this.wait;
+}
+
+void delay_reset(entity this)
+{
+       this.enemy = this.goalentity = NULL;
+       setthink(this, func_null);
+       this.nextthink = 0;
+}
+
+spawnfunc(trigger_delay)
+{
+    if(!this.wait)
+        this.wait = 1;
+
+    this.use = delay_use;
+    this.reset = delay_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/delay.qh b/qcsrc/common/mapobjects/trigger/delay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/disablerelay.qc b/qcsrc/common/mapobjects/trigger/disablerelay.qc
new file mode 100644 (file)
index 0000000..eee61c9
--- /dev/null
@@ -0,0 +1,29 @@
+#include "disablerelay.qh"
+#ifdef SVQC
+void trigger_disablerelay_use(entity this, entity actor, entity trigger)
+{
+       int a = 0, b = 0;
+
+       for(entity e = NULL; (e = find(e, targetname, this.target)); )
+       {
+               if(e.use == SUB_UseTargets)
+               {
+                       e.use = SUB_DontUseTargets;
+                       ++a;
+               }
+               else if(e.use == SUB_DontUseTargets)
+               {
+                       e.use = SUB_UseTargets;
+                       ++b;
+               }
+       }
+
+       if((!a) == (!b))
+               LOG_INFO("Invalid use of trigger_disablerelay: ", ftos(a), " relays were on, ", ftos(b), " relays were off!");
+}
+
+spawnfunc(trigger_disablerelay)
+{
+       this.use = trigger_disablerelay_use;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/disablerelay.qh b/qcsrc/common/mapobjects/trigger/disablerelay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/flipflop.qc b/qcsrc/common/mapobjects/trigger/flipflop.qc
new file mode 100644 (file)
index 0000000..141f3ea
--- /dev/null
@@ -0,0 +1,23 @@
+#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
+*/
+void flipflop_use(entity this, entity actor, entity trigger)
+{
+    this.state = !this.state;
+    if(this.state)
+        SUB_UseTargets(this, actor, trigger);
+}
+
+spawnfunc(trigger_flipflop)
+{
+    if(this.spawnflags & START_ENABLED)
+    {
+        this.state = true;
+    }
+    this.use = flipflop_use;
+    this.reset = spawnfunc_trigger_flipflop; // perfect resetter
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/flipflop.qh b/qcsrc/common/mapobjects/trigger/flipflop.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/gamestart.qc b/qcsrc/common/mapobjects/trigger/gamestart.qc
new file mode 100644 (file)
index 0000000..72d76d1
--- /dev/null
@@ -0,0 +1,28 @@
+#include "gamestart.qh"
+#ifdef SVQC
+void gamestart_use(entity this, entity actor, entity trigger)
+{
+       SUB_UseTargets(this, this, trigger);
+       delete(this);
+}
+
+void gamestart_use_this(entity this)
+{
+       gamestart_use(this, NULL, NULL);
+}
+
+spawnfunc(trigger_gamestart)
+{
+       this.use = gamestart_use;
+       this.reset2 = spawnfunc_trigger_gamestart;
+
+       if(this.wait)
+       {
+               setthink(this, adaptor_think2use);
+               this.nextthink = game_starttime + this.wait;
+       }
+       else
+               InitializeEntity(this, gamestart_use_this, INITPRIO_FINDTARGET);
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/gamestart.qh b/qcsrc/common/mapobjects/trigger/gamestart.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/gravity.qc b/qcsrc/common/mapobjects/trigger/gravity.qc
new file mode 100644 (file)
index 0000000..1ac0f87
--- /dev/null
@@ -0,0 +1,111 @@
+#include "gravity.qh"
+#ifdef SVQC
+.entity trigger_gravity_check;
+void trigger_gravity_remove(entity own)
+{
+       if(own.trigger_gravity_check.owner == own)
+       {
+               UpdateCSQCProjectile(own);
+               own.gravity = own.trigger_gravity_check.gravity;
+               delete(own.trigger_gravity_check);
+       }
+       else
+               backtrace("Removing a trigger_gravity_check with no valid owner");
+       own.trigger_gravity_check = NULL;
+}
+void trigger_gravity_check_think(entity this)
+{
+       // This spawns when a player enters the gravity zone and checks if he left.
+       // Each frame, this.count is set to 2 by trigger_gravity_touch() and decreased by 1 here.
+       // It the player has left the gravity trigger, this will be allowed to reach 0 and indicate that.
+       if(this.count <= 0)
+       {
+               if(this.owner.trigger_gravity_check == this)
+                       trigger_gravity_remove(this.owner);
+               else
+                       delete(this);
+               return;
+       }
+       else
+       {
+               this.count -= 1;
+               this.nextthink = time;
+       }
+}
+
+// legacy
+void trigger_gravity_use(entity this, entity actor, entity trigger)
+{
+       this.setactive(this, ACTIVE_TOGGLE);
+}
+
+void trigger_gravity_touch(entity this, entity toucher)
+{
+       float g;
+
+       if(this.active == ACTIVE_NOT)
+               return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       g = this.gravity;
+
+       if (!(this.spawnflags & GRAVITY_STICKY))
+       {
+               if(toucher.trigger_gravity_check)
+               {
+                       if(this == toucher.trigger_gravity_check.enemy)
+                       {
+                               // same?
+                               // NOTE: see explanation in trigger_gravity_check_think
+                               toucher.trigger_gravity_check.count = 2; // gravity one more frame...
+                               return;
+                       }
+
+                       // compare prio
+                       if(this.cnt > toucher.trigger_gravity_check.enemy.cnt)
+                               trigger_gravity_remove(toucher);
+                       else
+                               return;
+               }
+               toucher.trigger_gravity_check = spawn();
+               toucher.trigger_gravity_check.enemy = this;
+               toucher.trigger_gravity_check.owner = toucher;
+               toucher.trigger_gravity_check.gravity = toucher.gravity;
+               setthink(toucher.trigger_gravity_check, trigger_gravity_check_think);
+               toucher.trigger_gravity_check.nextthink = time;
+               toucher.trigger_gravity_check.count = 2;
+               if(toucher.gravity)
+                       g *= toucher.gravity;
+       }
+
+       if (toucher.gravity != g)
+       {
+               toucher.gravity = g;
+               if(this.noise != "")
+                       _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+               UpdateCSQCProjectile(this.owner);
+       }
+}
+
+spawnfunc(trigger_gravity)
+{
+       if(this.gravity == 1)
+               return;
+
+       EXACTTRIGGER_INIT;
+       settouch(this, trigger_gravity_touch);
+       if(this.noise != "")
+               precache_sound(this.noise);
+
+       this.active = ACTIVE_ACTIVE;
+       this.setactive = generic_setactive;
+       IFTARGETED
+       {
+               // legacy use
+               this.use = trigger_gravity_use;
+               if(this.spawnflags & GRAVITY_START_DISABLED)
+                       this.active = ACTIVE_NOT;
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/gravity.qh b/qcsrc/common/mapobjects/trigger/gravity.qh
new file mode 100644 (file)
index 0000000..872f04a
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const int GRAVITY_STICKY = BIT(0); // keep gravity multiplier even after exiting the trigger_gravity
+const int GRAVITY_START_DISABLED = BIT(1);
diff --git a/qcsrc/common/mapobjects/trigger/heal.qc b/qcsrc/common/mapobjects/trigger/heal.qc
new file mode 100644 (file)
index 0000000..cfcd726
--- /dev/null
@@ -0,0 +1,65 @@
+#include "heal.qh"
+#ifdef SVQC
+.float triggerhealtime;
+void trigger_heal_touch(entity this, entity toucher)
+{
+       if (this.active != ACTIVE_ACTIVE)
+               return;
+
+       // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
+       if (toucher.iscreature)
+       {
+               if (toucher.takedamage && !IS_DEAD(toucher) && toucher.triggerhealtime < time)
+               {
+                       bool is_trigger = this.targetname == "";
+                       if(is_trigger)
+                               EXACTTRIGGER_TOUCH(this, toucher);
+                       if(this.delay > 0)
+                               toucher.triggerhealtime = time + this.delay;
+
+                       bool playthesound = (this.spawnflags & HEAL_SOUND_ALWAYS);
+                       if (toucher.health < this.max_health)
+                       {
+                               playthesound = true;
+                               toucher.health = min(toucher.health + this.health, this.max_health);
+                               toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
+                       }
+
+                       if(playthesound)
+                               _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+               }
+       }
+}
+
+void trigger_heal_use(entity this, entity actor, entity trigger)
+{
+       trigger_heal_touch(this, actor);
+}
+
+void trigger_heal_init(entity this)
+{
+       this.active = ACTIVE_ACTIVE;
+       if(!this.delay)
+               this.delay = 1;
+       if(!this.health)
+               this.health = 10;
+       if(!this.max_health)
+               this.max_health = 200; // max health topoff for field
+       if(this.noise == "")
+               this.noise = "misc/mediumhealth.wav";
+       precache_sound(this.noise);
+}
+
+spawnfunc(trigger_heal)
+{
+       EXACTTRIGGER_INIT;
+       settouch(this, trigger_heal_touch);
+       trigger_heal_init(this);
+}
+
+spawnfunc(target_heal)
+{
+       this.use = trigger_heal_use;
+       trigger_heal_init(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/heal.qh b/qcsrc/common/mapobjects/trigger/heal.qh
new file mode 100644 (file)
index 0000000..8dbeea5
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int HEAL_SOUND_ALWAYS = BIT(2);
diff --git a/qcsrc/common/mapobjects/trigger/hurt.qc b/qcsrc/common/mapobjects/trigger/hurt.qc
new file mode 100644 (file)
index 0000000..966e0cf
--- /dev/null
@@ -0,0 +1,93 @@
+#include "hurt.qh"
+#ifdef SVQC
+void trigger_hurt_use(entity this, entity actor, entity trigger)
+{
+       if(IS_PLAYER(actor))
+               this.enemy = actor;
+       else
+               this.enemy = NULL; // let's just destroy it, if taking over is too much work
+}
+
+.float triggerhurttime;
+void trigger_hurt_touch(entity this, entity toucher)
+{
+       if (this.active != ACTIVE_ACTIVE)
+               return;
+
+       if(this.team)
+               if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != toucher.team))
+                       return;
+
+       // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
+       if (toucher.iscreature)
+       {
+               if (toucher.takedamage)
+               if (toucher.triggerhurttime < time)
+               {
+                       EXACTTRIGGER_TOUCH(this, toucher);
+                       toucher.triggerhurttime = time + 1;
+
+                       entity own;
+                       own = this.enemy;
+                       if (!IS_PLAYER(own))
+                       {
+                               own = this;
+                               this.enemy = NULL; // I still hate you all
+                       }
+
+                       Damage (toucher, this, own, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, toucher.origin, '0 0 0');
+               }
+       }
+       else if(toucher.damagedbytriggers)
+       {
+               if(toucher.takedamage)
+               {
+                       EXACTTRIGGER_TOUCH(this, toucher);
+                       Damage(toucher, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, toucher.origin, '0 0 0');
+               }
+       }
+
+       return;
+}
+
+/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
+Any object touching this will be hurt
+set dmg to damage amount
+default dmg = 1000
+*/
+.entity trigger_hurt_next;
+entity trigger_hurt_last;
+entity trigger_hurt_first;
+spawnfunc(trigger_hurt)
+{
+       EXACTTRIGGER_INIT;
+       this.active = ACTIVE_ACTIVE;
+       settouch(this, trigger_hurt_touch);
+       this.use = trigger_hurt_use;
+       this.enemy = world; // I hate you all
+       if (!this.dmg)
+               this.dmg = 1000;
+       if (this.message == "")
+               this.message = "was in the wrong place";
+       if (this.message2 == "")
+               this.message2 = "was thrown into a world of hurt by";
+       // this.message = "someone like %s always gets wrongplaced";
+
+       if(!trigger_hurt_first)
+               trigger_hurt_first = this;
+       if(trigger_hurt_last)
+               trigger_hurt_last.trigger_hurt_next = this;
+       trigger_hurt_last = this;
+}
+
+bool tracebox_hits_trigger_hurt(vector start, vector e_min, vector e_max, vector end)
+{
+       entity th;
+
+       for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
+               if(tracebox_hits_box(start, e_min, e_max, end, th.absmin, th.absmax))
+                       return true;
+
+       return false;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/hurt.qh b/qcsrc/common/mapobjects/trigger/hurt.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/impulse.qc b/qcsrc/common/mapobjects/trigger/impulse.qc
new file mode 100644 (file)
index 0000000..c4e7ae2
--- /dev/null
@@ -0,0 +1,243 @@
+#include "impulse.qh"
+// targeted (directional) mode
+void trigger_impulse_touch_directional(entity this, entity toucher)
+{
+       entity targ;
+       float pushdeltatime;
+       float str;
+
+       if (this.active != ACTIVE_ACTIVE)
+               return;
+
+       if (!isPushable(toucher))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       targ = find(NULL, targetname, this.target);
+       if(!targ)
+       {
+               objerror(this, "trigger_force without a (valid) .target!\n");
+               delete(this);
+               return;
+       }
+
+       // falloff is not supported because radius is always 0 in directional mode
+       str = this.strength;
+
+       pushdeltatime = time - toucher.lastpushtime;
+       if (pushdeltatime > IMPULSE_MAX_PUSHDELTATIME)
+       {
+               pushdeltatime = 0;
+       }
+       toucher.lastpushtime = time;
+       if(!pushdeltatime)
+       {
+               return;
+       }
+
+       if(this.spawnflags & IMPULSE_DIRECTIONAL_SPEEDTARGET)
+       {
+               float addspeed = str - toucher.velocity * normalize(targ.origin - this.origin);
+               if (addspeed > 0)
+               {
+                       float accelspeed = min(IMPULSE_DIRECTIONAL_MAX_ACCEL_FACTOR * pushdeltatime * str, addspeed);
+                       toucher.velocity += accelspeed * normalize(targ.origin - this.origin);
+               }
+       }
+       else
+               toucher.velocity = toucher.velocity + normalize(targ.origin - this.origin) * str * pushdeltatime;
+
+       UNSET_ONGROUND(toucher);
+
+#ifdef SVQC
+       UpdateCSQCProjectile(toucher);
+#endif
+}
+
+// Directionless (accelerator/decelerator) mode
+void trigger_impulse_touch_accel(entity this, entity toucher)
+{
+       float pushdeltatime;
+
+       if (this.active != ACTIVE_ACTIVE)
+               return;
+
+       if (!isPushable(toucher))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       pushdeltatime = time - toucher.lastpushtime;
+       if (pushdeltatime > IMPULSE_MAX_PUSHDELTATIME)
+       {
+               pushdeltatime = 0;
+       }
+       toucher.lastpushtime = time;
+       if(!pushdeltatime)
+       {
+               return;
+       }
+
+       // div0: ticrate independent, 1 = identity (not 20)
+       toucher.velocity = toucher.velocity * (this.strength ** pushdeltatime);
+
+#ifdef SVQC
+       UpdateCSQCProjectile(toucher);
+#endif
+}
+
+// Spherical (gravity/repulsor) mode
+void trigger_impulse_touch_radial(entity this, entity toucher)
+{
+       float pushdeltatime;
+       float str;
+
+       if (this.active != ACTIVE_ACTIVE)
+               return;
+
+       if (!isPushable(toucher))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       pushdeltatime = time - toucher.lastpushtime;
+       if (pushdeltatime > IMPULSE_MAX_PUSHDELTATIME)
+       {
+               pushdeltatime = 0;
+       }
+       toucher.lastpushtime = time;
+       if(!pushdeltatime)
+       {
+               return;
+       }
+
+       setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
+
+       str = min(this.radius, vlen(this.origin - toucher.origin));
+
+       if(this.falloff == FALLOFF_LINEAR)
+               str = (1 - str / this.radius) * this.strength; // 1 in the inside
+       else if(this.falloff == FALLOFF_LINEAR_INV)
+               str = (str / this.radius) * this.strength; // 0 in the inside
+       else
+               str = this.strength;
+
+       toucher.velocity = toucher.velocity + normalize(toucher.origin - this.origin) * str * pushdeltatime;
+
+#ifdef SVQC
+       UpdateCSQCProjectile(toucher);
+#endif
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
+
+/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
+Force field
+-------- KEYS --------
+target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
+                If not, this trigger acts like a damper/accelerator field.
+
+strength : This is how much force to add in the direction of .target each second
+                  when .target is set. If not, this is how much to slow down/accelerate
+                  something cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
+
+radius   : If set, act as a spherical device rather then a linear one.
+
+falloff : 0 = none, 1 = liniar, 2 = inverted liniar
+
+-------- NOTES --------
+Use a brush textured with common/origin in the trigger entity to determine the origin of the force
+in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
+*/
+#ifdef SVQC
+bool trigger_impulse_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
+
+       WriteByte(MSG_ENTITY, this.spawnflags);
+       WriteCoord(MSG_ENTITY, this.radius);
+       WriteCoord(MSG_ENTITY, this.strength);
+       WriteByte(MSG_ENTITY, this.falloff);
+       WriteByte(MSG_ENTITY, this.active);
+
+       trigger_common_write(this, true);
+
+       return true;
+}
+
+void trigger_impulse_link(entity this)
+{
+       trigger_link(this, trigger_impulse_send);
+}
+
+spawnfunc(trigger_impulse)
+{
+       this.active = ACTIVE_ACTIVE;
+
+       trigger_init(this);
+
+       if(this.radius)
+       {
+               if(!this.strength)
+               {
+                       this.strength = IMPULSE_DEFAULT_RADIAL_STRENGTH * autocvar_g_triggerimpulse_radial_multiplier;
+               }
+               setorigin(this, this.origin);
+               setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
+               settouch(this, trigger_impulse_touch_radial);
+       }
+       else
+       {
+               if(this.target)
+               {
+                       if(!this.strength)
+                       {
+                               this.strength = IMPULSE_DEFAULT_DIRECTIONAL_STRENGTH * autocvar_g_triggerimpulse_directional_multiplier;
+                       }
+                       settouch(this, trigger_impulse_touch_directional);
+               }
+               else
+               {
+                       if(!this.strength)
+                       {
+                               this.strength = IMPULSE_DEFAULT_ACCEL_STRENGTH;
+                       }
+                       this.strength = (this.strength ** autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
+                       settouch(this, trigger_impulse_touch_accel);
+               }
+       }
+
+       trigger_impulse_link(this);
+}
+#elif defined(CSQC)
+NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
+{
+       this.spawnflags = ReadByte();
+       this.radius = ReadCoord();
+       this.strength = ReadCoord();
+       this.falloff = ReadByte();
+       this.active = ReadByte();
+
+       trigger_common_read(this, true);
+       return = true;
+
+       this.classname = "trigger_impulse";
+       this.solid = SOLID_TRIGGER;
+       this.entremove = trigger_remove_generic;
+       this.move_time = time;
+
+       if (this.radius)
+       {
+               settouch(this, trigger_impulse_touch_radial);
+       }
+       else if (this.target)
+       {
+               settouch(this, trigger_impulse_touch_directional);
+       }
+       else
+       {
+               settouch(this, trigger_impulse_touch_accel);
+       }
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/impulse.qh b/qcsrc/common/mapobjects/trigger/impulse.qh
new file mode 100644 (file)
index 0000000..e86de4a
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+// tZorks trigger impulse / gravity
+.float radius;
+.int falloff;
+.float strength;
+.float lastpushtime;
+
+const int FALLOFF_NO = 0;
+const int FALLOFF_LINEAR = 1;
+const int FALLOFF_LINEAR_INV = 2;
+
+const int IMPULSE_DIRECTIONAL_SPEEDTARGET = BIT(6);
+
+const float IMPULSE_DEFAULT_RADIAL_STRENGTH = 2000;
+const float IMPULSE_DEFAULT_DIRECTIONAL_STRENGTH = 950;
+const float IMPULSE_DEFAULT_ACCEL_STRENGTH = 0.9;
+
+const float IMPULSE_MAX_PUSHDELTATIME = 0.15;
+
+const float IMPULSE_DIRECTIONAL_MAX_ACCEL_FACTOR = 8;
diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qc b/qcsrc/common/mapobjects/trigger/jumppads.qc
new file mode 100644 (file)
index 0000000..5ffdf2d
--- /dev/null
@@ -0,0 +1,676 @@
+#include "jumppads.qh"
+// TODO: split target_push and put it in the target folder
+#ifdef SVQC
+#include <common/physics/movetypes/movetypes.qh>
+
+void trigger_push_use(entity this, entity actor, entity trigger)
+{
+       if(teamplay)
+       {
+               this.team = actor.team;
+               this.SendFlags |= SF_TRIGGER_UPDATE;
+       }
+}
+#endif
+
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH)
+REGISTER_NET_LINKED(ENT_CLIENT_TARGET_PUSH)
+
+/*
+       trigger_push_calculatevelocity
+
+       Arguments:
+         org - origin of the object which is to be pushed
+         tgt - target entity (can be either a point or a model entity; if it is
+               the latter, its midpoint is used)
+         ht  - jump height, measured from the higher one of org and tgt's midpoint
+         pushed_entity - object that is to be pushed
+
+       Returns: velocity for the jump
+ */
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity)
+{
+       float grav, sdist, zdist, vs, vz, jumpheight;
+       vector sdir, torg;
+
+       torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
+
+       grav = PHYS_GRAVITY(NULL);
+       if(pushed_entity && PHYS_ENTGRAVITY(pushed_entity))
+               grav *= PHYS_ENTGRAVITY(pushed_entity);
+
+       zdist = torg.z - org.z;
+       sdist = vlen(torg - org - zdist * '0 0 1');
+       sdir = normalize(torg - org - zdist * '0 0 1');
+
+       // how high do we need to push the player?
+       jumpheight = fabs(ht);
+       if(zdist > 0)
+               jumpheight = jumpheight + zdist;
+
+       /*
+               STOP.
+
+               You will not understand the following equations anyway...
+               But here is what I did to get them.
+
+               I used the functions
+
+                 s(t) = t * vs
+                 z(t) = t * vz - 1/2 grav t^2
+
+               and solved for:
+
+                 s(ti) = sdist
+                 z(ti) = zdist
+                 max(z, ti) = jumpheight
+
+               From these three equations, you will find the three parameters vs, vz
+               and ti.
+        */
+
+       // push him so high...
+       vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
+
+       // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
+       if(ht < 0)
+               if(zdist < 0)
+                       vz = -vz;
+
+       vector solution;
+       solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
+       // ALWAYS solvable because jumpheight >= zdist
+       if(!solution.z)
+               solution_y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
+       if(zdist == 0)
+               solution_x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
+
+       float flighttime;
+       if(zdist < 0)
+       {
+               // down-jump
+               if(ht < 0)
+               {
+                       // almost straight line type
+                       // jump apex is before the jump
+                       // we must take the larger one
+                       flighttime = solution.y;
+               }
+               else
+               {
+                       // regular jump
+                       // jump apex is during the jump
+                       // we must take the larger one too
+                       flighttime = solution.y;
+               }
+       }
+       else
+       {
+               // up-jump
+               if(ht < 0)
+               {
+                       // almost straight line type
+                       // jump apex is after the jump
+                       // we must take the smaller one
+                       flighttime = solution.x;
+               }
+               else
+               {
+                       // regular jump
+                       // jump apex is during the jump
+                       // we must take the larger one
+                       flighttime = solution.y;
+               }
+       }
+       vs = sdist / flighttime;
+
+       // finally calculate the velocity
+       return sdir * vs + '0 0 1' * vz;
+}
+
+bool jumppad_push(entity this, entity targ)
+{
+       if (!isPushable(targ))
+               return false;
+
+       if(this.enemy)
+       {
+               targ.velocity = trigger_push_calculatevelocity(targ.origin, this.enemy, this.height, targ);
+       }
+       else if(this.target && this.target != "")
+       {
+               entity e;
+               RandomSelection_Init();
+               for(e = NULL; (e = find(e, targetname, this.target)); )
+               {
+                       if(e.cnt)
+                               RandomSelection_AddEnt(e, e.cnt, 1);
+                       else
+                               RandomSelection_AddEnt(e, 1, 1);
+               }
+               targ.velocity = trigger_push_calculatevelocity(targ.origin, RandomSelection_chosen_ent, this.height, targ);
+       }
+       else
+       {
+               targ.velocity = this.movedir;
+       }
+
+       UNSET_ONGROUND(targ);
+
+#ifdef CSQC
+       if (targ.flags & FL_PROJECTILE)
+       {
+               targ.angles = vectoangles (targ.velocity);
+               switch(targ.move_movetype)
+               {
+                       case MOVETYPE_FLY:
+                               set_movetype(targ, MOVETYPE_TOSS);
+                               targ.gravity = 1;
+                               break;
+                       case MOVETYPE_BOUNCEMISSILE:
+                               set_movetype(targ, MOVETYPE_BOUNCE);
+                               targ.gravity = 1;
+                               break;
+               }
+       }
+#endif
+
+#ifdef SVQC
+       if (IS_PLAYER(targ))
+       {
+               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+               targ.oldvelocity = targ.velocity;
+
+               if(this.pushltime < time)  // prevent "snorring" sound when a player hits the jumppad more than once
+               {
+                       // flash when activated
+                       Send_Effect(EFFECT_JUMPPAD, targ.origin, targ.velocity, 1);
+                       _sound (targ, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+                       this.pushltime = time + 0.2;
+               }
+               if(IS_REAL_CLIENT(targ) || IS_BOT_CLIENT(targ))
+               {
+                       bool found = false;
+                       for(int i = 0; i < targ.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
+                               if(targ.(jumppadsused[i]) == this)
+                                       found = true;
+                       if(!found)
+                       {
+                               targ.(jumppadsused[targ.jumppadcount % NUM_JUMPPADSUSED]) = this;
+                               targ.jumppadcount = targ.jumppadcount + 1;
+                       }
+
+                       if(IS_REAL_CLIENT(targ))
+                       {
+                               if(this.message)
+                                       centerprint(targ, this.message);
+                       }
+                       else
+                       {
+                               targ.lastteleporttime = time;
+                               targ.lastteleport_origin = targ.origin;
+                       }
+
+                       if (!IS_DEAD(targ))
+                               animdecide_setaction(targ, ANIMACTION_JUMP, true);
+               }
+               else
+                       targ.jumppadcount = 1;
+
+               // reset tracking of who pushed you into a hazard (for kill credit)
+               targ.pushltime = 0;
+               targ.istypefrag = 0;
+       }
+
+       if(this.enemy.target)
+               SUB_UseTargets(this.enemy, targ, this);
+
+       if (targ.flags & FL_PROJECTILE)
+       {
+               targ.angles = vectoangles (targ.velocity);
+               targ.com_phys_gravity_factor = 1;
+               switch(targ.move_movetype)
+               {
+                       case MOVETYPE_FLY:
+                               set_movetype(targ, MOVETYPE_TOSS);
+                               targ.gravity = 1;
+                               break;
+                       case MOVETYPE_BOUNCEMISSILE:
+                               set_movetype(targ, MOVETYPE_BOUNCE);
+                               targ.gravity = 1;
+                               break;
+               }
+               UpdateCSQCProjectile(targ);
+       }
+#endif
+
+       return true;
+}
+
+void trigger_push_touch(entity this, entity toucher)
+{
+       if (this.active == ACTIVE_NOT)
+               return;
+
+       if(this.team)
+               if(((this.spawnflags & INVERT_TEAMS) == 0) == (DIFF_TEAM(this, toucher)))
+                       return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       noref bool success = jumppad_push(this, toucher);
+
+#ifdef SVQC
+       if (success && (this.spawnflags & PUSH_ONCE))
+       {
+               settouch(this, func_null);
+               setthink(this, SUB_Remove);
+               this.nextthink = time;
+       }
+#endif
+}
+
+#ifdef SVQC
+void trigger_push_link(entity this);
+void trigger_push_updatelink(entity this);
+bool trigger_push_testorigin(entity tracetest_ent, entity targ, entity jp, vector org)
+{
+       setorigin(tracetest_ent, org);
+       tracetoss(tracetest_ent, tracetest_ent);
+       if(trace_startsolid)
+               return false;
+
+       if (!jp.height)
+       {
+               // since tracetoss starting from jumppad's origin often fails when target
+               // is very close to real destination, start it directly from target's
+               // origin instead
+               vector ofs = '0 0 0';
+               if (vdist(vec2(tracetest_ent.velocity), <, autocvar_sv_maxspeed))
+                       ofs = stepheightvec;
+
+               tracetest_ent.velocity.z = 0;
+               setorigin(tracetest_ent, targ.origin + ofs);
+               tracetoss(tracetest_ent, tracetest_ent);
+               if (trace_startsolid && ofs.z)
+               {
+                       setorigin(tracetest_ent, targ.origin + ofs / 2);
+                       tracetoss(tracetest_ent, tracetest_ent);
+                       if (trace_startsolid && ofs.z)
+                       {
+                               setorigin(tracetest_ent, targ.origin);
+                               tracetoss(tracetest_ent, tracetest_ent);
+                               if (trace_startsolid)
+                                       return false;
+                       }
+               }
+       }
+       tracebox(trace_endpos, tracetest_ent.mins, tracetest_ent.maxs, trace_endpos - eZ * 1500, true, tracetest_ent);
+       return true;
+}
+
+bool trigger_push_testorigin_for_item(entity tracetest_ent, entity item, vector org)
+{
+       setorigin(tracetest_ent, org);
+       tracetoss(tracetest_ent, tracetest_ent);
+
+       if(trace_startsolid)
+               return false;
+       if (trace_ent == item)
+               return true;
+
+       tracebox(trace_endpos, tracetest_ent.mins, tracetest_ent.maxs, trace_endpos - eZ * 1500, true, tracetest_ent);
+
+       if (trace_ent == item)
+               return true;
+
+       return false;
+}
+#endif
+
+/// if (item != NULL) returns true if the item can be reached by using this jumppad, false otherwise
+/// if (item == NULL) tests jumppad's trajectory and eventually spawns waypoints for it (return value doesn't matter)
+bool trigger_push_test(entity this, entity item)
+{
+       // first calculate a typical start point for the jump
+       vector org = (this.absmin + this.absmax) * 0.5;
+       org.z = this.absmax.z - PL_MIN_CONST.z - 7;
+
+       if (this.target)
+       {
+               int n = 0;
+#ifdef SVQC
+               vector vel = '0 0 0';
+#endif
+               for(entity t = NULL; (t = find(t, targetname, this.target)); )
+               {
+                       ++n;
+#ifdef SVQC
+                       if(t.move_movetype != MOVETYPE_NONE)
+                               continue;
+
+                       entity e = spawn();
+                       setsize(e, PL_MIN_CONST, PL_MAX_CONST);
+                       e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+                       e.velocity = trigger_push_calculatevelocity(org, t, this.height, e);
+
+                       vel = e.velocity;
+                       vector best_target = '0 0 0';
+                       vector best_org = '0 0 0';
+                       vector best_vel = '0 0 0';
+                       bool valid_best_target = false;
+                       if (item)
+                       {
+                               if (!trigger_push_testorigin_for_item(e, item, org))
+                               {
+                                       delete(e);
+                                       return false;
+                               }
+                       }
+                       else
+                       {
+                               if (trigger_push_testorigin(e, t, this, org))
+                               {
+                                       best_target = trace_endpos;
+                                       best_org = org;
+                                       best_vel = e.velocity;
+                                       valid_best_target = true;
+                               }
+                       }
+
+                       vector new_org;
+                       vector dist = t.origin - org;
+                       if (dist.x || dist.y) // if not perfectly vertical
+                       {
+                               // test trajectory with different starting points, sometimes the trajectory
+                               // starting from the jumppad origin can't reach the real destination
+                               // and destination waypoint ends up near the jumppad itself
+                               vector flatdir = normalize(dist - eZ * dist.z);
+                               vector ofs = flatdir * 0.5 * min(fabs(this.absmax.x - this.absmin.x), fabs(this.absmax.y - this.absmin.y));
+                               new_org = org + ofs;
+
+                               LABEL(new_test)
+                               e.velocity = trigger_push_calculatevelocity(new_org, t, this.height, e);
+                               if (item)
+                               {
+                                       if (!trigger_push_testorigin_for_item(e, item, new_org))
+                                       {
+                                               delete(e);
+                                               return false;
+                                       }
+                               }
+                               else
+                               {
+                                       vel = e.velocity;
+                                       if (vdist(vec2(e.velocity), <, autocvar_sv_maxspeed))
+                                               e.velocity = autocvar_sv_maxspeed * flatdir;
+                                       if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50))
+                                       {
+                                               best_target = trace_endpos;
+                                               best_org = new_org;
+                                               best_vel = vel;
+                                               valid_best_target = true;
+                                       }
+                               }
+                               if (ofs && new_org != org - ofs)
+                               {
+                                       new_org = org - ofs;
+                                       goto new_test;
+                               }
+                       }
+
+                       if (item)
+                       {
+                               delete(e);
+                               return true;
+                       }
+
+                       if (valid_best_target)
+                       {
+                               if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, best_target + PL_MIN_CONST, best_target + PL_MAX_CONST)))
+                               {
+                                       float velxy = vlen(vec2(best_vel));
+                                       float cost = vlen(vec2(t.origin - best_org)) / velxy;
+                                       if(velxy < autocvar_sv_maxspeed)
+                                               velxy = autocvar_sv_maxspeed;
+                                       cost += vlen(vec2(best_target - t.origin)) / velxy;
+                                       waypoint_spawnforteleporter(this, best_target, cost, e);
+                               }
+                       }
+                       delete(e);
+#endif
+               }
+
+               if(item)
+                       return false;
+
+               if(!n)
+               {
+                       // no dest!
+#ifdef SVQC
+                       objerror (this, "Jumppad with nonexistant target");
+#endif
+                       return false;
+               }
+               else if(n == 1)
+               {
+                       // exactly one dest - bots love that
+                       this.enemy = find(NULL, targetname, this.target);
+               }
+               else
+               {
+                       // have to use random selection every single time
+                       this.enemy = NULL;
+               }
+       }
+#ifdef SVQC
+       else
+       {
+               entity e = spawn();
+               setsize(e, PL_MIN_CONST, PL_MAX_CONST);
+               e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+               setorigin(e, org);
+               e.velocity = this.movedir;
+               tracetoss(e, e);
+               if (item)
+               {
+                       bool r = (trace_ent == item);
+                       delete(e);
+                       return r;
+               }
+               if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, trace_endpos + PL_MIN_CONST, trace_endpos + PL_MAX_CONST)))
+                       waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity), e);
+               delete(e);
+       }
+
+       defer(this, 0.1, trigger_push_updatelink);
+#endif
+       return true;
+}
+
+void trigger_push_findtarget(entity this)
+{
+       trigger_push_test(this, NULL);
+}
+
+#ifdef SVQC
+float trigger_push_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
+
+       WriteByte(MSG_ENTITY, this.team);
+       WriteInt24_t(MSG_ENTITY, this.spawnflags);
+       WriteByte(MSG_ENTITY, this.active);
+       WriteCoord(MSG_ENTITY, this.height);
+
+       WriteVector(MSG_ENTITY, this.movedir);
+
+       trigger_common_write(this, true);
+
+       return true;
+}
+
+void trigger_push_updatelink(entity this)
+{
+       this.SendFlags |= SF_TRIGGER_INIT;
+}
+
+void trigger_push_link(entity this)
+{
+       trigger_link(this, trigger_push_send);
+}
+
+/*
+ * ENTITY PARAMETERS:
+ *
+ *   target:  target of jump
+ *   height:  the absolute value is the height of the highest point of the jump
+ *            trajectory above the higher one of the player and the target.
+ *            the sign indicates whether the highest point is INSIDE (positive)
+ *            or OUTSIDE (negative) of the jump trajectory. General rule: use
+ *            positive values for targets mounted on the floor, and use negative
+ *            values to target a point on the ceiling.
+ *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
+ */
+spawnfunc(trigger_push)
+{
+       SetMovedir(this);
+
+       trigger_init(this);
+
+       this.active = ACTIVE_ACTIVE;
+       this.use = trigger_push_use;
+       settouch(this, trigger_push_touch);
+
+       // normal push setup
+       if (!this.speed)
+               this.speed = 1000;
+       this.movedir = this.movedir * this.speed * 10;
+
+       if (!this.noise)
+               this.noise = "misc/jumppad.wav";
+       precache_sound (this.noise);
+
+       trigger_push_link(this); // link it now
+
+       IL_PUSH(g_jumppads, this);
+
+       // this must be called to spawn the teleport waypoints for bots
+       InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
+}
+
+
+bool target_push_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
+
+       WriteByte(MSG_ENTITY, this.cnt);
+       WriteString(MSG_ENTITY, this.targetname);
+       WriteVector(MSG_ENTITY, this.origin);
+
+       WriteAngle(MSG_ENTITY, this.angles_x);
+       WriteAngle(MSG_ENTITY, this.angles_y);
+       WriteAngle(MSG_ENTITY, this.angles_z);
+
+       return true;
+}
+
+void target_push_use(entity this, entity actor, entity trigger)
+{
+       if(trigger.classname == "trigger_push" || trigger == this)
+               return; // WTF, why is this a thing
+
+       jumppad_push(this, actor);
+}
+
+void target_push_link(entity this)
+{
+       BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
+       Net_LinkEntity(this, false, 0, target_push_send);
+       //this.SendFlags |= 1; // update
+}
+
+void target_push_init(entity this)
+{
+       this.mangle = this.angles;
+       setorigin(this, this.origin);
+       target_push_link(this);
+}
+
+void target_push_init2(entity this)
+{
+       if(this.target && this.target != "") // we have an old style pusher!
+       {
+               InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
+               this.use = target_push_use;
+       }
+
+       target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
+}
+
+spawnfunc(target_push)
+{
+       target_push_init2(this);
+}
+
+spawnfunc(info_notnull)
+{
+       target_push_init(this);
+}
+spawnfunc(target_position)
+{
+       target_push_init(this);
+}
+
+#elif defined(CSQC)
+
+NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
+{
+       this.classname = "jumppad";
+       int mytm = ReadByte();
+       if(mytm)
+       {
+               this.team = mytm - 1;
+       }
+       this.spawnflags = ReadInt24_t();
+       this.active = ReadByte();
+       this.height = ReadCoord();
+
+       this.movedir = ReadVector();
+
+       trigger_common_read(this, true);
+
+       this.entremove = trigger_remove_generic;
+       this.solid = SOLID_TRIGGER;
+       settouch(this, trigger_push_touch);
+       this.move_time = time;
+       defer(this, 0.25, trigger_push_findtarget);
+
+       return true;
+}
+
+void target_push_remove(entity this)
+{
+       // strfree(this.classname);
+       strfree(this.targetname);
+}
+
+NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
+{
+       this.classname = "push_target";
+       this.cnt = ReadByte();
+       this.targetname = strzone(ReadString());
+       this.origin = ReadVector();
+
+       this.angles_x = ReadAngle();
+       this.angles_y = ReadAngle();
+       this.angles_z = ReadAngle();
+
+       return = true;
+
+       setorigin(this, this.origin);
+
+       this.drawmask = MASK_NORMAL;
+       this.entremove = target_push_remove;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/jumppads.qh b/qcsrc/common/mapobjects/trigger/jumppads.qh
new file mode 100644 (file)
index 0000000..cd6adec
--- /dev/null
@@ -0,0 +1,63 @@
+#pragma once
+
+
+const int PUSH_ONCE = BIT(0); // legacy, deactivate with relay instead
+const int PUSH_SILENT = BIT(1); // not used?
+
+IntrusiveList g_jumppads;
+STATIC_INIT(g_jumppads) { g_jumppads = IL_NEW(); }
+
+.float pushltime;
+.float istypefrag;
+.float height;
+
+const int NUM_JUMPPADSUSED = 3;
+.float jumppadcount;
+.entity jumppadsused[NUM_JUMPPADSUSED];
+
+#ifdef SVQC
+void SUB_UseTargets(entity this, entity actor, entity trigger);
+void trigger_push_use(entity this, entity actor, entity trigger);
+bool trigger_push_testorigin(entity tracetest_ent, entity targ, entity jp, vector org);
+bool trigger_push_testorigin_for_item(entity tracetest_ent, entity item, vector org);
+#endif
+
+/*
+       trigger_push_calculatevelocity
+
+       Arguments:
+         org - origin of the object which is to be pushed
+         tgt - target entity (can be either a point or a model entity; if it is
+               the latter, its midpoint is used)
+         ht  - jump height, measured from the higher one of org and tgt's midpoint
+         pushed_entity - object that is to be pushed
+
+       Returns: velocity for the jump
+ */
+vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity);
+
+void trigger_push_touch(entity this, entity toucher);
+
+.vector dest;
+bool trigger_push_test(entity this, entity item);
+void trigger_push_findtarget(entity this);
+
+/*
+ * ENTITY PARAMETERS:
+ *
+ *   target:  target of jump
+ *   height:  the absolute value is the height of the highest point of the jump
+ *            trajectory above the higher one of the player and the target.
+ *            the sign indicates whether the highest point is INSIDE (positive)
+ *            or OUTSIDE (negative) of the jump trajectory. General rule: use
+ *            positive values for targets mounted on the floor, and use negative
+ *            values to target a point on the ceiling.
+ *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
+ */
+#ifdef SVQC
+spawnfunc(trigger_push);
+
+spawnfunc(target_push);
+spawnfunc(info_notnull);
+spawnfunc(target_position);
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/keylock.qc b/qcsrc/common/mapobjects/trigger/keylock.qc
new file mode 100644 (file)
index 0000000..67db144
--- /dev/null
@@ -0,0 +1,187 @@
+#include "keylock.qh"
+/**
+ * trigger given targets
+ */
+void trigger_keylock_trigger(entity this, entity actor, string s)
+{
+       for(entity t = NULL; (t = find(t, targetname, s)); )
+               if(t.use)
+                       t.use(t, actor, this);
+}
+
+/**
+ * kill killtarget of trigger keylock.
+ */
+void trigger_keylock_kill(string s)
+{
+       entity t;
+       for(t = NULL; (t = find(t, targetname, s)); )
+               delete(t);
+}
+
+void trigger_keylock_touch(entity this, entity toucher)
+{
+       bool key_used = false;
+       bool started_delay = false;
+
+       // only player may trigger the lock
+       if(!IS_PLAYER(toucher))
+               return;
+
+       // check silver key
+       if(this.itemkeys)
+               key_used = item_keys_usekey(this, toucher);
+
+       if(this.itemkeys)
+       {
+#ifdef SVQC
+               // at least one of the keys is missing
+               if(key_used)
+               {
+                       // one or more keys were given, but others are still missing!
+                       play2(toucher, this.noise1);
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(this.itemkeys));
+                       toucher.key_door_messagetime = time + 2;
+               }
+               else if(toucher.key_door_messagetime <= time)
+               {
+                       // no keys were given
+                       play2(toucher, this.noise2);
+                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(this.itemkeys));
+                       toucher.key_door_messagetime = time + 2;
+               }
+#endif
+
+               // trigger target2
+               if(this.delay <= time || started_delay == true)
+               if(this.target2)
+               {
+                       trigger_keylock_trigger(this, toucher, this.target2);
+                       started_delay = true;
+                       this.delay = time + this.wait;
+               }
+       }
+       else
+       {
+#ifdef SVQC
+               // all keys were given!
+               play2(toucher, this.noise);
+               centerprint(toucher, this.message);
+#endif
+
+               if(this.target)
+                       trigger_keylock_trigger(this, toucher, this.target);
+
+               if(this.killtarget)
+                       trigger_keylock_kill(this.killtarget);
+
+               delete(this);
+       }
+
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_KEYLOCK)
+
+#ifdef SVQC
+bool trigger_keylock_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
+
+       WriteInt24_t(MSG_ENTITY, this.itemkeys);
+       WriteByte(MSG_ENTITY, this.height);
+
+       trigger_common_write(this, true);
+
+       return true;
+}
+
+void trigger_keylock_link(entity this)
+{
+       // uncomment to network keylocks
+       //Net_LinkEntity(this, false, 0, trigger_keylock_send);
+}
+
+/*QUAKED trigger_keylock (.0 .5 .8) ?
+Keylock trigger.  Must target other entities.
+This trigger will trigger target entities when all required keys are provided.
+-------- KEYS --------
+itemkeys: A bit field with key IDs that are needed to open this lock.
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default)
+target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger
+target2: trigger all entities with this targetname when triggered without giving it all the required keys.
+killtarget: remove all entities with this targetname when triggered with all the needed keys.
+message: print this message to the player who activated the trigger when all needed keys have been given.
+message2: print this message to the player who activated the trigger when not all of the needed keys have been given.
+noise: sound to play when lock gets unlocked (default: see sounds)
+noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav)
+noise2: sound to play when a key is missing (default: misc/talk.wav)
+wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4.
+---------NOTES----------
+If spawned without any key specified in itemkeys, this trigger will display an error and remove itself.
+message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone.
+*/
+spawnfunc(trigger_keylock)
+{
+       if(!this.itemkeys) { delete(this); return; }
+
+       // set unlocked message
+       if(this.message == "")
+               this.message = "Unlocked!";
+
+       // set default unlock noise
+       if(this.noise == "")
+       {
+               if(this.sounds == 1)
+                       this.noise = "misc/secret.wav";
+               else if(this.sounds == 2)
+                       this.noise = strzone(SND(TALK));
+               else //if (this.sounds == 3) {
+                       this.noise = "misc/trigger1.wav";
+       }
+
+       // set default use key sound
+       if(this.noise1 == "")
+               this.noise1 = "misc/decreasevalue.wav";
+
+       // set closed sourd
+       if(this.noise2 == "")
+               this.noise2 = SND(TALK);
+
+       // delay between triggering message2 and trigger2
+       if(!this.wait) { this.wait = 5; }
+
+       // precache sounds
+       precache_sound(this.noise);
+       precache_sound(this.noise1);
+       precache_sound(this.noise2);
+
+       EXACTTRIGGER_INIT;
+
+       settouch(this, trigger_keylock_touch);
+
+       trigger_keylock_link(this);
+}
+#elif defined(CSQC)
+void keylock_remove(entity this)
+{
+       strfree(this.target);
+       strfree(this.target2);
+       strfree(this.target3);
+       strfree(this.target4);
+       strfree(this.killtarget);
+       strfree(this.targetname);
+}
+
+NET_HANDLE(ENT_CLIENT_KEYLOCK, bool isnew)
+{
+       this.itemkeys = ReadInt24_t();
+       this.height = ReadByte();
+
+       trigger_common_read(this, true);
+
+       return = true;
+
+       this.classname = "trigger_keylock";
+       this.entremove = keylock_remove;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/keylock.qh b/qcsrc/common/mapobjects/trigger/keylock.qh
new file mode 100644 (file)
index 0000000..904c3fa
--- /dev/null
@@ -0,0 +1,10 @@
+#pragma once
+
+#ifdef CSQC
+bool item_keys_usekey(entity l, entity p)
+{
+       int valid = (l.itemkeys & p.itemkeys); // TODO: itemkeys isn't networked or anything!
+       l.itemkeys &= ~valid; // only some of the needed keys were given
+       return valid != 0;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/magicear.qc b/qcsrc/common/mapobjects/trigger/magicear.qc
new file mode 100644 (file)
index 0000000..16118cb
--- /dev/null
@@ -0,0 +1,200 @@
+#include "magicear.qh"
+#ifdef SVQC
+float magicear_matched;
+float W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
+string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
+{
+       float domatch, dotrigger, matchstart, l;
+       string s, msg;
+       string savemessage;
+
+       magicear_matched = false;
+
+       dotrigger = ((IS_PLAYER(source)) && (!IS_DEAD(source)) && ((ear.radius == 0) || (vdist(source.origin - ear.origin, <=, ear.radius))));
+       domatch = ((ear.spawnflags & MAGICEAR_REPLACE_OUTSIDE) || dotrigger);
+
+       if (!domatch)
+               return msgin;
+
+       if (!msgin)
+       {
+               // we are in TUBA mode!
+               if (!(ear.spawnflags & MAGICEAR_TUBA))
+                       return msgin;
+
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       if(!W_Tuba_HasPlayed(source, weaponentity, ear.message, ear.movedir_x, !(ear.spawnflags & MAGICEAR_TUBA_EXACTPITCH), ear.movedir_y, ear.movedir_z))
+                               return msgin;
+               }
+
+               magicear_matched = true;
+
+               if(dotrigger)
+               {
+                       savemessage = ear.message;
+                       ear.message = string_null;
+                       SUB_UseTargets(ear, source, NULL);
+                       ear.message = savemessage;
+               }
+
+               if(ear.netname != "")
+                       return ear.netname;
+
+               return msgin;
+       }
+
+       if(ear.spawnflags & MAGICEAR_TUBA) // ENOTUBA
+               return msgin;
+
+       if(privatesay)
+       {
+               if(ear.spawnflags & MAGICEAR_IGNORE_TELL)
+                       return msgin;
+       }
+       else
+       {
+               if(!teamsay)
+                       if(ear.spawnflags & MAGICEAR_IGNORE_SAY)
+                               return msgin;
+               if(teamsay > 0)
+                       if(ear.spawnflags & MAGICEAR_IGNORE_TEAMSAY)
+                               return msgin;
+               if(teamsay < 0)
+                       if(ear.spawnflags & MAGICEAR_IGNORE_INVALIDTELL)
+                               return msgin;
+       }
+
+       matchstart = -1;
+       l = strlen(ear.message);
+
+       if(ear.spawnflags & MAGICEAR_NODECOLORIZE)
+               msg = msgin;
+       else
+               msg = strdecolorize(msgin);
+
+       if(substring(ear.message, 0, 1) == "*")
+       {
+               if(substring(ear.message, -1, 1) == "*")
+               {
+                       // two wildcards
+                       // as we need multi-replacement here...
+                       s = substring(ear.message, 1, -2);
+                       l -= 2;
+                       if(strstrofs(msg, s, 0) >= 0)
+                               matchstart = -2; // we use strreplace on s
+               }
+               else
+               {
+                       // match at start
+                       s = substring(ear.message, 1, -1);
+                       l -= 1;
+                       if(substring(msg, -l, l) == s)
+                               matchstart = strlen(msg) - l;
+               }
+       }
+       else
+       {
+               if(substring(ear.message, -1, 1) == "*")
+               {
+                       // match at end
+                       s = substring(ear.message, 0, -2);
+                       l -= 1;
+                       if(substring(msg, 0, l) == s)
+                               matchstart = 0;
+               }
+               else
+               {
+                       // full match
+                       s = ear.message;
+                       if(msg == ear.message)
+                               matchstart = 0;
+               }
+       }
+
+       if(matchstart == -1) // no match
+               return msgin;
+
+       magicear_matched = true;
+
+       if(dotrigger)
+       {
+               savemessage = ear.message;
+               ear.message = string_null;
+               SUB_UseTargets(ear, source, NULL);
+               ear.message = savemessage;
+       }
+
+       if(ear.spawnflags & MAGICEAR_REPLACE_WHOLE_MESSAGE)
+       {
+               return ear.netname;
+       }
+       else if(ear.netname != "")
+       {
+               if(matchstart < 0)
+                       return strreplace(s, ear.netname, msg);
+               else
+                       return strcat(
+                               substring(msg, 0, matchstart),
+                               ear.netname,
+                               substring(msg, matchstart + l, -1)
+                       );
+       }
+       else
+               return msgin;
+}
+
+entity magicears;
+string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
+{
+       entity ear;
+       string msgout;
+       for(ear = magicears; ear; ear = ear.enemy)
+       {
+               msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin);
+               if(!(ear.spawnflags & MAGICEAR_CONTINUE))
+               if(magicear_matched)
+                       return msgout;
+               msgin = msgout;
+       }
+       return msgin;
+}
+
+spawnfunc(trigger_magicear)
+{
+       this.enemy = magicears;
+       magicears = this;
+
+       // actually handled in "say" processing
+       // spawnflags:
+       //    1 = ignore say
+       //    2 = ignore teamsay
+       //    4 = ignore tell
+       //    8 = ignore tell to unknown player
+       //   16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
+       //   32 = perform the replacement even if outside the radius or dead
+       //   64 = continue replacing/triggering even if this one matched
+       //  128 = don't decolorize message before matching
+       //  256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
+       //  512 = tuba notes must be exact right pitch, no transposing
+       // message: either
+       //   *pattern*
+       // or
+       //   *pattern
+       // or
+       //   pattern*
+       // or
+       //   pattern
+       // netname:
+       //   if set, replacement for the matched text
+       // radius:
+       //   "hearing distance"
+       // target:
+       //   what to trigger
+       // movedir:
+       //   for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
+
+       this.movedir_x -= 1; // map to tuba instrument numbers
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/magicear.qh b/qcsrc/common/mapobjects/trigger/magicear.qh
new file mode 100644 (file)
index 0000000..4e70586
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+
+const int MAGICEAR_IGNORE_SAY = BIT(0);
+const int MAGICEAR_IGNORE_TEAMSAY = BIT(1);
+const int MAGICEAR_IGNORE_TELL = BIT(2);
+const int MAGICEAR_IGNORE_INVALIDTELL = BIT(3);
+const int MAGICEAR_REPLACE_WHOLE_MESSAGE = BIT(4);
+const int MAGICEAR_REPLACE_OUTSIDE = BIT(5);
+const int MAGICEAR_CONTINUE = BIT(6);
+const int MAGICEAR_NODECOLORIZE = BIT(7);
+const int MAGICEAR_TUBA = BIT(8);
+const int MAGICEAR_TUBA_EXACTPITCH = BIT(9);
diff --git a/qcsrc/common/mapobjects/trigger/monoflop.qc b/qcsrc/common/mapobjects/trigger/monoflop.qc
new file mode 100644 (file)
index 0000000..0c960ba
--- /dev/null
@@ -0,0 +1,49 @@
+#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"
+*/
+void monoflop_use(entity this, entity actor, entity trigger)
+{
+       this.nextthink = time + this.wait;
+       this.enemy = actor;
+       if(this.state)
+               return;
+       this.state = 1;
+       SUB_UseTargets(this, actor, trigger);
+}
+void monoflop_fixed_use(entity this, entity actor, entity trigger)
+{
+       if(this.state)
+               return;
+       this.nextthink = time + this.wait;
+       this.state = 1;
+       this.enemy = actor;
+       SUB_UseTargets(this, actor, trigger);
+}
+
+void monoflop_think(entity this)
+{
+       this.state = 0;
+       SUB_UseTargets(this, this.enemy, NULL);
+}
+
+void monoflop_reset(entity this)
+{
+       this.state = 0;
+       this.nextthink = 0;
+}
+
+spawnfunc(trigger_monoflop)
+{
+       if(!this.wait)
+               this.wait = 1;
+       if(this.spawnflags & MONOFLOP_FIXED)
+               this.use = monoflop_fixed_use;
+       else
+               this.use = monoflop_use;
+       setthink(this, monoflop_think);
+       this.state = 0;
+       this.reset = monoflop_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/monoflop.qh b/qcsrc/common/mapobjects/trigger/monoflop.qh
new file mode 100644 (file)
index 0000000..c64dffd
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int MONOFLOP_FIXED = BIT(0);
diff --git a/qcsrc/common/mapobjects/trigger/multi.qc b/qcsrc/common/mapobjects/trigger/multi.qc
new file mode 100644 (file)
index 0000000..accfbe8
--- /dev/null
@@ -0,0 +1,224 @@
+#include "multi.qh"
+// NOTE: also contains trigger_once at bottom
+
+#ifdef SVQC
+// the wait time has passed, so set back up for another activation
+void multi_wait(entity this)
+{
+       if (this.max_health)
+       {
+               this.health = this.max_health;
+               this.takedamage = DAMAGE_YES;
+               this.solid = SOLID_BBOX;
+       }
+}
+
+
+// the trigger was just touched/killed/used
+// this.enemy should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger(entity this)
+{
+       if (this.nextthink > time)
+       {
+               return;         // allready been triggered
+       }
+
+       if(this.spawnflags & ONLY_PLAYERS && !IS_PLAYER(this.enemy))
+       {
+               return; // only players
+       }
+
+       // TODO: restructure this so that trigger_secret is more independent
+       if (this.classname == "trigger_secret")
+       {
+               if (!IS_PLAYER(this.enemy))
+                       return;
+               found_secrets = found_secrets + 1;
+               WriteByte (MSG_ALL, SVC_FOUNDSECRET);
+       }
+
+       if (this.noise)
+       {
+               _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+       }
+
+       // don't trigger again until reset
+       this.takedamage = DAMAGE_NO;
+
+       SUB_UseTargets(this, this.enemy, this.goalentity);
+
+       if (this.wait > 0)
+       {
+               setthink(this, multi_wait);
+               this.nextthink = time + this.wait;
+       }
+       else if (this.wait == 0)
+       {
+               multi_wait(this); // waiting finished
+       }
+       else
+       {       // we can't just delete(this) here, because this is a touch function
+               // called while C code is looping through area links...
+               settouch(this, func_null);
+       }
+}
+
+void multi_use(entity this, entity actor, entity trigger)
+{
+       this.goalentity = trigger;
+       this.enemy = actor;
+       multi_trigger(this);
+}
+
+void multi_touch(entity this, entity toucher)
+{
+       if(!(this.spawnflags & ALL_ENTITIES) && !toucher.iscreature)
+       {
+               return;
+       }
+
+       if(this.team)
+       {
+               if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != toucher.team))
+               {
+                       return;
+               }
+       }
+
+       // if the trigger has an angles field, check player's facing direction
+       if (this.movedir != '0 0 0')
+       {
+               makevectors (toucher.angles);
+               if (v_forward * this.movedir < 0)
+                       return;         // not facing the right way
+       }
+
+       // if the trigger has pressed keys, check that the player is pressing those keys
+       if(this.pressedkeys && IS_PLAYER(toucher)) // only for players
+       {
+               if(!(CS(toucher).pressedkeys & this.pressedkeys))
+               {
+                       return;
+               }
+       }
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       this.enemy = toucher;
+       this.goalentity = toucher;
+       multi_trigger(this);
+}
+
+void multi_eventdamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if(!this.takedamage)
+               return;
+       if(this.spawnflags & NOSPLASH)
+               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+                       return;
+       if(this.team)
+               if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != attacker.team))
+                       return;
+       this.health = this.health - damage;
+       if (this.health <= 0)
+       {
+               this.enemy = attacker;
+               this.goalentity = inflictor;
+               multi_trigger(this);
+       }
+}
+
+void multi_reset(entity this)
+{
+       if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
+               settouch(this, multi_touch);
+       if (this.max_health)
+       {
+               this.health = this.max_health;
+               this.takedamage = DAMAGE_YES;
+               this.solid = SOLID_BBOX;
+       }
+       setthink(this, func_null);
+       this.nextthink = 0;
+       this.team = this.team_saved;
+}
+
+/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
+Variable sized repeatable trigger.  Must be targeted at one or more entities.  If "health" is set, the trigger must be killed to activate each time.
+If "delay" is set, the trigger waits some time after activating before firing.
+"wait" : Seconds between triggerings. (.2 default)
+If notouch is set, the trigger is only fired by other entities, not by touching.
+NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
+sounds
+1)     secret
+2)     beep beep
+3)     large switch
+4)
+set "message" to text string
+*/
+spawnfunc(trigger_multiple)
+{
+       this.reset = multi_reset;
+       if (this.sounds == 1)
+               this.noise = "misc/secret.wav";
+       else if (this.sounds == 2)
+               this.noise = strzone(SND(TALK));
+       else if (this.sounds == 3)
+               this.noise = "misc/trigger1.wav";
+
+       if(this.noise)
+               precache_sound(this.noise);
+
+       if (!this.wait)
+               this.wait = 0.2;
+       else if(this.wait < -1)
+               this.wait = 0;
+       this.use = multi_use;
+
+       EXACTTRIGGER_INIT;
+
+       this.team_saved = this.team;
+       IL_PUSH(g_saved_team, this);
+
+       if (this.health)
+       {
+               if (this.spawnflags & SPAWNFLAG_NOTOUCH)
+                       objerror (this, "health and notouch don't make sense\n");
+               this.canteamdamage = true;
+               this.max_health = this.health;
+               this.event_damage = multi_eventdamage;
+               this.takedamage = DAMAGE_YES;
+               this.solid = SOLID_BBOX;
+               setorigin(this, this.origin);   // make sure it links into the world
+       }
+       else
+       {
+               if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
+               {
+                       settouch(this, multi_touch);
+                       setorigin(this, this.origin);   // make sure it links into the world
+               }
+       }
+}
+
+
+/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
+Variable sized trigger. Triggers once, then removes itself.  You must set the key "target" to the name of another object in the level that has a matching
+"targetname".  If "health" is set, the trigger must be killed to activate.
+If notouch is set, the trigger is only fired by other entities, not by touching.
+if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
+if "angle" is set, the trigger will only fire when someone is facing the direction of the angle.  Use "360" for an angle of 0.
+sounds
+1)     secret
+2)     beep beep
+3)     large switch
+4)
+set "message" to text string
+*/
+spawnfunc(trigger_once)
+{
+       this.wait = -1;
+       spawnfunc_trigger_multiple(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/multi.qh b/qcsrc/common/mapobjects/trigger/multi.qh
new file mode 100644 (file)
index 0000000..43358c2
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once
+
+#ifdef SVQC
+void multi_trigger(entity this);
+void multi_reset(entity this);
+
+spawnfunc(trigger_once);
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/multivibrator.qc b/qcsrc/common/mapobjects/trigger/multivibrator.qc
new file mode 100644 (file)
index 0000000..932fda1
--- /dev/null
@@ -0,0 +1,78 @@
+#include "multivibrator.qh"
+#ifdef SVQC
+void multivibrator_send(entity this)
+{
+       float newstate;
+       float cyclestart;
+
+       cyclestart = floor((time + this.phase) / (this.wait + this.respawntime)) * (this.wait + this.respawntime) - this.phase;
+
+       newstate = (time < cyclestart + this.wait);
+
+       if(this.state != newstate)
+               SUB_UseTargets(this, this, NULL);
+       this.state = newstate;
+
+       if(this.state)
+               this.nextthink = cyclestart + this.wait + 0.01;
+       else
+               this.nextthink = cyclestart + this.wait + this.respawntime + 0.01;
+}
+
+void multivibrator_send_think(entity this)
+{
+       multivibrator_send(this);
+}
+
+void multivibrator_toggle(entity this, entity actor, entity trigger)
+{
+       if(this.nextthink == 0)
+       {
+               multivibrator_send(this);
+       }
+       else
+       {
+               if(this.state)
+               {
+                       SUB_UseTargets(this, actor, trigger);
+                       this.state = 0;
+               }
+               this.nextthink = 0;
+       }
+}
+
+void multivibrator_reset(entity this)
+{
+       if(!(this.spawnflags & START_ENABLED))
+               this.nextthink = 0; // wait for a trigger event
+       else
+               this.nextthink = max(1, time);
+}
+
+/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ENABLED
+"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
+-------- KEYS --------
+target: trigger all entities with this targetname when it goes off
+targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
+phase: offset of the timing
+wait: "on" cycle time (default: 1)
+respawntime: "off" cycle time (default: same as wait)
+-------- SPAWNFLAGS --------
+START_ENABLED: assume it is already turned on (when targeted)
+*/
+spawnfunc(trigger_multivibrator)
+{
+       if(!this.wait)
+               this.wait = 1;
+       if(!this.respawntime)
+               this.respawntime = this.wait;
+
+       this.state = 0;
+       this.use = multivibrator_toggle;
+       setthink(this, multivibrator_send_think);
+       this.nextthink = max(1, time);
+
+       IFTARGETED
+               multivibrator_reset(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/multivibrator.qh b/qcsrc/common/mapobjects/trigger/multivibrator.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/relay.qc b/qcsrc/common/mapobjects/trigger/relay.qc
new file mode 100644 (file)
index 0000000..f99d364
--- /dev/null
@@ -0,0 +1,26 @@
+#include "relay.qh"
+#ifdef SVQC
+
+void relay_use(entity this, entity actor, entity trigger)
+{
+       if(this.active != ACTIVE_ACTIVE)
+               return;
+
+       SUB_UseTargets(this, actor, trigger);
+}
+
+/*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.
+*/
+spawnfunc(trigger_relay)
+{
+       this.active = ACTIVE_ACTIVE;
+       this.use = relay_use;
+       this.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
+}
+
+spawnfunc(target_relay)
+{
+       spawnfunc_trigger_relay(this);
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/relay.qh b/qcsrc/common/mapobjects/trigger/relay.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/relay_activators.qc b/qcsrc/common/mapobjects/trigger/relay_activators.qc
new file mode 100644 (file)
index 0000000..18c2a40
--- /dev/null
@@ -0,0 +1,34 @@
+#include "relay_activators.qh"
+#ifdef SVQC
+void relay_activators_use(entity this, entity actor, entity trigger)
+{
+       for(entity trg = NULL; (trg = find(trg, targetname, this.target)); )
+       {
+               if (trg.setactive)
+                       trg.setactive(trg, this.cnt);
+               else
+               {
+                       //bprint("Not using setactive\n");
+                       generic_setactive(trg, this.cnt);
+               }
+       }
+}
+
+spawnfunc(relay_activate)
+{
+       this.cnt = ACTIVE_ACTIVE;
+       this.use = relay_activators_use;
+}
+
+spawnfunc(relay_deactivate)
+{
+       this.cnt = ACTIVE_NOT;
+       this.use = relay_activators_use;
+}
+
+spawnfunc(relay_activatetoggle)
+{
+       this.cnt = ACTIVE_TOGGLE;
+       this.use = relay_activators_use;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/relay_activators.qh b/qcsrc/common/mapobjects/trigger/relay_activators.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/relay_if.qc b/qcsrc/common/mapobjects/trigger/relay_if.qc
new file mode 100644 (file)
index 0000000..9adcd66
--- /dev/null
@@ -0,0 +1,20 @@
+#include "relay_if.qh"
+#ifdef SVQC
+void trigger_relay_if_use(entity this, entity actor, entity trigger)
+{
+       int n = this.count;
+
+       // TODO make this generic AND faster than nextent()ing through all, if somehow possible
+       n = (cvar_string(this.netname) == cvar_string(this.message));
+       if(this.spawnflags & RELAYIF_NEGATE)
+               n = !n;
+
+       if(n)
+               SUB_UseTargets(this, actor, trigger);
+}
+
+spawnfunc(trigger_relay_if)
+{
+       this.use = trigger_relay_if_use;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/relay_if.qh b/qcsrc/common/mapobjects/trigger/relay_if.qh
new file mode 100644 (file)
index 0000000..6f37aa7
--- /dev/null
@@ -0,0 +1,4 @@
+#pragma once
+
+
+const int RELAYIF_NEGATE = BIT(0);
diff --git a/qcsrc/common/mapobjects/trigger/relay_teamcheck.qc b/qcsrc/common/mapobjects/trigger/relay_teamcheck.qc
new file mode 100644 (file)
index 0000000..bf03b15
--- /dev/null
@@ -0,0 +1,37 @@
+#include "relay_teamcheck.qh"
+#ifdef SVQC
+void trigger_relay_teamcheck_use(entity this, entity actor, entity trigger)
+{
+       if(actor.team)
+       {
+               if(this.spawnflags & RELAYTEAMCHECK_INVERT)
+               {
+                       if(DIFF_TEAM(actor, this))
+                               SUB_UseTargets(this, actor, trigger);
+               }
+               else
+               {
+                       if(SAME_TEAM(actor, this))
+                               SUB_UseTargets(this, actor, trigger);
+               }
+       }
+       else
+       {
+               if(this.spawnflags & RELAYTEAMCHECK_NOTEAM)
+                       SUB_UseTargets(this, actor, trigger);
+       }
+}
+
+void trigger_relay_teamcheck_reset(entity this)
+{
+       this.team = this.team_saved;
+}
+
+spawnfunc(trigger_relay_teamcheck)
+{
+       this.team_saved = this.team;
+       IL_PUSH(g_saved_team, this);
+       this.use = trigger_relay_teamcheck_use;
+       this.reset = trigger_relay_teamcheck_reset;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/relay_teamcheck.qh b/qcsrc/common/mapobjects/trigger/relay_teamcheck.qh
new file mode 100644 (file)
index 0000000..602d253
--- /dev/null
@@ -0,0 +1,5 @@
+#pragma once
+
+
+const int RELAYTEAMCHECK_NOTEAM = BIT(0);
+const int RELAYTEAMCHECK_INVERT = BIT(1);
diff --git a/qcsrc/common/mapobjects/trigger/secret.qc b/qcsrc/common/mapobjects/trigger/secret.qc
new file mode 100644 (file)
index 0000000..9377332
--- /dev/null
@@ -0,0 +1,90 @@
+#include "secret.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <common/util.qh>
+    #include <server/defs.qh>
+#endif
+
+#ifdef SVQC
+
+void secrets_setstatus(entity this)
+{
+       // TODO: use global stats!
+       STAT(SECRETS_TOTAL, this) = secrets_total;
+       STAT(SECRETS_FOUND, this) = secrets_found;
+}
+
+/**
+ * A secret has been found (maybe :P)
+ */
+void trigger_secret_touch(entity this, entity toucher)
+{
+       // only a player can trigger this
+       if (!IS_PLAYER(toucher))
+               return;
+
+       // update secrets found counter
+       secrets_found += 1;
+       //print("Secret found: ", ftos(secret_counter.cnt), "/");
+       //print(ftos(secret_counter.count), "\n");
+
+       // centerprint message (multi_touch() doesn't always call centerprint())
+       centerprint(toucher, this.message);
+       this.message = "";
+
+       // handle normal trigger features
+       multi_touch(this, toucher);
+       // we can't just delete(this) here, because this is a touch function
+       // called while C code is looping through area links...
+       //delete(this);
+}
+
+/*QUAKED trigger_secret (.5 .5 .5) ?
+Variable sized secret trigger. Can be targeted at one or more entities.
+Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
+-------- KEYS --------
+sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
+noise: path to sound file, if you want to play something else
+target: trigger all entities with this targetname when triggered
+message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
+killtarget: remove all entities with this targetname when triggered
+-------- NOTES --------
+You should create a common/trigger textured brush covering the entrance to a secret room/area.
+Trigger secret can only be trigger by a player's touch and can not be a target itself.
+*/
+spawnfunc(trigger_secret)
+{
+       // FIXME: should it be disabled in most modes?
+
+       // update secrets count
+       secrets_total += 1;
+
+       // add default message
+       if (this.message == "")
+               this.message = "You found a secret!";
+
+       // set default sound
+       if (this.noise == "")
+       if (!this.sounds)
+               this.sounds = 1; // misc/secret.wav
+
+       // this entity can't be a target itself!!!!
+       this.targetname = "";
+
+       // you can't just shoot a room to find it, can you?
+       this.health = 0;
+
+       // a secret can not be delayed
+       this.delay = 0;
+
+       // convert this trigger to trigger_once
+       //this.classname = "trigger_once";
+       spawnfunc_trigger_once(this);
+
+       // take over the touch() function, so we can mark secret as found
+       settouch(this, trigger_secret_touch);
+       // ignore triggering;
+       this.use = func_null;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/secret.qh b/qcsrc/common/mapobjects/trigger/secret.qh
new file mode 100644 (file)
index 0000000..fcc55c3
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+#ifdef SVQC
+
+/**
+ * Total number of secrets on the map.
+ */
+float secrets_total;
+
+/**
+ * Total numbe of secrets found on the map.
+ */
+float secrets_found;
+
+
+/**
+ * update secrets status.
+ */
+void secrets_setstatus(entity this);
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/swamp.qc b/qcsrc/common/mapobjects/trigger/swamp.qc
new file mode 100644 (file)
index 0000000..058e41c
--- /dev/null
@@ -0,0 +1,157 @@
+#include "swamp.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <lib/warpzone/util_server.qh>
+    #include <common/weapons/_all.qh>
+    #include <server/defs.qh>
+    #include <common/deathtypes/all.qh>
+#endif
+
+/*
+*              t_swamp.c
+*              Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
+*              Author tZork (Jakob MG)
+*              jakob@games43.se
+*              2005 11 29
+*/
+
+.float swamp_interval; //Hurt players in swamp with this interval
+.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
+.entity swampslug;
+
+#ifdef SVQC
+spawnfunc(trigger_swamp);
+#endif
+void swamp_touch(entity this, entity toucher);
+void swampslug_think(entity this);
+
+
+/*
+* Uses a entity calld swampslug to handle players in the swamp
+* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
+* attaches a new "swampslug" to the player. As long as the plyer is inside
+* the swamp the swamp gives the slug new health. But the slug slowly kills itself
+* so when the player goes outside the swamp, it dies and releases the player from the
+* swamps curses (dmg/slowdown)
+*
+* I do it this way becuz there is no "untouch" event.
+*/
+void swampslug_think(entity this)
+{
+       //Slowly kill the slug
+       this.health = this.health - 1;
+
+       //Slug dead? then remove curses.
+       if(this.health <= 0)
+       {
+               this.owner.in_swamp = 0;
+               delete(this);
+               //centerprint(this.owner,"Killing slug...\n");
+               return;
+       }
+
+       // Slug still alive, so we are still in the swamp
+       // Or we have exited it very recently.
+       // Do the damage and renew the timer.
+#ifdef SVQC
+       Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, DMG_NOWEP, this.owner.origin, '0 0 0');
+#endif
+
+       this.nextthink = time + this.swamp_interval;
+}
+
+void swamp_touch(entity this, entity toucher)
+{
+       // If whatever thats touching the swamp is not a player
+       // or if its a dead player, just dont care abt it.
+       if(!IS_PLAYER(toucher) || IS_DEAD(toucher))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, toucher);
+
+       // Chech if player alredy got a swampslug.
+       if(toucher.in_swamp != 1)
+       {
+               // If not attach one.
+               //centerprint(toucher,"Entering swamp!\n");
+               toucher.swampslug = spawn();
+               toucher.swampslug.health = 2;
+               setthink(toucher.swampslug, swampslug_think);
+               toucher.swampslug.nextthink = time;
+               toucher.swampslug.owner = toucher;
+               toucher.swampslug.dmg = this.dmg;
+               toucher.swampslug.swamp_interval = this.swamp_interval;
+               toucher.swamp_slowdown = this.swamp_slowdown;
+               toucher.in_swamp = 1;
+               return;
+       }
+
+       //toucher.in_swamp = 1;
+
+       //Revitalize players swampslug
+       toucher.swampslug.health = 2;
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
+
+#ifdef SVQC
+float swamp_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
+
+       WriteByte(MSG_ENTITY, this.dmg); // can probably get away with using a single byte here
+       WriteByte(MSG_ENTITY, this.swamp_slowdown);
+       WriteByte(MSG_ENTITY, this.swamp_interval);
+
+       trigger_common_write(this, false);
+
+       return true;
+}
+
+void swamp_link(entity this)
+{
+       trigger_link(this, swamp_send);
+}
+
+/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
+Players gettin into the swamp will
+get slowd down and damaged
+*/
+spawnfunc(trigger_swamp)
+{
+       // Init stuff
+       trigger_init(this);
+       settouch(this, swamp_touch);
+
+       // Setup default keys, if missing
+       if(this.dmg <= 0)
+               this.dmg = 5;
+       if(this.swamp_interval <= 0)
+               this.swamp_interval = 1;
+       if(this.swamp_slowdown <= 0)
+               this.swamp_slowdown = 0.5;
+
+       swamp_link(this);
+}
+
+#elif defined(CSQC)
+
+NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
+{
+       this.dmg = ReadByte();
+       this.swamp_slowdown = ReadByte();
+       this.swamp_interval = ReadByte();
+
+       trigger_common_read(this, false);
+
+       return = true;
+
+       this.classname = "trigger_swamp";
+       this.solid = SOLID_TRIGGER;
+       settouch(this, swamp_touch);
+       this.drawmask = MASK_NORMAL;
+       this.move_time = time;
+       this.entremove = trigger_remove_generic;
+}
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/swamp.qh b/qcsrc/common/mapobjects/trigger/swamp.qh
new file mode 100644 (file)
index 0000000..f4df983
--- /dev/null
@@ -0,0 +1,8 @@
+#pragma once
+
+.float swamp_interval; //Hurt players in swamp with this interval
+.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
+.entity swampslug;
+
+.float in_swamp;              // bool
+.entity swampslug;            // Uses this to release from swamp ("untouch" fix)
diff --git a/qcsrc/common/mapobjects/trigger/teleport.qc b/qcsrc/common/mapobjects/trigger/teleport.qc
new file mode 100644 (file)
index 0000000..825dd01
--- /dev/null
@@ -0,0 +1,183 @@
+#include "teleport.qh"
+REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_TELEPORT)
+
+#ifdef SVQC
+void trigger_teleport_use(entity this, entity actor, entity trigger)
+{
+       if(teamplay)
+               this.team = actor.team;
+#ifdef SVQC
+       this.SendFlags |= SF_TRIGGER_UPDATE;
+#endif
+}
+#endif
+
+bool Teleport_Active(entity this, entity player)
+{
+       if (this.active != ACTIVE_ACTIVE)
+               return false;
+
+#ifdef SVQC
+       if (!player.teleportable)
+               return false;
+
+       if(player.vehicle)
+       if(!player.vehicle.teleportable)
+               return false;
+
+       if(IS_TURRET(player))
+               return false;
+#elif defined(CSQC)
+       if(!IS_PLAYER(player))
+               return false;
+#endif
+
+       if(IS_DEAD(player))
+               return false;
+
+       if(this.team)
+               if(((this.spawnflags & INVERT_TEAMS) == 0) == (DIFF_TEAM(this, player)))
+                       return false;
+
+       return true;
+}
+
+void Teleport_Touch(entity this, entity toucher)
+{
+       entity player = toucher;
+
+       if(!Teleport_Active(this, player))
+               return;
+
+       EXACTTRIGGER_TOUCH(this, player);
+
+#ifdef SVQC
+       if(IS_PLAYER(player))
+               RemoveGrapplingHooks(player);
+#endif
+
+       entity e;
+       e = Simple_TeleportPlayer(this, player);
+
+#ifdef SVQC
+       string s = this.target; this.target = string_null;
+       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
+       if (!this.target) this.target = s;
+
+       SUB_UseTargets(e, player, player);
+#endif
+}
+
+#ifdef SVQC
+void target_teleport_use(entity this, entity actor, entity trigger)
+{
+       entity player = actor;
+
+       if(!Teleport_Active(this, player))
+               return;
+
+       if(IS_PLAYER(player))
+               RemoveGrapplingHooks(player);
+
+       entity e = Simple_TeleportPlayer(this, player);
+
+       string s = this.target; this.target = string_null;
+       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
+       if (!this.target)
+       {
+               this.target = s;
+       }
+
+       SUB_UseTargets(e, player, player);
+}
+#endif
+
+#ifdef SVQC
+float trigger_teleport_send(entity this, entity to, float sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_TELEPORT);
+
+       WriteByte(MSG_ENTITY, this.team);
+       WriteInt24_t(MSG_ENTITY, this.spawnflags);
+       WriteByte(MSG_ENTITY, this.active);
+       WriteCoord(MSG_ENTITY, this.speed);
+
+       trigger_common_write(this, true);
+
+       return true;
+}
+
+void trigger_teleport_link(entity this)
+{
+       //trigger_link(this, trigger_teleport_send);
+}
+
+spawnfunc(trigger_teleport)
+{
+       this.angles = '0 0 0';
+
+       this.active = ACTIVE_ACTIVE;
+       //trigger_init(this); // only for predicted triggers?
+       EXACTTRIGGER_INIT;
+       this.use = trigger_teleport_use;
+
+       if(this.noise != "")
+               FOREACH_WORD(this.noise, true, precache_sound(it));
+
+       // this must be called to spawn the teleport waypoints for bots
+       InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
+
+       if (this.target == "")
+       {
+               objerror (this, "Teleporter with no target");
+               return;
+       }
+
+       IL_PUSH(g_teleporters, this);
+}
+
+spawnfunc(target_teleporter)
+{
+       if(this.target == "")
+       {
+               // actually a destination!
+               spawnfunc_info_teleport_destination(this);
+               return;
+       }
+
+       this.active = ACTIVE_ACTIVE;
+
+       this.use = target_teleport_use;
+
+       if(this.noise != "")
+               FOREACH_WORD(this.noise, true, precache_sound(it));
+
+       InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
+}
+#elif defined(CSQC)
+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();
+       this.speed = ReadCoord();
+
+       trigger_common_read(this, true);
+
+       this.entremove = trigger_remove_generic;
+       this.solid = SOLID_TRIGGER;
+       //settouch(this, trigger_push_touch);
+       this.move_time = time;
+       defer(this, 0.25, teleport_findtarget);
+
+       return true;
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/teleport.qh b/qcsrc/common/mapobjects/trigger/teleport.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
diff --git a/qcsrc/common/mapobjects/trigger/viewloc.qc b/qcsrc/common/mapobjects/trigger/viewloc.qc
new file mode 100644 (file)
index 0000000..ba5dcbe
--- /dev/null
@@ -0,0 +1,213 @@
+#include "viewloc.qh"
+#if defined(CSQC)
+#elif defined(MENUQC)
+#elif defined(SVQC)
+    #include <lib/warpzone/util_server.qh>
+    #include <server/defs.qh>
+#endif
+
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC)
+REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER)
+
+#ifdef SVQC
+
+void viewloc_think(entity this)
+{
+       // we abuse this method, rather than using normal .touch, because touch isn't reliable with multiple clients inside the same trigger, and can't "untouch" entities
+
+       // set myself as current viewloc where possible
+#if 1
+       FOREACH_CLIENT(IS_PLAYER(it) && it.viewloc == this,
+       {
+               it.viewloc = NULL;
+       });
+#else
+       entity e;
+       for(e = NULL; (e = findentity(e, viewloc, this)); )
+               e.viewloc = NULL;
+#endif
+
+#if 1
+       FOREACH_CLIENT(!it.viewloc && IS_PLAYER(it),
+       {
+               vector emin = it.absmin;
+               vector emax = it.absmax;
+               if(this.solid == SOLID_BSP)
+               {
+                       emin -= '1 1 1';
+                       emax += '1 1 1';
+               }
+               if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+               {
+                       if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
+                               it.viewloc = this;
+               }
+       });
+#else
+
+               for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
+                       if(!e.viewloc)
+                               if(IS_PLAYER(e)) // should we support non-player entities with this?
+                               //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet
+                               {
+                                       vector emin = e.absmin;
+                                       vector emax = e.absmax;
+                                       if(this.solid == SOLID_BSP)
+                                       {
+                                               emin -= '1 1 1';
+                                               emax += '1 1 1';
+                                       }
+                                       if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
+                                               if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
+                                                       e.viewloc = this;
+                               }
+#endif
+
+       this.nextthink = time;
+}
+
+bool trigger_viewloc_send(entity this, entity to, int sf)
+{
+       // CSQC doesn't need to know our origin (yet), as we're only available for referencing
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
+
+       WriteByte(MSG_ENTITY, this.spawnflags);
+
+       WriteEntity(MSG_ENTITY, this.enemy);
+       WriteEntity(MSG_ENTITY, this.goalentity);
+
+       WriteVector(MSG_ENTITY, this.origin);
+
+       return true;
+}
+
+void viewloc_init(entity this)
+{
+       entity e;
+       for(e = NULL; (e = find(e, targetname, this.target)); )
+               if(e.classname == "target_viewlocation_start")
+               {
+                       this.enemy = e;
+                       break;
+               }
+       for(e = NULL; (e = find(e, targetname, this.target2)); )
+               if(e.classname == "target_viewlocation_end")
+               {
+                       this.goalentity = e;
+                       break;
+               }
+
+       if(!this.enemy) { LOG_INFO("^1FAIL!"); delete(this); return; }
+
+       if(!this.goalentity)
+               this.goalentity = this.enemy; // make them match so CSQC knows what to do
+
+       Net_LinkEntity(this, false, 0, trigger_viewloc_send);
+
+       setthink(this, viewloc_think);
+       this.nextthink = time;
+}
+
+spawnfunc(trigger_viewlocation)
+{
+       // we won't check target2 here yet, as it may not even need to exist
+       if(this.target == "") { LOG_INFO("^1FAIL!"); delete(this); return; }
+
+       EXACTTRIGGER_INIT;
+       InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET);
+}
+
+bool viewloc_send(entity this, entity to, int sf)
+{
+       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
+
+       WriteByte(MSG_ENTITY, this.cnt);
+
+       WriteVector(MSG_ENTITY, this.origin);
+
+       WriteAngle(MSG_ENTITY, this.angles_x);
+       WriteAngle(MSG_ENTITY, this.angles_y);
+       WriteAngle(MSG_ENTITY, this.angles_z);
+
+       return true;
+}
+
+.float angle;
+void viewloc_link(entity this)
+{
+       if(this.angle)
+               this.angles_y = this.angle;
+       Net_LinkEntity(this, false, 0, viewloc_send);
+}
+
+spawnfunc(target_viewlocation_start)
+{
+       this.classname = "target_viewlocation_start";
+       this.cnt = 1;
+       viewloc_link(this);
+}
+spawnfunc(target_viewlocation_end)
+{
+       this.classname = "target_viewlocation_end";
+       this.cnt = 2;
+       viewloc_link(this);
+}
+
+// compatibility
+spawnfunc(target_viewlocation)
+{
+       spawnfunc_target_viewlocation_start(this);
+}
+
+#elif defined(CSQC)
+
+void trigger_viewloc_updatelink(entity this)
+{
+       this.enemy = findfloat(NULL, entnum, this.cnt);
+       this.goalentity = findfloat(NULL, entnum, this.count);
+}
+
+NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew)
+{
+       this.spawnflags = ReadByte();
+
+       float point1 = ReadShort();
+       float point2 = ReadShort();
+
+       this.enemy = findfloat(NULL, entnum, point1);
+       this.goalentity = findfloat(NULL, entnum, point2);
+
+       this.origin = ReadVector();
+
+       return = true;
+
+       setorigin(this, this.origin);
+
+       this.cnt = point1;
+       this.count = point2;
+
+       setthink(this, trigger_viewloc_updatelink);
+       this.nextthink = time + 1; // we need to delay this or else
+
+       this.classname = "trigger_viewlocation";
+       this.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
+}
+
+NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew)
+{
+       this.cnt = ReadByte();
+
+       this.origin = ReadVector();
+       setorigin(this, this.origin);
+
+       this.movedir_x = ReadAngle();
+       this.movedir_y = ReadAngle();
+       this.movedir_z = ReadAngle();
+
+       return = true;
+
+       this.classname = ((this.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
+       this.drawmask = MASK_NORMAL; // don't cull it
+}
+
+#endif
diff --git a/qcsrc/common/mapobjects/trigger/viewloc.qh b/qcsrc/common/mapobjects/trigger/viewloc.qh
new file mode 100644 (file)
index 0000000..3c393af
--- /dev/null
@@ -0,0 +1,14 @@
+#pragma once
+
+
+const int VIEWLOC_NOSIDESCROLL = BIT(0); // NOTE: currently unimplemented
+const int VIEWLOC_FREEAIM = BIT(1);
+const int VIEWLOC_FREEMOVE = BIT(2);
+
+.entity viewloc;
+
+#ifdef CSQC
+.entity goalentity;
+.entity enemy;
+.vector movedir;
+#endif
diff --git a/qcsrc/common/mapobjects/triggers.qc b/qcsrc/common/mapobjects/triggers.qc
new file mode 100644 (file)
index 0000000..6968a65
--- /dev/null
@@ -0,0 +1,353 @@
+#include "triggers.qh"
+#ifdef SVQC
+       #include <server/item_key.qh>
+#endif
+
+void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
+
+void SUB_UseTargets(entity this, entity actor, entity trigger);
+
+void DelayThink(entity this)
+{
+       SUB_UseTargets (this, this.enemy, NULL);
+       delete(this);
+}
+
+void FixSize(entity e)
+{
+       e.mins_x = rint(e.mins_x);
+       e.mins_y = rint(e.mins_y);
+       e.mins_z = rint(e.mins_z);
+
+       e.maxs_x = rint(e.maxs_x);
+       e.maxs_y = rint(e.maxs_y);
+       e.maxs_z = rint(e.maxs_z);
+}
+
+#ifdef SVQC
+void generic_setactive(entity this, int act)
+{
+       if(act == ACTIVE_TOGGLE)
+       {
+               if(this.active == ACTIVE_ACTIVE)
+               {
+                       this.active = ACTIVE_NOT;
+               }
+               else
+               {
+                       this.active = ACTIVE_ACTIVE;
+               }
+       }
+       else
+       {
+               this.active = act;
+       }
+}
+
+void generic_netlinked_setactive(entity this, int act)
+{
+       int old_status = this.active;
+       generic_setactive(this, act);
+
+       if (this.active != old_status)
+       {
+               this.SendFlags |= SF_TRIGGER_UPDATE;
+       }
+}
+
+void generic_netlinked_reset(entity this)
+{
+       IFTARGETED
+       {
+               if(this.spawnflags & START_ENABLED)
+               {
+                       this.active = ACTIVE_ACTIVE;
+               }
+               else
+               {
+                       this.active = ACTIVE_NOT;
+               }
+       }
+       else
+       {
+               this.active = ACTIVE_ACTIVE;
+       }
+
+       this.SendFlags |= SF_TRIGGER_UPDATE;
+}
+
+// Compatibility with old maps
+void generic_netlinked_legacy_use(entity this, entity actor, entity trigger)
+{
+       LOG_WARNF("Entity %s was (de)activated by a trigger, please update map to use relays", this.targetname);
+       this.setactive(this, ACTIVE_TOGGLE);
+}
+
+bool autocvar_g_triggers_debug = true;
+
+void trigger_init(entity this)
+{
+       string m = this.model;
+       EXACTTRIGGER_INIT;
+       if(autocvar_g_triggers_debug)
+       {
+               if(m != "")
+               {
+                       precache_model(m);
+                       _setmodel(this, m); // no precision needed
+               }
+               setorigin(this, this.origin);
+               if(this.scale)
+                       setsize(this, this.mins * this.scale, this.maxs * this.scale);
+               else
+                       setsize(this, this.mins, this.maxs);
+       }
+
+       if(autocvar_g_triggers_debug)
+               BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
+}
+
+void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
+{
+       setSendEntity(this, sendfunc);
+       this.SendFlags = 0xFFFFFF;
+}
+
+void trigger_common_write(entity this, bool withtarget)
+{
+       int f = 0;
+       if(this.warpzone_isboxy)
+               BITSET_ASSIGN(f, 1);
+       if(this.origin != '0 0 0')
+               BITSET_ASSIGN(f, 4);
+       if(this.movedir != '0 0 0')
+               BITSET_ASSIGN(f, 8);
+       if(this.angles != '0 0 0')
+               BITSET_ASSIGN(f, 16);
+       WriteByte(MSG_ENTITY, f);
+
+       if(withtarget)
+       {
+               // probably some way to clean this up...
+               int targbits = 0;
+               if(this.target && this.target != "") targbits |= BIT(0);
+               if(this.target2 && this.target2 != "") targbits |= BIT(1);
+               if(this.target3 && this.target3 != "") targbits |= BIT(2);
+               if(this.target4 && this.target4 != "") targbits |= BIT(3);
+               if(this.targetname && this.targetname != "") targbits |= BIT(4);
+               if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
+
+               WriteByte(MSG_ENTITY, targbits);
+
+               if(targbits & BIT(0))
+                       WriteString(MSG_ENTITY, this.target);
+               if(targbits & BIT(1))
+                       WriteString(MSG_ENTITY, this.target2);
+               if(targbits & BIT(2))
+                       WriteString(MSG_ENTITY, this.target3);
+               if(targbits & BIT(3))
+                       WriteString(MSG_ENTITY, this.target4);
+               if(targbits & BIT(4))
+                       WriteString(MSG_ENTITY, this.targetname);
+               if(targbits & BIT(5))
+                       WriteString(MSG_ENTITY, this.killtarget);
+       }
+
+       if(f & 4)
+               WriteVector(MSG_ENTITY, this.origin);
+
+       if(f & 8)
+               WriteVector(MSG_ENTITY, this.movedir);
+
+       if(f & 16)
+               WriteVector(MSG_ENTITY, this.angles);
+
+       WriteShort(MSG_ENTITY, this.modelindex);
+       WriteVector(MSG_ENTITY, this.mins);
+       WriteVector(MSG_ENTITY, this.maxs);
+       WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
+}
+
+#elif defined(CSQC)
+
+void trigger_common_read(entity this, bool withtarget)
+{
+       int f = ReadByte();
+       this.warpzone_isboxy = (f & 1);
+
+       if(withtarget)
+       {
+               strfree(this.target);
+               strfree(this.target2);
+               strfree(this.target3);
+               strfree(this.target4);
+               strfree(this.targetname);
+               strfree(this.killtarget);
+
+               int targbits = ReadByte();
+
+               this.target = ((targbits & BIT(0)) ? strzone(ReadString()) : string_null);
+               this.target2 = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
+               this.target3 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
+               this.target4 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
+               this.targetname = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
+               this.killtarget = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
+       }
+
+       if(f & 4)
+               this.origin = ReadVector();
+       else
+               this.origin = '0 0 0';
+       setorigin(this, this.origin);
+
+       if(f & 8)
+               this.movedir = ReadVector();
+       else
+               this.movedir = '0 0 0';
+
+       if(f & 16)
+               this.angles = ReadVector();
+       else
+               this.angles = '0 0 0';
+
+       this.modelindex = ReadShort();
+       this.mins = ReadVector();
+       this.maxs = ReadVector();
+       this.scale = ReadByte() / 16;
+       setsize(this, this.mins, this.maxs);
+}
+
+void trigger_remove_generic(entity this)
+{
+       strfree(this.target);
+       strfree(this.target2);
+       strfree(this.target3);
+       strfree(this.target4);
+       strfree(this.targetname);
+       strfree(this.killtarget);
+}
+#endif
+
+
+/*
+==============================
+SUB_UseTargets
+
+the global "activator" should be set to the entity that initiated the firing.
+
+If this.delay is set, a DelayedUse entity will be created that will actually
+do the SUB_UseTargets after that many seconds have passed.
+
+Centerprints any this.message to the activator.
+
+Removes all entities with a targetname that match this.killtarget,
+and removes them, so some events can remove other triggers.
+
+Search for (string)targetname in all entities that
+match (string)this.target and call their .use function
+
+==============================
+*/
+
+void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse)
+{
+//
+// check for a delay
+//
+       if (this.delay)
+       {
+       // create a temp object to fire at a later time
+               entity t = new(DelayedUse);
+               t.nextthink = time + this.delay;
+               setthink(t, DelayThink);
+               t.enemy = actor;
+               t.message = this.message;
+               t.killtarget = this.killtarget;
+               t.target = this.target;
+               t.target2 = this.target2;
+               t.target3 = this.target3;
+               t.target4 = this.target4;
+               t.antiwall_flag = this.antiwall_flag;
+               return;
+       }
+
+       string s;
+
+//
+// print the message
+//
+#ifdef SVQC
+       if(this)
+       if(IS_PLAYER(actor) && this.message != "")
+       if(IS_REAL_CLIENT(actor))
+       {
+               centerprint(actor, this.message);
+               if (this.noise == "")
+                       play2(actor, SND(TALK));
+       }
+
+//
+// kill the killtagets
+//
+       s = this.killtarget;
+       if (s != "")
+       {
+               for(entity t = NULL; (t = find(t, targetname, s)); )
+                       delete(t);
+       }
+#endif
+
+//
+// fire targets
+//
+
+       if(this.target_random)
+               RandomSelection_Init();
+
+       for(int i = 0; i < 4; ++i)
+       {
+               switch(i)
+               {
+                       default:
+                       case 0: s = this.target; break;
+                       case 1: s = this.target2; break;
+                       case 2: s = this.target3; break;
+                       case 3: s = this.target4; break;
+               }
+               if (s != "")
+               {
+                       // Flag to set func_clientwall state
+                       // 1 == deactivate, 2 == activate, 0 == do nothing
+                       int aw_flag = this.antiwall_flag;
+                       for(entity t = NULL; (t = find(t, targetname, s)); )
+                       {
+                               if(t.use && (t.sub_target_used != time || !preventReuse))
+                               {
+                                       if(this.target_random)
+                                       {
+                                               RandomSelection_AddEnt(t, 1, 0);
+                                       }
+                                       else
+                                       {
+                                               if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
+                                                       t.antiwall_flag = aw_flag;
+
+                                               t.use(t, actor, this);
+                                               if(preventReuse)
+                                                       t.sub_target_used = time;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(this.target_random && RandomSelection_chosen_ent)
+       {
+               RandomSelection_chosen_ent.use(RandomSelection_chosen_ent, actor, this);
+               if(preventReuse)
+                       RandomSelection_chosen_ent.sub_target_used = time;
+       }
+}
+
+void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false); }
+void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true); }
diff --git a/qcsrc/common/mapobjects/triggers.qh b/qcsrc/common/mapobjects/triggers.qh
new file mode 100644 (file)
index 0000000..82e7d54
--- /dev/null
@@ -0,0 +1,52 @@
+#pragma once
+#include "defs.qh"
+
+.bool pushable;
+
+.float antiwall_flag; // Variable to define what to do with func_clientwall
+// 0 == do nothing, 1 == deactivate, 2 == activate
+
+.float height;
+
+#define IFTARGETED if(this.targetname && this.targetname != "")
+
+.float lip;
+
+// used elsewhere (will fix)
+#ifdef SVQC
+void trigger_common_write(entity this, bool withtarget);
+
+string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
+
+void target_voicescript_next(entity pl);
+void target_voicescript_clear(entity pl);
+
+void SUB_DontUseTargets(entity this, entity actor, entity trigger);
+void SUB_UseTargets(entity this, entity actor, entity trigger);
+
+void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger);
+
+void generic_setactive(entity this, int act);
+// generic methods for netlinked entities
+void generic_netlinked_reset(entity this);
+void generic_netlinked_setactive(entity this, int act);
+// WARNING: DON'T USE, ONLY TO KEEP COMPATIBILITY BECAUSE OF SWITCH FROM .state TO .alive!!!!
+void generic_netlinked_legacy_use(entity this, entity actor, entity trigger);
+#endif
+
+.float sub_target_used;
+
+.float volume, atten;
+
+.vector dest;
+
+void FixSize(entity e);
+
+#ifdef CSQC
+void trigger_common_read(entity this, bool withtarget);
+void trigger_remove_generic(entity this);
+
+.float active;
+.string target;
+.string targetname;
+#endif
index a0f6195d1232f6ec6ca994d4514de840b099c58a..415984a2a8a914b17822a98a69a861d927315c2d 100644 (file)
@@ -1,5 +1,7 @@
 #pragma once
 
+#include "cl_minigames_hud.qh"
+
 // Get a square in the center of the avaliable area
 // \note macro to pass by reference pos and mySize
 #define minigame_hud_fitsqare(pos, mySize) \
@@ -92,12 +94,6 @@ void minigame_cmd_workaround(float dummy, string...cmdargc);
 // (ie: it's their turn and they should get back to the minigame)
 void minigame_prompt();
 
-float HUD_MinigameMenu_IsOpened();
-void HUD_MinigameMenu_Close(entity this, entity actor, entity trigger);
-
-// Adds a game-specific entry to the menu
-void HUD_MinigameMenu_CustomEntry(entity parent, string message, string event_arg);
-
 
 #define FOREACH_MINIGAME_ENTITY(entityvar) \
        entityvar=NULL; \
index ef44ea025f5633635496415635e9ce6665293075..c14985f627ceb8497b37b7854c5071cd6a7abe75 100644 (file)
@@ -2,3 +2,9 @@
 
 float HUD_Minigame_InputEvent(float bInputType, float nPrimary, float nSecondary);
 void HUD_Minigame_Mouse();
+
+float HUD_MinigameMenu_IsOpened();
+void HUD_MinigameMenu_Close(entity this, entity actor, entity trigger);
+
+// Adds a game-specific entry to the menu
+void HUD_MinigameMenu_CustomEntry(entity parent, string message, string event_arg);
index 4790f1f1f785eaba2d48eb66a07fbb932a1d8f3f..b4195c05774eec2f08d780de5b4ddbff6cc687c5 100644 (file)
@@ -309,8 +309,7 @@ bool bd_move_dozer(entity minigame, entity dozer)
                                case BD_TILE_BRICK1: return false;
                        }
 
-                       if(hit.netname) { strunzone(hit.netname); }
-                       hit.netname = strzone(testpos);
+                       strcpy(hit.netname, testpos);
                        minigame_server_sendflags(hit,MINIG_SF_UPDATE);
                        break;
                }
@@ -330,8 +329,7 @@ bool bd_move_dozer(entity minigame, entity dozer)
                case BD_TILE_BRICK1: return false;
        }
 
-       if(dozer.netname) { strunzone(dozer.netname); }
-       dozer.netname = strzone(newpos);
+       strcpy(dozer.netname, newpos);
 
        return true;
 }
@@ -422,7 +420,7 @@ void bd_editor_place(entity minigame, entity player, string pos, int thetile, st
                                if(!piece)
                                        return; // how?!
 
-                               if(piece.netname) { strunzone(piece.netname); }
+                               strfree(piece.netname);
                                delete(piece);
                                minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
                                return;
@@ -488,12 +486,12 @@ void bd_unfill_recurse(entity minigame, entity player, int thetype, int letter,
 
        if(targ && thetype == targ.bd_tiletype)
        {
-               if(targ.netname) { strunzone(targ.netname); }
+               strfree(targ.netname);
                delete(targ);
        }
        else if(piece && thetype == piece.bd_tiletype)
        {
-               if(piece.netname) { strunzone(piece.netname); }
+               strfree(piece.netname);
                delete(piece);
        }
        else return;
@@ -568,7 +566,7 @@ void bd_setup_pieces(entity minigame)
        while( (e = findentity(e, owner, minigame)) )
                if(e.classname == "minigame_board_piece")
                {
-                       if(e.netname) { strunzone(e.netname); }
+                       strfree(e.netname);
                        delete(e);
                }
        e = NULL;
@@ -598,8 +596,7 @@ void bd_do_next_match(entity minigame, entity player)
 
        if(minigame.bd_nextlevel && minigame.bd_nextlevel != "")
        {
-               if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
-               minigame.bd_levelname = strzone(minigame.bd_nextlevel);
+               strcpy(minigame.bd_levelname, minigame.bd_nextlevel);
        }
 
        bd_setup_pieces(minigame);
@@ -609,8 +606,7 @@ void bd_do_next_match(entity minigame, entity player)
 
 void bd_set_next_match(entity minigame, string next)
 {
-       if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
-       minigame.bd_nextlevel = strzone(next);
+       strcpy(minigame.bd_nextlevel, next);
 }
 
 void bd_next_match(entity minigame, entity player, string next)
@@ -678,8 +674,7 @@ void bd_set_nextlevel(entity minigame, string s)
 {
        tokenize_console(s);
 
-       if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
-       minigame.bd_nextlevel = strzone(argv(2));
+       strcpy(minigame.bd_nextlevel, argv(2));
 }
 
 int bd_fix_dir(vector dir)
@@ -854,8 +849,7 @@ int bd_server_event(entity minigame, string event, ...)
        {
                case "start":
                {
-                       if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
-                       minigame.bd_levelname = strzone(autocvar_sv_minigames_bulldozer_startlevel);
+                       strcpy(minigame.bd_levelname, autocvar_sv_minigames_bulldozer_startlevel);
                        bd_setup_pieces(minigame);
                        minigame.minigame_flags = BD_TURN_MOVE;
 
@@ -867,7 +861,7 @@ int bd_server_event(entity minigame, string event, ...)
                        while( (e = findentity(e, owner, minigame)) )
                        if(e.classname == "minigame_board_piece")
                        {
-                               if(e.netname) { strunzone(e.netname); }
+                               strfree(e.netname);
                                delete(e);
                        }
                        e = NULL;
@@ -877,8 +871,8 @@ int bd_server_event(entity minigame, string event, ...)
                                delete(e);
                        }
 
-                       if(minigame.bd_nextlevel) { strunzone(minigame.bd_nextlevel); }
-                       if(minigame.bd_levelname) { strunzone(minigame.bd_levelname); }
+                       strfree(minigame.bd_nextlevel);
+                       strfree(minigame.bd_levelname);
                        return false;
                }
                case "join":
@@ -1209,8 +1203,7 @@ void bd_editor_fill(entity minigame)
 
 void bd_set_curr_pos(string s)
 {
-       if ( bd_curr_pos )
-               strunzone(bd_curr_pos);
+       strfree(bd_curr_pos);
        if ( s )
                s = strzone(s);
        bd_curr_pos = s;
@@ -1386,8 +1379,7 @@ int bd_client_event(entity minigame, string event, ...)
                                {
                                        int letter = ReadByte();
                                        int number = ReadByte();
-                                       if(sent.netname) { strunzone(sent.netname); }
-                                       sent.netname = strzone(minigame_tile_buildname(letter, number));
+                                       strcpy(sent.netname, minigame_tile_buildname(letter, number));
 
                                        sent.bd_tiletype = ReadByte();
 
index b3f5885c22380c9404284b610094090b1dad0ac1..c8f8184f5b0bd019862d1b73ecc631faea5084f1 100644 (file)
@@ -201,7 +201,7 @@ int c4_server_event(entity minigame, string event, ...)
                        while( (e = findentity(e, owner, minigame)) )
                        if(e.classname == "minigame_board_piece")
                        {
-                               if(e.netname) { strunzone(e.netname); }
+                               strfree(e.netname);
                                delete(e);
                        }
                        return false;
@@ -399,8 +399,7 @@ void c4_make_move(entity minigame)
 
 void c4_set_curr_pos(string s)
 {
-       if ( c4_curr_pos )
-               strunzone(c4_curr_pos);
+       strfree(c4_curr_pos);
        if ( s )
                s = strzone(s);
        c4_curr_pos = s;
index 82e09c324ab3982966ea7a08dc33f81527e50467..65ac9dee01db2940a47d53fc9e8ebf37eb55483c 100644 (file)
@@ -126,9 +126,9 @@ void nmm_kill_tiles(entity minig)
        while ( ( e = findentity(e,owner,minig) ) )
                if ( e.classname == "minigame_nmm_tile" )
                {
-                       strunzone(e.netname);
-                       strunzone(e.nmm_tile_hmill);
-                       strunzone(e.nmm_tile_vmill);
+                       strfree(e.netname);
+                       strfree(e.nmm_tile_hmill);
+                       strfree(e.nmm_tile_vmill);
                        delete(e);
                }
 }
index 40ddcca08b84c06e251a8165de2fe1e17c8051d7..0b1d74344e93f09fbe00877ecc2c8e6818c328ed 100644 (file)
@@ -121,7 +121,7 @@ void pp_move(entity minigame, entity player, string pos )
 
                        if(existing)
                        {
-                               if(existing.netname) { strunzone(existing.netname); }
+                               strfree(existing.netname);
                                delete(existing);
                        }
 
@@ -215,7 +215,7 @@ int pp_server_event(entity minigame, string event, ...)
                        while( (e = findentity(e, owner, minigame)) )
                        if(e.classname == "minigame_board_piece")
                        {
-                               if(e.netname) { strunzone(e.netname); }
+                               strfree(e.netname);
                                delete(e);
                        }
                        return false;
@@ -471,8 +471,7 @@ void pp_make_move(entity minigame)
 
 void pp_set_curr_pos(string s)
 {
-       if ( pp_curr_pos )
-               strunzone(pp_curr_pos);
+       strfree(pp_curr_pos);
        if ( s )
                s = strzone(s);
        pp_curr_pos = s;
index cd5c001e7adf95a30802b03bf468f857692bc9df..c8851f2ac4bad90e9f437751a20482182736050c 100644 (file)
@@ -139,11 +139,10 @@ bool ps_move_piece(entity minigame, entity piece, string pos, int leti, int numb
        if(!middle)
                return false;
 
-       if(middle.netname) { strunzone(middle.netname); }
+       strfree(middle.netname);
        delete(middle);
 
-       if(piece.netname) { strunzone(piece.netname); }
-       piece.netname = strzone(pos);
+       strcpy(piece.netname, pos);
 
        minigame_server_sendflags(piece,MINIG_SF_ALL);
 
@@ -232,7 +231,7 @@ int ps_server_event(entity minigame, string event, ...)
                        while( (e = findentity(e, owner, minigame)) )
                        if(e.classname == "minigame_board_piece")
                        {
-                               if(e.netname) { strunzone(e.netname); }
+                               strfree(e.netname);
                                delete(e);
                        }
                        return false;
@@ -514,8 +513,7 @@ void ps_make_move(entity minigame)
 
 void ps_set_curr_pos(string s)
 {
-       if ( ps_curr_pos )
-               strunzone(ps_curr_pos);
+       strfree(ps_curr_pos);
        if ( s )
                s = strzone(s);
        ps_curr_pos = s;
index c5a658054fe0d1e55192363b7e12cfd0abe9112b..a6cc50237736f010c2dab9500fa552426d974829 100644 (file)
@@ -147,7 +147,7 @@ int ttt_server_event(entity minigame, string event, ...)
                        while( (e = findentity(e, owner, minigame)) )
                        if(e.classname == "minigame_board_piece")
                        {
-                               if(e.netname) { strunzone(e.netname); }
+                               strfree(e.netname);
                                delete(e);
                        }
                        return false;
@@ -540,8 +540,7 @@ void ttt_make_move(entity minigame)
 
 void ttt_set_curr_pos(string s)
 {
-       if ( ttt_curr_pos )
-               strunzone(ttt_curr_pos);
+       strfree(ttt_curr_pos);
        if ( s )
                s = strzone(s);
        ttt_curr_pos = s;
index 415417b465f627ec1f3420e6c35e7291d08e401b..5c6af26615dc5f71363dfb9286eab23da294a859 100644 (file)
@@ -248,7 +248,7 @@ void end_minigame(entity minigame_session)
                delete(e);
        }
 
-       strunzone(minigame_session.netname);
+       strfree(minigame_session.netname);
        delete(minigame_session);
 }
 
index 7a1e7d73c2a471c802a1cf496d9a68e15c0d49e9..38aa4e33ada8d62930db4634610e5f2cb8610221 100644 (file)
@@ -1,10 +1,9 @@
 #pragma once
 
-#define setmodel(e, m) _setmodel((e), (m).model_str())
-
 CLASS(Model, Object)
     ATTRIB(Model, m_id, int, 0);
     ATTRIB(Model, model_str, string());
+    ATTRIB(Model, model_str_, string);
     CONSTRUCTOR(Model, string() path)
     {
         CONSTRUCT(Model);
@@ -20,5 +19,12 @@ CLASS(Model, Object)
         }
         profile(sprintf("precache_model(\"%s\")", s));
         precache_model(s);
+        strcpy(this.model_str_, s);
     }
 ENDCLASS(Model)
+
+#define setmodel(this, m) MACRO_BEGIN \
+    Model _setmodel_model = (m); \
+    string _setmodel_cached = _setmodel_model.model_str_; \
+    _setmodel((this), _setmodel_cached ? _setmodel_cached : _setmodel_model.model_str()); \
+MACRO_END
index beab98f0ac157a65f65a42898180f8226d4d9033..b8b647bef36946b5ce6cce47fb5e22241bd52236 100644 (file)
@@ -101,7 +101,15 @@ bool M_Mage_Defend_Heal_Check(entity this, entity targ)
        switch(this.skin)
        {
                case 0: return (targ.health < autocvar_g_balance_health_regenstable);
-               case 1: return ((targ.ammo_cells && targ.ammo_cells < g_pickup_cells_max) || (targ.ammo_plasma && targ.ammo_plasma < g_pickup_plasma_max) || (targ.ammo_rockets && targ.ammo_rockets < g_pickup_rockets_max) || (targ.ammo_nails && targ.ammo_nails < g_pickup_nails_max) || (targ.ammo_shells && targ.ammo_shells < g_pickup_shells_max));
+               case 1:
+               {
+                       return ((GetResourceAmount(targ, RESOURCE_CELLS) && GetResourceAmount(targ, RESOURCE_CELLS) < g_pickup_cells_max)
+                               ||  (GetResourceAmount(targ, RESOURCE_PLASMA) && GetResourceAmount(targ, RESOURCE_PLASMA) < g_pickup_plasma_max)
+                               ||  (GetResourceAmount(targ, RESOURCE_ROCKETS) && GetResourceAmount(targ, RESOURCE_ROCKETS) < g_pickup_rockets_max)
+                               ||  (GetResourceAmount(targ, RESOURCE_BULLETS) && GetResourceAmount(targ, RESOURCE_BULLETS) < g_pickup_nails_max)
+                               ||  (GetResourceAmount(targ, RESOURCE_SHELLS) && GetResourceAmount(targ, RESOURCE_SHELLS) < g_pickup_shells_max)
+                                       );
+               }
                case 2: return (targ.armorvalue < autocvar_g_balance_armor_regenstable);
                case 3: return (targ.health > 0);
        }
@@ -118,7 +126,7 @@ void M_Mage_Attack_Spike_Explode(entity this, entity directhitentity)
        this.realowner.mage_spike = NULL;
 
        Send_Effect(EFFECT_EXPLOSION_SMALL, this.origin, '0 0 0', 1);
-       RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius), 
+       RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
                                                NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, directhitentity);
 
        delete(this);
@@ -230,13 +238,16 @@ void M_Mage_Defend_Heal(entity this)
                                        fx = EFFECT_HEALING;
                                        break;
                                case 1:
-                                       if(it.ammo_cells) it.ammo_cells = bound(it.ammo_cells, it.ammo_cells + 1, g_pickup_cells_max);
-                                       if(it.ammo_plasma) it.ammo_plasma = bound(it.ammo_plasma, it.ammo_plasma + 1, g_pickup_plasma_max);
-                                       if(it.ammo_rockets) it.ammo_rockets = bound(it.ammo_rockets, it.ammo_rockets + 1, g_pickup_rockets_max);
-                                       if(it.ammo_shells) it.ammo_shells = bound(it.ammo_shells, it.ammo_shells + 2, g_pickup_shells_max);
-                                       if(it.ammo_nails) it.ammo_nails = bound(it.ammo_nails, it.ammo_nails + 5, g_pickup_nails_max);
+                               {
+                                       float tmpfld;
+                                       tmpfld = GetResourceAmount(it, RESOURCE_CELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_CELLS, bound(tmpfld, tmpfld + 1, g_pickup_cells_max));
+                                       tmpfld = GetResourceAmount(it, RESOURCE_PLASMA); if(tmpfld) SetResourceAmount(it, RESOURCE_PLASMA, bound(tmpfld, tmpfld + 1, g_pickup_plasma_max));
+                                       tmpfld = GetResourceAmount(it, RESOURCE_ROCKETS); if(tmpfld) SetResourceAmount(it, RESOURCE_ROCKETS, bound(tmpfld, tmpfld + 1, g_pickup_rockets_max));
+                                       tmpfld = GetResourceAmount(it, RESOURCE_SHELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_SHELLS, bound(tmpfld, tmpfld + 2, g_pickup_shells_max));
+                                       tmpfld = GetResourceAmount(it, RESOURCE_BULLETS); if(tmpfld) SetResourceAmount(it, RESOURCE_BULLETS, bound(tmpfld, tmpfld + 5, g_pickup_nails_max));
                                        fx = EFFECT_AMMO_REGEN;
                                        break;
+                               }
                                case 2:
                                        if(it.armorvalue < autocvar_g_balance_armor_regenstable)
                                        {
@@ -272,7 +283,7 @@ void M_Mage_Defend_Heal(entity this)
 void M_Mage_Attack_Push(entity this)
 {
        sound(this, CH_SHOTS, SND_TAGEXP1, 1, ATTEN_NORM);
-       RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius), 
+       RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
                                                NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, this.enemy);
        Send_Effect(EFFECT_TE_EXPLOSION, this.origin, '0 0 0', 1);
 
index d596d7d33bf29cda76bc76d72cf855a75d70bc88..0a52e61090e553a140817abc3536a9429a0fd425 100644 (file)
@@ -71,7 +71,7 @@ void M_Wyvern_Attack_Fireball_Explode(entity this)
 
        entity own = this.realowner;
 
-       RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force, 
+       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, DMG_NOWEP, NULL);
 
        FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
index 1197c261346eae99235f85e5c33580a0f5835f04..b4861b917dd39e068cb816fc3253f89f9b7acf4a 100644 (file)
@@ -1,6 +1,5 @@
 #include "sv_monsters.qh"
 
-#include <server/g_subs.qh>
 #include <lib/warpzone/common.qh>
 #include "../constants.qh"
 #include "../teams.qh"
@@ -18,7 +17,7 @@
 #include "../vehicles/all.qh"
 #include <server/campaign.qh>
 #include <server/command/_mod.qh>
-#include "../triggers/triggers.qh"
+#include "../mapobjects/triggers.qh"
 #include <lib/csqcmodel/sv_model.qh>
 #include <server/round_handler.qh>
 #include <server/weapons/_mod.qh>
@@ -82,6 +81,7 @@ bool Monster_ValidTarget(entity this, entity targ)
        || (IS_VEHICLE(targ) && !((Monsters_from(this.monsterid)).spawnflags & MON_FLAG_RANGED)) // melee vs vehicle is useless
        || (time < game_starttime) // monsters do nothing before match has started
        || (targ.takedamage == DAMAGE_NO)
+       || (game_stopped)
        || (targ.items & IT_INVISIBILITY)
        || (IS_SPEC(targ) || IS_OBSERVER(targ)) // don't attack spectators
        || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || targ.health <= 0 || this.health <= 0))
@@ -275,7 +275,7 @@ void Monster_Sounds_Precache(entity this)
 
 void Monster_Sounds_Clear(entity this)
 {
-#define _MSOUND(m) if(this.monstersound_##m) { strunzone(this.monstersound_##m); this.monstersound_##m = string_null; }
+#define _MSOUND(m) strfree(this.monstersound_##m);
        ALLMONSTERSOUNDS
 #undef _MSOUND
 }
@@ -310,9 +310,7 @@ bool Monster_Sounds_Load(entity this, string f, int first)
                field = Monster_Sound_SampleField(argv(0));
                if(GetMonsterSoundSampleField_notFound)
                        continue;
-               if (this.(field))
-                       strunzone(this.(field));
-               this.(field) = strzone(strcat(argv(1), " ", argv(2)));
+               strcpy(this.(field), strcat(argv(1), " ", argv(2)));
        }
        fclose(fh);
        return true;
index d6989ad31839d52229cc8f612879fd6c83ab8686..d456282d429ee6fbc6c5113f90b7f57484b8fcff 100644 (file)
@@ -21,7 +21,7 @@ entity spawnmonster (entity e, string monster, int monster_id, entity spawnedby,
        if(monster == "random" || allow_any)
        {
                RandomSelection_Init();
-               FOREACH(Monsters, it != MON_Null && (allow_any || (!(it.spawnflags & MONSTER_TYPE_PASSIVE) && !(it.spawnflags & MON_FLAG_HIDDEN))),
+               FOREACH(Monsters, it != MON_Null && (allow_any || !(it.spawnflags & MON_FLAG_HIDDEN)) && !(it.spawnflags & MONSTER_TYPE_PASSIVE),
                {
                        RandomSelection_AddEnt(it, 1, 1);
                });
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..1fd3ec672fb6cc750979ee7fa51aa00b996e325f 100644 (file)
@@ -1 +1,3 @@
 #pragma once
+
+.string spawnmob;
index 4f940c42b3c016f3e9131e0c6d3b213bc4d5497a..163960ba5f5d9ee2d4841b277d28bbe2b316f464 100644 (file)
@@ -135,7 +135,7 @@ void RegisterCallbacks() {};
         params(_MUTATOR_HANDLE_NOP,     _MUTATOR_HANDLE_POPOUT) \
         return ret; \
     } \
-    [[accumulate]] void RegisterHooks() { HOOK_##id = NEW(CallbackChain, #id); }
+    ACCUMULATE void RegisterHooks() { HOOK_##id = NEW(CallbackChain, #id); }
 
 #define MUTATOR_CALLHOOK(id, ...) _MUTATOR_CALLHOOK(id, __VA_ARGS__)
 #ifdef __STDC__
@@ -171,6 +171,8 @@ void Mutator_Remove(Mutator mut);
 bool mutator_log = false;
 .bool m_added;
 
+#define MUTATOR_IS_ENABLED(this) MUTATOR_##this.mutatorcheck()
+
 #ifdef GAMEQC
 /** server mutators activate corresponding client mutators for all clients */
 REGISTER_NET_LINKED(Mutator)
@@ -265,7 +267,7 @@ void Mutator_Remove(Mutator mut)
     bool MUTATOR_##id##_check() { return dependence; } \
     REGISTER(Mutators, MUTATOR, id, m_id, NEW(Mutator, #id, MUTATORFUNCTION_##id)) \
     { this.mutatorcheck = MUTATOR_##id##_check; } \
-    [[accumulate]] bool MUTATORFUNCTION_##id(int mode)
+    ACCUMULATE bool MUTATORFUNCTION_##id(int mode)
 
 STATIC_INIT(Mutators) {
     RegisterHooks();
@@ -301,7 +303,7 @@ STATIC_INIT_LATE(Mutators) {
 #define _MUTATOR_CALLBACK(name, func) \
     Callback CALLBACK_##name; \
     bool func(); \
-    [[accumulate]] void RegisterCallbacks() { CALLBACK_##name = NEW(Callback, func); }
+    ACCUMULATE void RegisterCallbacks() { CALLBACK_##name = NEW(Callback, func); }
 
 #define MUTATOR_HOOKFUNCTION(...) \
     EVAL_MUTATOR_HOOKFUNCTION(OVERLOAD(MUTATOR_HOOKFUNCTION, __VA_ARGS__))
@@ -312,9 +314,9 @@ STATIC_INIT_LATE(Mutators) {
 
 #define MUTATOR_HOOKFUNCTION_3(mut, cb, order) \
     _MUTATOR_CALLBACK(mut##_##cb, mut##_##cb) \
-    [[accumulate]] bool MUTATORFUNCTION_##mut##_hooks(int mode) { MUTATOR_HOOK(cb, mut##_##cb, order); } \
+    ACCUMULATE bool MUTATORFUNCTION_##mut##_hooks(int mode) { MUTATOR_HOOK(cb, mut##_##cb, order); } \
     bool mut##_##cb() { return = false; } \
-    [[accumulate]] bool mut##_##cb()
+    ACCUMULATE bool mut##_##cb()
 
 #define MUTATOR_HOOK(cb, func, order) MACRO_BEGIN {                     \
     MUTATOR_ONADD {                                                     \
index d6cf1ca82e0fa4a4b77b86efe26e77ffdbfebb5a..35005e7a8fea65285d869afd82a8f247da833f78 100644 (file)
@@ -64,6 +64,7 @@ STATIC_INIT(REGISTER_BUFFS) {
 #endif
 
 string Buff_UndeprecateName(string buffname);
+entity buff_FirstFromFlags(int _buffs);
 
 REGISTER_BUFF(Null);
 BUFF_SPAWNFUNCS(random, BUFF_Null)
index 937f4cbde4ba00c19395d58c45dd7e6add6aba03..4be441dc1096106c0b4db2c1836880d0596e14e9 100644 (file)
@@ -1,6 +1,6 @@
 #include "sv_buffs.qh"
 
-#include <common/triggers/target/music.qh>
+#include <common/mapobjects/target/music.qh>
 #include <common/gamemodes/_mod.qh>
 
 void buffs_DelayedInit(entity this);
@@ -926,7 +926,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
                BUFF_ONADD(BUFF_INVISIBLE)
                {
-                       if(time < player.strength_finished && g_instagib)
+                       if(time < player.strength_finished && MUTATOR_IS_ENABLED(mutator_instagib))
                                player.buff_invisible_prev_alpha = default_player_alpha; // we don't want to save the powerup's alpha, as player may lose the powerup while holding the buff
                        else
                                player.buff_invisible_prev_alpha = player.alpha;
@@ -935,7 +935,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
                BUFF_ONREM(BUFF_INVISIBLE)
                {
-                       if(time < player.strength_finished && g_instagib)
+                       if(time < player.strength_finished && MUTATOR_IS_ENABLED(mutator_instagib))
                                player.alpha = autocvar_g_instagib_invis_alpha;
                        else
                                player.alpha = player.buff_invisible_prev_alpha;
index 4d9f107af794270f54a2beddddf23b26740a4d09..671a524f9eea2132f773c333c35b06ee3d02431d 100644 (file)
@@ -14,7 +14,7 @@ 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;
-bool autocvar_g_buffs_drop = true;
+bool autocvar_g_buffs_drop = false;
 float autocvar_g_buffs_cooldown_activate;
 float autocvar_g_buffs_cooldown_respawn;
 float autocvar_g_buffs_resistance_blockpercent;
index a1fe27a877c3e46e5e4dfe59a15239c583930f0a..5f9de3b7cbfd906461a58d55d5edace06b9f71e6 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_cloaked.qh"
 
-string autocvar_g_cloaked;
-REGISTER_MUTATOR(cloaked, expr_evaluate(autocvar_g_cloaked));
+//string autocvar_g_cloaked;
+REGISTER_MUTATOR(cloaked, expr_evaluate(cvar_string("g_cloaked")));
 
 float autocvar_g_balance_cloaked_alpha;
 
index 0977b62cebe380b5172e0ef03c6d11f38546da54..5f8d8e68230623cb7fad6700b059895c72b5ff49 100644 (file)
@@ -155,8 +155,7 @@ CLASS(DamageText, Object)
             );
         }
 
-        if (this.text) strunzone(this.text);
-        this.text = strzone(s);
+        strcpy(this.text, s);
 
         this.m_size = map_bound_ranges(potential,
             autocvar_cl_damagetext_size_min_damage, autocvar_cl_damagetext_size_max_damage,
@@ -180,7 +179,7 @@ CLASS(DamageText, Object)
     }
 
     DESTRUCTOR(DamageText) {
-        if (this.text) strunzone(this.text);
+        strfree(this.text);
         if (this == DamageText_screen_first) {
             // start from 0 offset again, hopefully, others (if any) will have faded away by now
             DamageText_screen_first = NULL;
index 4a18cc930879ad34e28ef7551c7af1e381bf8d46..b88d96d700307fbf05480fb88befac6a4824b6bd 100644 (file)
@@ -4,7 +4,7 @@ AUTOCVAR(sv_damagetext, int, 2, "<= 0: disabled, >= 1: visible to spectators, >=
 
 REGISTER_MUTATOR(damagetext, true);
 
-#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 || autocvar_g_instagib)
+#define SV_DAMAGETEXT_DISABLED()        (autocvar_sv_damagetext <= 0 || MUTATOR_IS_ENABLED(mutator_instagib))
 #define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1)
 #define SV_DAMAGETEXT_PLAYERS()         (autocvar_sv_damagetext >= 2)
 #define SV_DAMAGETEXT_ALL()             (autocvar_sv_damagetext >= 3)
index 7097eaf390dac022c2840f7db4d9dc6ee7028368..9989d8e3f3313193763276e3652ea16ed013c6e2 100644 (file)
@@ -1,5 +1,8 @@
 // generated file; do not modify
 #include <common/mutators/mutator/instagib/items.qh>
+#ifdef SVQC
+    #include <common/mutators/mutator/instagib/sv_items.qh>
+#endif
 #ifdef SVQC
     #include <common/mutators/mutator/instagib/sv_instagib.qh>
 #endif
index fe0070afcb1589bd8cbcd45af5e6486aa4632430..95f4f3210c6a97c2650ff61317efb5018b509cdf 100644 (file)
@@ -16,7 +16,7 @@ SOUND(VaporizerCells, Item_Sound("itempickup"));
 
 #ifdef SVQC
 int autocvar_g_instagib_ammo_drop;
-void ammo_vaporizercells_init(entity item)
+void ammo_vaporizercells_init(Pickup this, entity item)
 {
     if(!item.ammo_cells)
         item.ammo_cells = autocvar_g_instagib_ammo_drop;
@@ -25,7 +25,7 @@ void ammo_vaporizercells_init(entity item)
 REGISTER_ITEM(VaporizerCells, Ammo) {
     this.m_canonical_spawnfunc = "item_vaporizer_cells";
 #ifdef GAMEQC
-    this.spawnflags = ITEM_FLAG_INSTAGIB | ITEM_FLAG_MUTATORBLOCKED;
+    this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
     this.m_model                =   MDL_VaporizerCells_ITEM;
     this.m_sound                =   SND_VaporizerCells;
 #endif
@@ -52,8 +52,7 @@ SOUND(ExtraLife, Item_Sound("megahealth"));
 REGISTER_ITEM(ExtraLife, Powerup) {
     this.m_canonical_spawnfunc = "item_extralife";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_INSTAGIB;
-    this.m_model                =   MDL_ExtraLife_ITEM;
+       this.m_model                =   MDL_ExtraLife_ITEM;
     this.m_sound                =   SND_ExtraLife;
 #endif
     this.netname                =   "extralife";
@@ -76,13 +75,13 @@ SOUND(Invisibility, Item_Sound("powerup"));
 /// \brief Initializes the invisibility powerup.
 /// \param[in,out] item Item to initialize.
 /// \return No return.
-void powerup_invisibility_init(entity item);
+void powerup_invisibility_init(Pickup this, entity item);
 #endif
 
 REGISTER_ITEM(Invisibility, Powerup) {
     this.m_canonical_spawnfunc = "item_invisibility";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_INSTAGIB | ITEM_FLAG_MUTATORBLOCKED;
+       this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
     this.m_model            =   MDL_Invisibility_ITEM;
     this.m_sound            =   SND_Invisibility;
     this.m_glow             =   true;
@@ -111,13 +110,13 @@ SOUND(Speed, Item_Sound("powerup_shield"));
 /// \brief Initializes the speed powerup.
 /// \param[in,out] item Item to initialize.
 /// \return No return.
-void powerup_speed_init(entity item);
+void powerup_speed_init(Pickup this, entity item);
 #endif
 
 REGISTER_ITEM(Speed, Powerup) {
     this.m_canonical_spawnfunc = "item_speed";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_INSTAGIB | ITEM_FLAG_MUTATORBLOCKED;
+       this.spawnflags = ITEM_FLAG_MUTATORBLOCKED;
     this.m_model            =   MDL_Speed_ITEM;
     this.m_sound            =   SND_Speed;
     this.m_glow             =   true;
index 616a05da3c93e9c77294028f469ae9a1c649a9ce..3cda4485f1a3efde2bcb324335fbc2da635ea11b 100644 (file)
@@ -1,5 +1,9 @@
 #include "sv_instagib.qh"
 
+#include <server/client.qh>
+#include <common/items/_mod.qh>
+#include "../random_items/sv_random_items.qh"
+
 bool autocvar_g_instagib_damagedbycontents = true;
 bool autocvar_g_instagib_blaster_keepdamage = false;
 bool autocvar_g_instagib_blaster_keepforce = false;
@@ -13,24 +17,14 @@ bool autocvar_g_instagib_ammo_convert_bullets;
 int autocvar_g_instagib_extralives;
 float autocvar_g_instagib_speed_highspeed;
 
-#include <server/client.qh>
-
-#include <common/items/_mod.qh>
-
-REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball)
+IntrusiveList g_instagib_items;
+STATIC_INIT()
 {
-       MUTATOR_ONADD
-       {
-               ITEM_VaporizerCells.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Invisibility.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Speed.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-       }
-       MUTATOR_ONROLLBACK_OR_REMOVE
-       {
-               ITEM_VaporizerCells.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Invisibility.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_Speed.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-       }
+       g_instagib_items = IL_NEW();
+       IL_PUSH(g_instagib_items, ITEM_VaporizerCells);
+       IL_PUSH(g_instagib_items, ITEM_ExtraLife);
+       IL_PUSH(g_instagib_items, ITEM_Invisibility);
+       IL_PUSH(g_instagib_items, ITEM_Speed);
 }
 
 void instagib_invisibility(entity this)
@@ -50,6 +44,26 @@ void instagib_speed(entity this)
        StartItem(this, ITEM_Speed);
 }
 
+/// \brief Returns a random classname of the instagib item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the instagib item.
+string RandomItems_GetRandomInstagibItemClassName(string prefix)
+{
+       RandomSelection_Init();
+       IL_EACH(g_instagib_items, Item_IsDefinitionAllowed(it),
+       {
+               string cvar_name = sprintf("g_%s_%s_probability", prefix,
+                       it.m_canonical_spawnfunc);
+               if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+               {
+                       LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       continue;
+               }
+               RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
+       });
+       return RandomSelection_chosen_string;
+}
+
 .float instagib_nextthink;
 .float instagib_needammo;
 void instagib_stop_countdown(entity e)
@@ -147,6 +161,13 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, MatchEnd)
        FOREACH_CLIENT(IS_PLAYER(it), { instagib_stop_countdown(it); });
 }
 
+MUTATOR_HOOKFUNCTION(mutator_instagib, RandomItems_GetRandomItemClassName)
+{
+       M_ARGV(1, string) = RandomItems_GetRandomInstagibItemClassName(
+               M_ARGV(0, string));
+       return true;
+}
+
 MUTATOR_HOOKFUNCTION(mutator_instagib, MonsterDropItem)
 {
        entity item = M_ARGV(1, entity);
index 9020b93124777851f80a80eb1e2dc4b0edab75fa..56f4ac7daaaace7d5d831d281107ed0632d75eaf 100644 (file)
@@ -7,3 +7,19 @@ float autocvar_g_instagib_invis_alpha;
 void instagib_invisibility(entity this);
 void instagib_extralife(entity this);
 void instagib_speed(entity this);
+
+REGISTER_MUTATOR(mutator_instagib, autocvar_g_instagib && !g_nexball)
+{
+       MUTATOR_ONADD
+       {
+               ITEM_VaporizerCells.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Invisibility.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Speed.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+       }
+       MUTATOR_ONROLLBACK_OR_REMOVE
+       {
+               ITEM_VaporizerCells.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Invisibility.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_Speed.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+       }
+}
index ffd9bfb0ca1fd2c7ac37b5fc72e55249a233da1d..c944f56c337055c3f7e941df76ebc250f1b8540a 100644 (file)
@@ -1,3 +1,5 @@
+#include "sv_items.qh"
+
 #include "items.qh"
 
 /// \brief Time of ivisibility powerup in seconds.
@@ -5,7 +7,7 @@ float autocvar_g_instagib_invisibility_time;
 /// \brief Time of speed powerup in seconds.
 float autocvar_g_instagib_speed_time;
 
-void powerup_invisibility_init(entity item)
+void powerup_invisibility_init(Pickup this, entity item)
 {
        if(!item.strength_finished)
        {
@@ -14,7 +16,7 @@ void powerup_invisibility_init(entity item)
 }
 
 
-void powerup_speed_init(entity item)
+void powerup_speed_init(Pickup this, entity item)
 {
        if(!item.invincible_finished)
        {
diff --git a/qcsrc/common/mutators/mutator/instagib/sv_items.qh b/qcsrc/common/mutators/mutator/instagib/sv_items.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index c2402ef4608c95d7b1f5fbb84e8f70768ffed1e9..1379d586f10fd4da14b9f82d98571cd00bbe6c78 100644 (file)
@@ -124,7 +124,7 @@ void Item_ItemsTime_SetTime(entity e, float t)
     {
                if (!item.instanceOfWeaponPickup)
                        it_times[item.m_id] = t;
-               else if (e.weapons & WEPSET_SUPERWEAPONS)
+               else if (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
                        it_times[Items_MAX] = t;
     }
 }
@@ -139,7 +139,7 @@ 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))))
+        if(!(it.itemdef == e.itemdef || ((STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) && (STAT(WEAPONS, it) & WEPSET_SUPERWEAPONS))))
             continue;
         if (it.scheduledrespawntime <= time)
             isavailable = true;
index 98fb4815c1ce28cc699a429537ea75c2643b4487..0144c3147c85433ceb1d005e7188a83b62c9208b 100644 (file)
@@ -1 +1,4 @@
 // generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh>
+#endif
index a3b028f1c6c0c9573b8eb7b10765a34a4db9b71c..d91546af5711fcfa9b9848202cc7c775c3aca151 100644 (file)
@@ -1,3 +1,4 @@
+#include "sv_kick_teamkiller.qh"
 
 float autocvar_g_kick_teamkiller_rate;
 float autocvar_g_kick_teamkiller_lower_limit;
@@ -24,7 +25,7 @@ MUTATOR_HOOKFUNCTION(kick_teamkiller, PlayerDies)
        // use the players actual playtime
        float playtime = time - CS(attacker).startplaytime;
        // rate is in teamkills/minutes, playtime in seconds
-       if (teamkills >= autocvar_g_kick_teamkiller_lower_limit && 
+       if (teamkills >= autocvar_g_kick_teamkiller_lower_limit &&
            teamkills >= autocvar_g_kick_teamkiller_rate*playtime/60.0)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_KICK_TEAMKILL, attacker.netname);
diff --git a/qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh b/qcsrc/common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index d6796fc0590e0581be335989330a384934bee600..a56efaf83cffbf086b2cbca93f5798cfce6b7d20 100644 (file)
@@ -1,7 +1,9 @@
 #include "sv_melee_only.qh"
 
+#include "../overkill/sv_overkill.qh"
+
 string autocvar_g_melee_only;
-REGISTER_MUTATOR(melee_only, expr_evaluate(autocvar_g_melee_only) && !cvar("g_instagib") && !cvar("g_overkill") && !g_nexball);
+REGISTER_MUTATOR(melee_only, expr_evaluate(autocvar_g_melee_only) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok) && !g_nexball);
 
 MUTATOR_HOOKFUNCTION(melee_only, SetStartItems, CBC_ORDER_LAST)
 {
@@ -25,11 +27,11 @@ MUTATOR_HOOKFUNCTION(melee_only, ForbidThrowCurrentWeapon)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(melee_only, FilterItem)
+MUTATOR_HOOKFUNCTION(melee_only, FilterItemDefinition)
 {
-       entity item = M_ARGV(0, entity);
+       entity definition = M_ARGV(0, entity);
 
-       switch (item.itemdef)
+       switch (definition)
        {
                case ITEM_HealthSmall:
                case ITEM_ArmorSmall:
index cde0016f1bffe7112f2692a83ab49894caa8cbb5..83cf74247fcdf2275c5a2bcc4df83025925700fb 100644 (file)
@@ -1,3 +1,5 @@
+#include <common/effects/all.qh>
+
 EFFECT(0, NADE_EXPLODE_RED,         "nade_red_explode")
 EFFECT(0, NADE_EXPLODE_BLUE,        "nade_blue_explode")
 EFFECT(0, NADE_EXPLODE_YELLOW,      "nade_yellow_explode")
index bcdbe0cd920973e256c142f27d1d216ef8e90f02..0245cee640f1e9437af91804340e9f0fbb737ba3 100644 (file)
@@ -68,3 +68,12 @@ REGISTER_NADE(ENTRAP) {
     NADE_PROJECTILE(0, PROJECTILE_NADE_ENTRAP, EFFECT_NADE_TRAIL_YELLOW);
     NADE_PROJECTILE(1, PROJECTILE_NADE_ENTRAP_BURN, EFFECT_NADE_TRAIL_BURN_YELLOW);
 }
+
+REGISTER_NADE(VEIL) {
+    this.m_color = '0.65 0.85 0.65';
+    this.m_name = _("Veil grenade");
+    this.m_icon = "nade_veil";
+    this.m_alpha = 0.45;
+    NADE_PROJECTILE(0, PROJECTILE_NADE_VEIL, EFFECT_NADE_TRAIL_NEUTRAL);
+    NADE_PROJECTILE(1, PROJECTILE_NADE_VEIL_BURN, EFFECT_NADE_TRAIL_BURN_NEUTRAL);
+}
index 24149ad7fce9430ca89000e777d20a3939f25fe6..7da7c0709b3161da40140a82ba44a8795af6ad2d 100644 (file)
@@ -1,5 +1,7 @@
 #include "nades.qh"
 
+#include "../overkill/okmachinegun.qh"
+
 #ifdef SVQC
 bool autocvar_g_nades_nade_small;
 float autocvar_g_nades_spread = 0.04;
@@ -36,6 +38,7 @@ entity Nade_TrailEffect(int proj, int nade_team)
 REGISTER_MUTATOR(cl_nades, true);
 MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
 {
+       // TODO: make a common orb state!
        if (STAT(HEALING_ORB) > time)
        {
                M_ARGV(0, vector) = NADE_TYPE_HEAL.m_color;
@@ -48,6 +51,12 @@ MUTATOR_HOOKFUNCTION(cl_nades, HUD_Draw_overlay)
                M_ARGV(1, float) = STAT(ENTRAP_ORB_ALPHA);
                return true;
        }
+       if (STAT(VEIL_ORB) > time)
+       {
+               M_ARGV(0, vector) = NADE_TYPE_VEIL.m_color;
+               M_ARGV(1, float) = STAT(VEIL_ORB_ALPHA);
+               return true;
+       }
        return false;
 }
 MUTATOR_HOOKFUNCTION(cl_nades, Ent_Projectile)
@@ -96,6 +105,7 @@ MUTATOR_HOOKFUNCTION(cl_nades, EditProjectile)
        settouch(proj, func_null);
        proj.scale = 1.5;
        proj.avelocity = randomvec() * 720;
+       proj.alphamod = nade_type.m_alpha;
 
        if (nade_type == NADE_TYPE_TRANSLOCATE || nade_type == NADE_TYPE_SPAWN)
                proj.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
@@ -148,7 +158,6 @@ void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expan
 #include <common/gamemodes/_mod.qh>
 #include <common/monsters/sv_spawn.qh>
 #include <common/monsters/sv_monsters.qh>
-#include <server/g_subs.qh>
 
 REGISTER_MUTATOR(nades, autocvar_g_nades);
 
@@ -665,6 +674,35 @@ void nade_monster_boom(entity this)
        e.monster_skill = MONSTER_SKILL_INSANE;
 }
 
+void nade_veil_touch(entity this, entity toucher)
+{
+       if ( IS_REAL_CLIENT(toucher) || IS_VEHICLE(toucher) || IS_MONSTER(toucher) )
+       {
+               entity show_tint = (IS_VEHICLE(toucher)) ? toucher.owner : toucher;
+
+               float tint_alpha = 0.75;
+               if(SAME_TEAM(toucher, this.realowner))
+               {
+                       tint_alpha = 0.45;
+                       if(!STAT(VEIL_ORB, show_tint))
+                       {
+                               toucher.nade_veil_prevalpha = toucher.alpha;
+                               toucher.alpha = -1;
+                       }
+               }
+               STAT(VEIL_ORB, show_tint) = time + 0.1;
+               STAT(VEIL_ORB_ALPHA, show_tint) = tint_alpha * (this.ltime - time) / this.orb_lifetime;
+       }
+}
+
+void nade_veil_boom(entity this)
+{
+       entity orb = nades_spawn_orb(this.owner, this.realowner, this.origin, autocvar_g_nades_veil_time, autocvar_g_nades_veil_radius);
+
+       settouch(orb, nade_veil_touch);
+       orb.colormod = NADE_TYPE_VEIL.m_color;
+}
+
 void nade_boom(entity this)
 {
        entity expef = NULL;
@@ -705,6 +743,11 @@ void nade_boom(entity this)
                        expef = EFFECT_SPAWN_YELLOW;
                        break;
 
+               case NADE_TYPE_VEIL:
+                       nade_blast = false;
+                       expef = EFFECT_SPAWN_NEUTRAL;
+                       break;
+
                default:
                case NADE_TYPE_NORMAL:
                        expef = EFFECT_NADE_EXPLODE(this.realowner.team);
@@ -736,6 +779,7 @@ void nade_boom(entity this)
                case NADE_TYPE_HEAL: nade_heal_boom(this); break;
                case NADE_TYPE_MONSTER: nade_monster_boom(this); break;
                case NADE_TYPE_ENTRAP: nade_entrap_boom(this); break;
+               case NADE_TYPE_VEIL: nade_veil_boom(this); break;
        }
 
        IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
@@ -838,12 +882,12 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
                force *= 0.5; // too much
                damage = 0;
        }
-       else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER))
+       else if(DEATH_ISWEAPON(deathtype, WEP_VORTEX) || DEATH_ISWEAPON(deathtype, WEP_VAPORIZER) || DEATH_ISWEAPON(deathtype, WEP_OVERKILL_NEX))
        {
                force *= 6;
                damage = this.max_health * 0.55;
        }
-       else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN))
+       else if(DEATH_ISWEAPON(deathtype, WEP_MACHINEGUN) || DEATH_ISWEAPON(deathtype, WEP_OVERKILL_MACHINEGUN))
                damage = this.max_health * 0.1;
        else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
        {
@@ -1056,6 +1100,7 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
        n.projectiledeathtype = DEATH_NADE.m_id;
        n.weaponentity_fld = weaponentity;
        n.nade_lifetime = ntime;
+       n.alpha = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_alpha;
 
        setmodel(fn, MDL_NADE_VIEW);
        setattachment(fn, player.(weaponentity), "");
@@ -1066,6 +1111,7 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
        setthink(fn, SUB_Remove);
        fn.nextthink = n.wait;
        fn.weaponentity_fld = weaponentity;
+       fn.alpha = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_alpha;
 
        player.nade = n;
        player.fake_nade = fn;
@@ -1206,7 +1252,7 @@ MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
 {
     entity player = M_ARGV(0, entity);
 
-       if (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
+       if (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)) || autocvar_g_nades_override_dropweapon) {
                nades_CheckThrow(player);
                return true;
        }
@@ -1218,7 +1264,7 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
 
        if (!IS_PLAYER(player)) { return; }
 
-       if (player.nade && (player.offhand != OFFHAND_NADE || (player.weapons & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
+       if (player.nade && (player.offhand != OFFHAND_NADE || (STAT(WEAPONS, player) & WEPSET(HOOK)))) OFFHAND_NADE.offhand_think(OFFHAND_NADE, player, player.nade_altbutton);
 
        entity held_nade = player.nade;
        if (held_nade)
@@ -1271,6 +1317,15 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
                {
                        STAT(NADE_BONUS, player) = STAT(NADE_BONUS_SCORE, player) = 0;
                }
+
+               if(STAT(VEIL_ORB, player) && STAT(VEIL_ORB, player) <= time)
+               {
+                       STAT(VEIL_ORB, player) = 0;
+                       if(player.vehicle)
+                               player.vehicle.alpha = player.vehicle.nade_veil_prevalpha;
+                       else
+                               player.alpha = player.nade_veil_prevalpha;
+               }
        }
 
        int n = 0;
@@ -1331,6 +1386,12 @@ MUTATOR_HOOKFUNCTION(nades, MonsterMove)
                M_ARGV(1, float) *= autocvar_g_nades_entrap_speed; // run speed
                M_ARGV(2, float) *= autocvar_g_nades_entrap_speed; // walk speed
        }
+
+       if (STAT(VEIL_ORB, mon) && STAT(VEIL_ORB, mon) <= time)
+       {
+               mon.alpha = mon.nade_veil_prevalpha;
+               STAT(VEIL_ORB, mon) = 0;
+       }
 }
 
 MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
@@ -1404,10 +1465,7 @@ MUTATOR_HOOKFUNCTION(nades, Damage_Calculate)
        entity frag_target = M_ARGV(2, entity);
        float frag_deathtype = M_ARGV(3, float);
 
-       if(STAT(FROZEN, frag_target))
-       if(autocvar_g_freezetag_revive_nade)
-       if(frag_attacker == frag_target)
-       if(frag_deathtype == DEATH_NADE.m_id)
+       if(autocvar_g_freezetag_revive_nade && STAT(FROZEN, frag_target) && frag_attacker == frag_target && frag_deathtype == DEATH_NADE.m_id)
        if(time - frag_inflictor.toss_time <= 0.1)
        {
                Unfreeze(frag_target);
@@ -1469,6 +1527,8 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
        STAT(HEALING_ORB_ALPHA, client) = STAT(HEALING_ORB_ALPHA, spectatee);
        STAT(ENTRAP_ORB, client) = STAT(ENTRAP_ORB, spectatee);
        STAT(ENTRAP_ORB_ALPHA, client) = STAT(ENTRAP_ORB_ALPHA, spectatee);
+       STAT(VEIL_ORB, client) = STAT(VEIL_ORB, spectatee);
+       STAT(VEIL_ORB_ALPHA, client) = STAT(VEIL_ORB_ALPHA, spectatee);
 }
 
 REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
index c5a1967e0b53ffa14bd4e0e756070cf7fb584802..2729316a88b4fd8c95eb24f1afc1580b3d7126f3 100644 (file)
@@ -18,6 +18,8 @@ const int PROJECTILE_NADE_MONSTER = 82;
 const int PROJECTILE_NADE_MONSTER_BURN = 83;
 const int PROJECTILE_NADE_ENTRAP = 84;
 const int PROJECTILE_NADE_ENTRAP_BURN = 85;
+const int PROJECTILE_NADE_VEIL = 86;
+const int PROJECTILE_NADE_VEIL_BURN = 87;
 
 REGISTRY(Nades, BITS(4))
 #define Nades_from(i) _Nades_from(i, NADE_TYPE_Null)
@@ -31,6 +33,7 @@ CLASS(Nade, Object)
     ATTRIB(Nade, m_color, vector, '0 0 0');
     ATTRIB(Nade, m_name, string, _("Grenade"));
     ATTRIB(Nade, m_icon, string, "nade_normal");
+    ATTRIB(Nade, m_alpha, float, 1);
     ATTRIBARRAY(Nade, m_projectile, int, 2);
     ATTRIBARRAY(Nade, m_trail, entity, 2);
     METHOD(Nade, display, void(entity this, void(string name, string icon) returns)) {
@@ -72,6 +75,7 @@ Nade Nade_FromProjectile(int proj)
 .string cvar_cl_pokenade_type;
 .float toss_time;
 .float nade_show_particles;
+.float nade_veil_prevalpha;
 
 bool orb_send(entity this, entity to, int sf);
 
@@ -95,3 +99,9 @@ void nades_GiveBonus(entity player, float score);
 MUTATOR_HOOKABLE(Nade_Damage, EV_Nade_Damage);
 
 #endif
+
+#ifdef CSQC
+bool Projectile_isnade(int proj); // TODO: remove
+
+void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
+#endif
index ec2593215a09b5187abd522608e07dc6f978e141..540edc69d9c6578c7ef4277a9f35b1a2f37cfb4b 100644 (file)
@@ -70,11 +70,11 @@ roflsound "New toys, new toys!" sound.
 
 */
 
-string autocvar_g_new_toys;
+//string autocvar_g_new_toys;
 
 bool nt_IsNewToy(int w);
 
-REGISTER_MUTATOR(nt, expr_evaluate(autocvar_g_new_toys) && !cvar("g_instagib") && !cvar("g_overkill"))
+REGISTER_MUTATOR(nt, expr_evaluate(cvar_string("g_new_toys")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok))
 {
        MUTATOR_ONADD
        {
@@ -195,7 +195,7 @@ MUTATOR_HOOKFUNCTION(nt, SetStartItems)
 
 MUTATOR_HOOKFUNCTION(nt, SetWeaponreplace)
 {
-       if (autocvar_g_random_items)
+       if (MUTATOR_IS_ENABLED(random_items))
        {
                // Do not replace weapons when random items are enabled.
                return;
index c174b530f0a48e94cb20d6661fd069ecb0e2ecc4..da5dcc234e32b4df646150465d7dee849f3193ae 100644 (file)
@@ -1,6 +1,6 @@
 #include "sv_nix.qh"
 
-string autocvar_g_nix;
+//string autocvar_g_nix;
 int autocvar_g_balance_nix_ammo_cells;
 int autocvar_g_balance_nix_ammo_plasma;
 int autocvar_g_balance_nix_ammo_fuel;
@@ -36,7 +36,7 @@ float nix_nextweapon;
 
 bool NIX_CanChooseWeapon(int wpn);
 
-REGISTER_MUTATOR(nix, expr_evaluate(autocvar_g_nix) && !cvar("g_instagib") && !cvar("g_overkill"))
+REGISTER_MUTATOR(nix, expr_evaluate(cvar_string("g_nix")) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok))
 {
        MUTATOR_ONADD
        {
@@ -63,7 +63,7 @@ REGISTER_MUTATOR(nix, expr_evaluate(autocvar_g_nix) && !cvar("g_instagib") && !c
                        SetResourceAmount(it, RESOURCE_CELLS, start_ammo_cells);
                        SetResourceAmount(it, RESOURCE_PLASMA, start_ammo_plasma);
                        SetResourceAmount(it, RESOURCE_FUEL, start_ammo_fuel);
-                       it.weapons = start_weapons;
+                       STAT(WEAPONS, it) = start_weapons;
                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                        {
                                .entity weaponentity = weaponentities[slot];
@@ -208,10 +208,10 @@ void NIX_GiveCurrentWeapon(entity this)
                this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
        }
 
-       this.weapons = '0 0 0';
+       STAT(WEAPONS, this) = '0 0 0';
        if(g_nix_with_blaster)
-               this.weapons |= WEPSET(BLASTER);
-       this.weapons |= e.m_wepset;
+               STAT(WEAPONS, this) |= WEPSET(BLASTER);
+       STAT(WEAPONS, this) |= e.m_wepset;
 
     Weapon w = Weapons_from(nix_weapon);
     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
@@ -244,15 +244,15 @@ MUTATOR_HOOKFUNCTION(nix, BuildMutatorsPrettyString)
        M_ARGV(0, string) = strcat(M_ARGV(0, string), ", NIX");
 }
 
-MUTATOR_HOOKFUNCTION(nix, FilterItem)
+MUTATOR_HOOKFUNCTION(nix, FilterItemDefinition)
 {
-       entity item = M_ARGV(0, entity);
+       entity definition = M_ARGV(0, entity);
 
-       if(item.itemdef.instanceOfHealth || item.itemdef.instanceOfArmor)
+       if (definition.instanceOfHealth || definition.instanceOfArmor)
        {
                return !autocvar_g_nix_with_healtharmor;
        }
-       else if(item.itemdef.instanceOfPowerup)
+       else if (definition.instanceOfPowerup)
        {
                return !autocvar_g_nix_with_powerups;
        }
index 98fb4815c1ce28cc699a429537ea75c2643b4487..5e11096a532644d671eb7bd409b0519e08d3c3bd 100644 (file)
@@ -1 +1,4 @@
 // generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh>
+#endif
index b25175aea5ad9055355fd508b0ba238fad97673a..3a10055fe5419e0f52c855f91edb0066ba170718 100644 (file)
@@ -1,3 +1,5 @@
+#include "sv_offhand_blaster.qh"
+
 string autocvar_g_offhand_blaster = "0";
 
 REGISTER_MUTATOR(offhand_blaster, expr_evaluate(autocvar_g_offhand_blaster));
diff --git a/qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh b/qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh
new file mode 100644 (file)
index 0000000..6f70f09
--- /dev/null
@@ -0,0 +1 @@
+#pragma once
index 0552173c1a0874c8c8ca6765ac0a922ff60ff01b..017cc2082adfc7a9468e293dde68c276160abff5 100644 (file)
@@ -1,10 +1,15 @@
 // 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>
+#include <common/mutators/mutator/overkill/okhmg.qc>
+#include <common/mutators/mutator/overkill/okmachinegun.qc>
+#include <common/mutators/mutator/overkill/oknex.qc>
+#include <common/mutators/mutator/overkill/okrpc.qc>
+#include <common/mutators/mutator/overkill/okshotgun.qc>
+#ifdef SVQC
+    #include <common/mutators/mutator/overkill/sv_weapons.qc>
+#endif
index 13e42431b32ebb3a28c11504a38fb822e69d7640..7731f17e169e9191fb49996c819cdf1ec200faa8 100644 (file)
@@ -1,10 +1,12 @@
 // 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>
+#include <common/mutators/mutator/overkill/okhmg.qh>
+#include <common/mutators/mutator/overkill/okmachinegun.qh>
+#include <common/mutators/mutator/overkill/oknex.qh>
+#include <common/mutators/mutator/overkill/okrpc.qh>
+#include <common/mutators/mutator/overkill/okshotgun.qh>
index eb21953955429543f0edd1cb87ec88dd6ade0a03..4b14194be628f0bc9929e2608463b6426ef37473 100644 (file)
@@ -4,8 +4,5 @@ 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/hmg.qc b/qcsrc/common/mutators/mutator/overkill/hmg.qc
deleted file mode 100644 (file)
index b9e01bd..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#include "hmg.qh"
-
-#ifdef SVQC
-
-REGISTER_MUTATOR(hmg_nadesupport, true);
-MUTATOR_HOOKFUNCTION(hmg_nadesupport, Nade_Damage)
-{
-       if (M_ARGV(1, entity) != WEP_HMG) return;
-       return = true;
-       M_ARGV(3, float) /* damage */ = (M_ARGV(0, entity)).max_health * 0.1;
-}
-
-void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
-{
-       if (!PHYS_INPUT_BUTTON_ATCK(actor))
-       {
-               w_ready(thiswep, actor, weaponentity, fire);
-               return;
-       }
-
-       if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
-       {
-               W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
-               w_ready(thiswep, actor, weaponentity, fire);
-               return;
-       }
-
-       W_DecreaseAmmo(WEP_HMG, actor, WEP_CVAR(hmg, ammo), weaponentity);
-
-       W_SetupShot (actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(hmg, damage), WEP_HMG.m_id);
-
-       if(!autocvar_g_norecoil)
-       {
-               actor.punchangle_x = random () - 0.5;
-               actor.punchangle_y = random () - 0.5;
-       }
-
-       float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(hmg, spread_max));
-       fireBullet(actor, weaponentity, w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
-
-       actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
-
-       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
-       W_MachineGun_MuzzleFlash(actor, weaponentity);
-       W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
-
-       if (autocvar_g_casings >= 2) // casing code
-       {
-               makevectors(actor.v_angle); // for some reason, this is lost
-               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
-       }
-
-       int slot = weaponslot(weaponentity);
-       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor(actor);
-       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
-}
-
-METHOD(HeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
-{
-    if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
-        PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
-    else
-        PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
-}
-
-METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
-{
-    if(WEP_CVAR(hmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
-        thiswep.wr_reload(thiswep, actor, weaponentity);
-    } else
-    {
-        if (fire & 1)
-        if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
-        {
-            actor.(weaponentity).misc_bulletcounter = 0;
-            W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
-        }
-    }
-}
-
-METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
-{
-    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
-
-    if(autocvar_g_balance_hmg_reload_ammo)
-        ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-    return ammo_amount;
-}
-
-METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
-{
-    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
-
-    if(autocvar_g_balance_hmg_reload_ammo)
-        ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
-    return ammo_amount;
-}
-
-METHOD(HeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
-{
-    W_Reload(actor, weaponentity, WEP_CVAR(hmg, ammo), SND_RELOAD);
-}
-
-METHOD(HeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
-{
-    return WEAPON_THINKING_WITH_PORTALS;
-}
-
-METHOD(HeavyMachineGun, wr_killmessage, Notification(entity thiswep))
-{
-    if(w_deathtype & HITTYPE_SECONDARY)
-        return WEAPON_HMG_MURDER_SNIPE;
-    else
-        return WEAPON_HMG_MURDER_SPRAY;
-}
-
-#endif
-#ifdef CSQC
-
-METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
-{
-    vector org2;
-    org2 = w_org + w_backoff * 2;
-    pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
-    if(!w_issilent)
-        sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
-}
-
-#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/hmg.qh b/qcsrc/common/mutators/mutator/overkill/hmg.qh
deleted file mode 100644 (file)
index 99c8093..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include <common/weapons/all.qh>
-
-CLASS(HeavyMachineGun, Weapon)
-/* spawnfunc */ ATTRIB(HeavyMachineGun, m_canonical_spawnfunc, string, "weapon_hmg");
-/* ammotype  */ ATTRIB(HeavyMachineGun, ammo_type, int, RESOURCE_BULLETS);
-/* 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, 10000);
-/* 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));
-
-SPAWNFUNC_WEAPON(weapon_hmg, WEP_HMG)
diff --git a/qcsrc/common/mutators/mutator/overkill/okhmg.qc b/qcsrc/common/mutators/mutator/overkill/okhmg.qc
new file mode 100644 (file)
index 0000000..d278ca9
--- /dev/null
@@ -0,0 +1,168 @@
+#include "okhmg.qh"
+
+#ifdef SVQC
+
+REGISTER_MUTATOR(okhmg_nadesupport, true);
+MUTATOR_HOOKFUNCTION(okhmg_nadesupport, Nade_Damage)
+{
+       if (M_ARGV(1, entity) != WEP_OVERKILL_HMG) return;
+       return = true;
+       M_ARGV(3, float) /* damage */ = (M_ARGV(0, entity)).max_health * 0.1;
+}
+
+void W_OverkillHeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+       if (!PHYS_INPUT_BUTTON_ATCK(actor))
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       W_DecreaseAmmo(WEP_OVERKILL_HMG, actor, WEP_CVAR_PRI(okhmg, ammo), weaponentity);
+
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okhmg, damage), WEP_OVERKILL_HMG.m_id);
+
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random () - 0.5;
+               actor.punchangle_y = random () - 0.5;
+       }
+
+       float okhmg_spread = bound(WEP_CVAR_PRI(okhmg, spread_min), WEP_CVAR_PRI(okhmg, spread_min) + (WEP_CVAR_PRI(okhmg, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR_PRI(okhmg, spread_max));
+       fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okhmg_spread, WEP_CVAR_PRI(okhmg, solidpenetration), WEP_CVAR_PRI(okhmg, damage), WEP_CVAR_PRI(okhmg, force), WEP_OVERKILL_HMG.m_id, 0);
+
+       actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+       W_MachineGun_MuzzleFlash(actor, weaponentity);
+       W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+
+       if (autocvar_g_casings >= 2) // casing code
+       {
+               makevectors(actor.v_angle); // for some reason, this is lost
+               SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
+       }
+
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okhmg, refire) * W_WeaponRateFactor(actor);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okhmg, refire), W_OverkillHeavyMachineGun_Attack_Auto);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+    if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+        PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+    else
+        PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+       if ((WEP_CVAR_SEC(okhmg, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okhmg, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+    if (WEP_CVAR(okhmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okhmg, ammo))
+       {
+               // Forced reload.
+        thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+               {
+                       return;
+               }
+               actor.(weaponentity).misc_bulletcounter = 0;
+               W_OverkillHeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okhmg, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okhmg, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okhmg, animtime), w_ready);
+       }
+}
+
+METHOD(OverkillHeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okhmg, ammo);
+       if (autocvar_g_balance_okhmg_reload_ammo)
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_PRI(okhmg, ammo);
+       }
+       return ammo_amount;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(okhmg, ammo);
+       if (autocvar_g_balance_okhmg_reload_ammo)
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_SEC(okhmg, ammo);
+       }
+       return ammo_amount;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+    W_Reload(actor, weaponentity, WEP_CVAR_PRI(okhmg, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
+{
+    return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_killmessage, Notification(entity thiswep))
+{
+    if(w_deathtype & HITTYPE_SECONDARY)
+        return WEAPON_OVERKILL_HMG_MURDER_SNIPE;
+    else
+        return WEAPON_OVERKILL_HMG_MURDER_SPRAY;
+}
+
+#endif
+#ifdef CSQC
+
+METHOD(OverkillHeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+{
+    vector org2;
+    org2 = w_org + w_backoff * 2;
+    pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+    if(!w_issilent)
+        sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/okhmg.qh b/qcsrc/common/mutators/mutator/overkill/okhmg.qh
new file mode 100644 (file)
index 0000000..b3c2664
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+#include <common/weapons/all.qh>
+
+CLASS(OverkillHeavyMachineGun, Weapon)
+/* spawnfunc */ ATTRIB(OverkillHeavyMachineGun, m_canonical_spawnfunc, string, "weapon_okhmg");
+/* ammotype  */ ATTRIB(OverkillHeavyMachineGun, ammo_type, int, RESOURCE_BULLETS);
+/* impulse   */ ATTRIB(OverkillHeavyMachineGun, impulse, int, 3);
+/* flags     */ ATTRIB(OverkillHeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON);
+/* rating    */ ATTRIB(OverkillHeavyMachineGun, bot_pickupbasevalue, float, 10000);
+/* color     */ ATTRIB(OverkillHeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(OverkillHeavyMachineGun, mdl, string, "ok_hmg");
+#ifdef GAMEQC
+/* model     */ ATTRIB(OverkillHeavyMachineGun, m_model, Model, MDL_HMG_ITEM);
+#endif
+/* crosshair */ ATTRIB(OverkillHeavyMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(OverkillHeavyMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(OverkillHeavyMachineGun, model2, string, "weaponhmg");
+/* refname   */ ATTRIB(OverkillHeavyMachineGun, netname, string, "okhmg");
+/* wepname   */ ATTRIB(OverkillHeavyMachineGun, m_name, string, _("Overkill Heavy Machine Gun"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, PRI) \
+               P(class, prefix, damage, float, PRI) \
+               P(class, prefix, force, float, PRI) \
+               P(class, prefix, refire, float, PRI) \
+               P(class, prefix, solidpenetration, float, PRI) \
+               P(class, prefix, spread_add, float, PRI) \
+               P(class, prefix, spread_max, float, PRI) \
+               P(class, prefix, spread_min, float, PRI) \
+               P(class, prefix, ammo, float, SEC) \
+               P(class, prefix, animtime, float, SEC) \
+               P(class, prefix, damage, float, SEC) \
+               P(class, prefix, delay, float, SEC) \
+               P(class, prefix, edgedamage, float, SEC) \
+               P(class, prefix, force, float, SEC) \
+               P(class, prefix, lifetime, float, SEC) \
+               P(class, prefix, radius, float, SEC) \
+               P(class, prefix, refire, float, SEC) \
+               P(class, prefix, refire_type, float, SEC) \
+               P(class, prefix, shotangle, float, SEC) \
+               P(class, prefix, speed, float, SEC) \
+               P(class, prefix, spread, float, SEC) \
+               P(class, prefix, reload_ammo, float, NONE) \
+               P(class, prefix, reload_time, 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, OverkillHeavyMachineGun, okhmg)
+#undef X
+
+ENDCLASS(OverkillHeavyMachineGun)
+REGISTER_WEAPON(OVERKILL_HMG, okhmg, NEW(OverkillHeavyMachineGun));
+
+//SPAWNFUNC_WEAPON(weapon_okhmg, WEP_OVERKILL_HMG)
+//SPAWNFUNC_WEAPON(weapon_hmg, WEP_OVERKILL_HMG)
diff --git a/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc b/qcsrc/common/mutators/mutator/overkill/okmachinegun.qc
new file mode 100644 (file)
index 0000000..63c1e24
--- /dev/null
@@ -0,0 +1,156 @@
+#include "okmachinegun.qh"
+
+#ifdef SVQC
+
+void W_OverkillMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
+{
+       float okmachinegun_spread;
+
+       if(!(fire & 1))
+       {
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       if(!thiswep.wr_checkammo1(thiswep, actor, weaponentity))
+       if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       {
+               W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
+               w_ready(thiswep, actor, weaponentity, fire);
+               return;
+       }
+
+       W_DecreaseAmmo(WEP_OVERKILL_MACHINEGUN, actor, WEP_CVAR_PRI(okmachinegun, ammo), weaponentity);
+
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okmachinegun, damage), WEP_OVERKILL_MACHINEGUN.m_id);
+       if(!autocvar_g_norecoil)
+       {
+               actor.punchangle_x = random() - 0.5;
+               actor.punchangle_y = random() - 0.5;
+       }
+
+       okmachinegun_spread = bound(WEP_CVAR_PRI(okmachinegun, spread_min), WEP_CVAR_PRI(okmachinegun, spread_min) + (WEP_CVAR_PRI(okmachinegun, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR_PRI(okmachinegun, spread_max));
+       fireBullet(actor, weaponentity, w_shotorg, w_shotdir, okmachinegun_spread, WEP_CVAR_PRI(okmachinegun, solidpenetration), WEP_CVAR_PRI(okmachinegun, damage), WEP_CVAR_PRI(okmachinegun, force), WEP_OVERKILL_MACHINEGUN.m_id, 0);
+
+       actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+
+       Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+       W_MachineGun_MuzzleFlash(actor, weaponentity);
+       W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+
+       if(autocvar_g_casings >= 2) // casing code
+       {
+               makevectors(actor.v_angle); // for some reason, this is lost
+               SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
+       }
+
+       int slot = weaponslot(weaponentity);
+       ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okmachinegun, refire) * W_WeaponRateFactor(actor);
+       weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okmachinegun, refire), W_OverkillMachineGun_Attack_Auto);
+}
+
+METHOD(OverkillMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+               PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+       else
+               PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+}
+
+METHOD(OverkillMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+       if ((WEP_CVAR_SEC(okmachinegun, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okmachinegun, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+       if (WEP_CVAR(okmachinegun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okmachinegun, ammo))
+       {
+               // Forced reload
+               thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+               {
+                       return;
+               }
+               actor.(weaponentity).misc_bulletcounter = 0;
+               W_OverkillMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okmachinegun, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(okmachinegun, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okmachinegun, animtime), w_ready);
+       }
+}
+
+METHOD(OverkillMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount;
+       ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okmachinegun, ammo);
+       if (WEP_CVAR(okmachinegun, reload_ammo))
+       {
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR_PRI(okmachinegun, ammo);
+       }
+       return ammo_amount;
+}
+
+METHOD(OverkillMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       return true; // Blaster secondary is unlimited.
+}
+
+METHOD(OverkillMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(okmachinegun, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillMachineGun, wr_suicidemessage, Notification(entity thiswep))
+{
+       return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillMachineGun, wr_killmessage, Notification(entity thiswep))
+{
+       return WEAPON_OVERKILL_MACHINEGUN_MURDER;
+}
+
+#endif
+#ifdef CSQC
+
+METHOD(OverkillMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+{
+       vector org2;
+       org2 = w_org + w_backoff * 2;
+       pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+       if(!w_issilent)
+               sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
+}
+
+#endif
+
diff --git a/qcsrc/common/mutators/mutator/overkill/okmachinegun.qh b/qcsrc/common/mutators/mutator/overkill/okmachinegun.qh
new file mode 100644 (file)
index 0000000..997b49d
--- /dev/null
@@ -0,0 +1,57 @@
+#pragma once
+
+CLASS(OverkillMachineGun, Weapon)
+/* spawnfunc */ ATTRIB(OverkillMachineGun, m_canonical_spawnfunc, string, "weapon_okmachinegun");
+/* ammotype  */ ATTRIB(OverkillMachineGun, ammo_type, int, RESOURCE_BULLETS);
+/* impulse   */ ATTRIB(OverkillMachineGun, impulse, int, 3);
+/* flags        */ ATTRIB(OverkillMachineGun, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS | WEP_FLAG_MUTATORBLOCKED);
+/* rating      */ ATTRIB(OverkillMachineGun, bot_pickupbasevalue, float, 7000);
+/* color        */ ATTRIB(OverkillMachineGun, wpcolor, vector, '1 1 0');
+/* modelname */ ATTRIB(OverkillMachineGun, mdl, string, "ok_mg");
+#ifdef GAMEQC
+/* model        */ ATTRIB(OverkillMachineGun, m_model, Model, MDL_OK_MG_ITEM);
+#endif
+/* crosshair */ ATTRIB(OverkillMachineGun, w_crosshair, string, "gfx/crosshairuzi");
+/* crosshair */ ATTRIB(OverkillMachineGun, w_crosshair_size, float, 0.6);
+/* wepimg      */ ATTRIB(OverkillMachineGun, model2, string, "ok_weapon_smg");
+/* refname   */ ATTRIB(OverkillMachineGun, netname, string, "okmachinegun");
+/* wepname   */ ATTRIB(OverkillMachineGun, m_name, string, _("Overkill MachineGun"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, PRI) \
+               P(class, prefix, damage, float, PRI) \
+               P(class, prefix, force, float, PRI) \
+               P(class, prefix, refire, float, PRI) \
+               P(class, prefix, solidpenetration, float, PRI) \
+               P(class, prefix, spread_add, float, PRI) \
+               P(class, prefix, spread_max, float, PRI) \
+               P(class, prefix, spread_min, float, PRI) \
+               P(class, prefix, animtime, float, SEC) \
+               P(class, prefix, damage, float, SEC) \
+               P(class, prefix, delay, float, SEC) \
+               P(class, prefix, edgedamage, float, SEC) \
+               P(class, prefix, force, float, SEC) \
+               P(class, prefix, lifetime, float, SEC) \
+               P(class, prefix, radius, float, SEC) \
+               P(class, prefix, refire, float, SEC) \
+               P(class, prefix, refire_type, float, SEC) \
+               P(class, prefix, shotangle, float, SEC) \
+               P(class, prefix, speed, float, SEC) \
+               P(class, prefix, spread, float, SEC) \
+               P(class, prefix, reload_ammo, float, NONE) \
+               P(class, prefix, reload_time, 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, OverkillMachineGun, okmachinegun)
+#undef X
+
+ENDCLASS(OverkillMachineGun)
+REGISTER_WEAPON(OVERKILL_MACHINEGUN, okmachinegun, NEW(OverkillMachineGun));
+
+//SPAWNFUNC_WEAPON(weapon_okmachinegun, WEP_OVERKILL_MACHINEGUN)
diff --git a/qcsrc/common/mutators/mutator/overkill/oknex.qc b/qcsrc/common/mutators/mutator/overkill/oknex.qc
new file mode 100644 (file)
index 0000000..0f67ddb
--- /dev/null
@@ -0,0 +1,361 @@
+#include "oknex.qh"
+
+#ifdef SVQC
+
+.float oknex_lasthit;
+#endif
+
+#if defined(GAMEQC)
+
+METHOD(OverkillNex, wr_glow, vector(OverkillNex this, entity actor, entity wepent))
+{
+       if (!WEP_CVAR(oknex, charge)) return '0 0 0';
+       float charge = wepent.oknex_charge;
+       float animlimit = WEP_CVAR(oknex, charge_animlimit);
+       vector g;
+       g.x = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_half * min(1, charge / animlimit);
+       g.y = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_half * min(1, charge / animlimit);
+       g.z = autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_half * min(1, charge / animlimit);
+       if (charge > animlimit)
+       {
+               g.x += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_red_full * (charge - animlimit) / (1 - animlimit);
+               g.y += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_green_full * (charge - animlimit) / (1 - animlimit);
+               g.z += autocvar_g_weapon_charge_colormod_hdrmultiplier * autocvar_g_weapon_charge_colormod_blue_full * (charge - animlimit) / (1 - animlimit);
+       }
+       return g;
+}
+#endif
+
+#ifdef SVQC
+REGISTER_MUTATOR(oknex_charge, true);
+
+MUTATOR_HOOKFUNCTION(oknex_charge, GetPressedKeys)
+{
+       entity player = M_ARGV(0, entity);
+
+       // WEAPONTODO
+       if(!WEP_CVAR(oknex, charge) || !WEP_CVAR(oknex, charge_velocity_rate))
+               return;
+
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+
+               if (player.(weaponentity).m_weapon == WEP_OVERKILL_NEX && WEP_CVAR(oknex, charge) && WEP_CVAR(oknex, charge_velocity_rate) && vdist(vec2(player.velocity), >, WEP_CVAR(oknex, charge_minspeed)))
+               {
+                       float xyspeed = vlen(vec2(player.velocity));
+                       // add a maximum of charge_velocity_rate when going fast (f = 1), gradually increasing from minspeed (f = 0) to maxspeed
+                               xyspeed = min(xyspeed, WEP_CVAR(oknex, charge_maxspeed));
+                       float f = (xyspeed - WEP_CVAR(oknex, charge_minspeed)) / (WEP_CVAR(oknex, charge_maxspeed) - WEP_CVAR(oknex, charge_minspeed));
+                       // add the extra charge
+                       player.(weaponentity).oknex_charge = min(1, player.(weaponentity).oknex_charge + WEP_CVAR(oknex, charge_velocity_rate) * f * PHYS_INPUT_TIMELENGTH);
+               }
+       }
+}
+
+void W_OverkillNex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float issecondary)
+{
+       float mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, myammo, charge;
+
+       mydmg = WEP_CVAR_BOTH(oknex, !issecondary, damage);
+       myforce = WEP_CVAR_BOTH(oknex, !issecondary, force);
+       mymindist = WEP_CVAR_BOTH(oknex, !issecondary, damagefalloff_mindist);
+       mymaxdist = WEP_CVAR_BOTH(oknex, !issecondary, damagefalloff_maxdist);
+       myhalflife = WEP_CVAR_BOTH(oknex, !issecondary, damagefalloff_halflife);
+       myforcehalflife = WEP_CVAR_BOTH(oknex, !issecondary, damagefalloff_forcehalflife);
+       myammo = WEP_CVAR_BOTH(oknex, !issecondary, ammo);
+
+       float flying;
+       flying = IsFlying(actor); // do this BEFORE to make the trace values from FireRailgunBullet last
+
+       if (WEP_CVAR(oknex, charge))
+       {
+               charge = WEP_CVAR(oknex, charge_mindmg) / mydmg + (1 - WEP_CVAR(oknex, charge_mindmg) / mydmg) * actor.(weaponentity).oknex_charge;
+               actor.(weaponentity).oknex_charge *= WEP_CVAR(oknex, charge_shot_multiplier); // do this AFTER setting mydmg/myforce
+               // O RLY? -- divVerent
+               // YA RLY -- FruitieX
+       }
+       else
+       {
+               charge = 1;
+       }
+       mydmg *= charge;
+       myforce *= charge;
+
+       W_SetupShot(actor, weaponentity, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg, WEP_OVERKILL_NEX.m_id);
+       if(charge > WEP_CVAR(oknex, charge_animlimit) && WEP_CVAR(oknex, charge_animlimit)) // if the OverkillNex is overcharged, we play an extra sound
+       {
+               sound(actor, CH_WEAPON_B, SND_NEXCHARGE, VOL_BASE * (charge - 0.5 * WEP_CVAR(oknex, charge_animlimit)) / (1 - 0.5 * WEP_CVAR(oknex, charge_animlimit)), ATTN_NORM);
+       }
+
+       yoda = 0;
+       damage_goodhits = 0;
+       FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_OVERKILL_NEX.m_id);
+
+       if(yoda && flying)
+               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
+       if(damage_goodhits && actor.oknex_lasthit)
+       {
+               Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_IMPRESSIVE);
+               damage_goodhits = 0; // only every second time
+       }
+
+       actor.oknex_lasthit = damage_goodhits;
+
+       //beam and muzzle flash done on client
+       SendCSQCVortexBeamParticle(charge);
+
+       W_DecreaseAmmo(thiswep, actor, myammo, weaponentity);
+}
+
+.float oknex_chargepool_pauseregen_finished;
+
+METHOD(OverkillNex, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       if(bot_aim(actor, weaponentity, 1000000, 0, 1, false))
+               PHYS_INPUT_BUTTON_ATCK(actor) = true;
+       else
+       {
+               if(WEP_CVAR(oknex, charge))
+                       PHYS_INPUT_BUTTON_ATCK2(actor) = true;
+       }
+}
+
+METHOD(OverkillNex, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+       if (WEP_CVAR(oknex, charge) && actor.(weaponentity).oknex_charge < WEP_CVAR(oknex, charge_limit))
+       {
+               actor.(weaponentity).oknex_charge = min(1, actor.(weaponentity).oknex_charge + WEP_CVAR(oknex, charge_rate) * frametime / W_TICSPERFRAME);
+       }
+
+       if (WEP_CVAR_SEC(oknex, chargepool))
+               if (actor.(weaponentity).oknex_chargepool_ammo < 1)
+               {
+                       if (actor.oknex_chargepool_pauseregen_finished < time)
+                               actor.(weaponentity).oknex_chargepool_ammo = min(1, actor.(weaponentity).oknex_chargepool_ammo + WEP_CVAR_SEC(oknex, chargepool_regen) * frametime / W_TICSPERFRAME);
+                       actor.pauseregen_finished = max(actor.pauseregen_finished, time + WEP_CVAR_SEC(oknex, chargepool_pause_regen));
+               }
+
+       if ((WEP_CVAR_SEC(oknex, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(oknex, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(oknex, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+
+       if (autocvar_g_balance_oknex_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR_PRI(oknex, ammo))
+       {
+               // Rorced reload
+               thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(oknex, refire)))
+               {
+                       return;
+               }
+               W_OverkillNex_Attack(thiswep, actor, weaponentity, 0);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(oknex, animtime), w_ready);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR(oknex, secondary) == 2) && (WEP_CVAR_SEC(oknex, refire_type) == 0))
+       {
+               // Secondary attack
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(oknex, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(oknex, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(oknex, animtime), w_ready);
+               return;
+       }
+       //if ((WEP_CVAR(oknex, charge) && (WEP_CVAR(oknex, secondary) == 1)) ? (PHYS_INPUT_BUTTON_ZOOM(actor) | PHYS_INPUT_BUTTON_ZOOMSCRIPT(actor)) : (fire & 2))
+       //{
+       //      if(WEP_CVAR(oknex, charge))
+       //      {
+       //              actor.(weaponentity).oknex_charge_rottime = time + WEP_CVAR(oknex, charge_rot_pause);
+       //              float dt = frametime / W_TICSPERFRAME;
+       //
+       //              if(actor.(weaponentity).oknex_charge < 1)
+       //              {
+       //                      if(WEP_CVAR_SEC(oknex, chargepool))
+       //                      {
+       //                              if(WEP_CVAR_SEC(oknex, ammo))
+       //                              {
+       //                                      // always deplete if secondary is held
+       //                                      actor.(weaponentity).oknex_chargepool_ammo = max(0, actor.(weaponentity).oknex_chargepool_ammo - WEP_CVAR_SEC(oknex, ammo) * dt);
+
+       //                                      dt = min(dt, (1 - actor.(weaponentity).oknex_charge) / WEP_CVAR(oknex, charge_rate));
+       //                                      actor.oknex_chargepool_pauseregen_finished = time + WEP_CVAR_SEC(oknex, chargepool_pause_regen);
+       //                                      dt = min(dt, actor.(weaponentity).oknex_chargepool_ammo);
+       //                                      dt = max(0, dt);
+
+       //                                      actor.(weaponentity).oknex_charge += dt * WEP_CVAR(oknex, charge_rate);
+       //                              }
+       //                      }
+
+       //                      else if(WEP_CVAR_SEC(oknex, ammo))
+       //                      {
+       //                              if(fire & 2) // only eat ammo when the button is pressed
+       //                              {
+       //                                      dt = min(dt, (1 - actor.(weaponentity).oknex_charge) / WEP_CVAR(oknex, charge_rate));
+       //                                      if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
+       //                                      {
+       //                                              // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
+       //                                              if(autocvar_g_balance_vortex_reload_ammo)
+       //                                              {
+       //                                                      dt = min(dt, (actor.(weaponentity).clip_load - WEP_CVAR_PRI(oknex, ammo)) / WEP_CVAR_SEC(oknex, ammo));
+       //                                                      dt = max(0, dt);
+       //                                                      if(dt > 0)
+       //                                                      {
+       //                                                              actor.(weaponentity).clip_load = max(WEP_CVAR_SEC(oknex, ammo), actor.(weaponentity).clip_load - WEP_CVAR_SEC(oknex, ammo) * dt);
+       //                                                      }
+       //                                                      actor.(weaponentity).(weapon_load[WEP_OVERKILL_NEX.m_id]) = actor.(weaponentity).clip_load;
+       //                                              }
+       //                                              else
+       //                                              {
+       //                                                      dt = min(dt, (actor.(thiswep.ammo_field) - WEP_CVAR_PRI(oknex, ammo)) / WEP_CVAR_SEC(oknex, ammo));
+       //                                                      dt = max(0, dt);
+       //                                                      if(dt > 0)
+       //                                                      {
+       //                                                              actor.(thiswep.ammo_field) = max(WEP_CVAR_SEC(oknex, ammo), actor.(thiswep.ammo_field) - WEP_CVAR_SEC(oknex, ammo) * dt);
+       //                                                      }
+       //                                              }
+       //                                      }
+       //                                      actor.(weaponentity).oknex_charge += dt * WEP_CVAR(oknex, charge_rate);
+       //                              }
+       //                      }
+
+       //                      else
+       //                      {
+       //                              dt = min(dt, (1 - actor.(weaponentity).oknex_charge) / WEP_CVAR(oknex, charge_rate));
+       //                              actor.(weaponentity).oknex_charge += dt * WEP_CVAR(oknex, charge_rate);
+       //                      }
+       //              }
+       //      }
+       //      else if(WEP_CVAR(oknex, secondary))
+       //      {
+       //              if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(oknex, refire)))
+       //              {
+       //                      W_OverkillNex_Attack(thiswep, actor, weaponentity, 1);
+       //                      weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(oknex, animtime), w_ready);
+       //              }
+       //      }
+       //}
+}
+
+METHOD(OverkillNex, wr_setup, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       actor.oknex_lasthit = 0;
+}
+
+METHOD(OverkillNex, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(oknex, ammo);
+       ammo_amount += (autocvar_g_balance_oknex_reload_ammo && actor.(weaponentity).(weapon_load[WEP_OVERKILL_NEX.m_id]) >= WEP_CVAR_PRI(oknex, ammo));
+       return ammo_amount;
+}
+
+METHOD(OverkillNex, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       if (WEP_CVAR(oknex, secondary))
+       {
+               // don't allow charging if we don't have enough ammo
+               float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(oknex, ammo);
+               ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_NEX.m_id]) >= WEP_CVAR_SEC(oknex, ammo);
+               return ammo_amount;
+       }
+       else
+       {
+               return false; // zoom is not a fire mode
+       }
+}
+
+METHOD(OverkillNex, wr_resetplayer, void(entity thiswep, entity actor))
+{
+       if (WEP_CVAR(oknex, charge)) {
+               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               {
+                       .entity weaponentity = weaponentities[slot];
+                       actor.(weaponentity).oknex_charge = WEP_CVAR(oknex, charge_start);
+               }
+       }
+       actor.oknex_lasthit = 0;
+}
+
+METHOD(OverkillNex, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(oknex, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillNex, wr_suicidemessage, Notification(entity thiswep))
+{
+       return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillNex, wr_killmessage, Notification(entity thiswep))
+{
+       return WEAPON_OVERKILL_NEX_MURDER;
+}
+
+METHOD(OverkillNex, wr_zoom, bool(entity thiswep, entity actor))
+{
+       return PHYS_INPUT_BUTTON_ATCK2(actor) && !WEP_CVAR(oknex, secondary);
+}
+
+#endif
+#ifdef CSQC
+
+METHOD(OverkillNex, wr_impacteffect, void(entity thiswep, entity actor))
+{
+       entity this = actor;
+       vector org2 = w_org + w_backoff * 6;
+       pointparticles(EFFECT_VORTEX_IMPACT, org2, '0 0 0', 1);
+       if(!w_issilent)
+               sound(this, CH_SHOTS, SND_NEXIMPACT, VOL_BASE, ATTN_NORM);
+}
+
+METHOD(OverkillNex, wr_init, void(entity thiswep))
+{
+       if(autocvar_cl_reticle && autocvar_cl_reticle_weapon)
+       {
+               precache_pic("gfx/reticle_nex");
+       }
+}
+
+METHOD(OverkillNex, wr_zoom, bool(entity thiswep, entity actor))
+{
+       if(button_zoom || zoomscript_caught || (!WEP_CVAR(oknex, secondary) && button_attack2))
+       {
+               return true;
+       }
+       else
+       {
+               // no weapon specific image for this weapon
+               return false;
+       }
+}
+
+METHOD(OverkillNex, wr_zoomdir, bool(entity thiswep))
+{
+    return button_attack2 && !WEP_CVAR(oknex, secondary);
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/oknex.qh b/qcsrc/common/mutators/mutator/overkill/oknex.qh
new file mode 100644 (file)
index 0000000..f38588e
--- /dev/null
@@ -0,0 +1,77 @@
+#pragma once
+
+CLASS(OverkillNex, Weapon)
+/* spawnfunc */ ATTRIB(OverkillNex, m_canonical_spawnfunc, string, "weapon_oknex");
+/* ammotype  */ ATTRIB(OverkillNex, ammo_type, int, RESOURCE_CELLS);
+/* impulse   */ ATTRIB(OverkillNex, impulse, int, 7);
+/* flags     */ ATTRIB(OverkillNex, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_MUTATORBLOCKED);
+/* rating    */ ATTRIB(OverkillNex, bot_pickupbasevalue, float, 8000);
+/* color     */ ATTRIB(OverkillNex, wpcolor, vector, '0.5 1 1');
+/* modelname */ ATTRIB(OverkillNex, mdl, string, "ok_sniper");
+#ifdef GAMEQC
+/* model     */ ATTRIB(OverkillNex, m_model, Model, MDL_OK_SNIPER_ITEM);
+#endif
+/* crosshair */ ATTRIB(OverkillNex, w_crosshair, string, "gfx/crosshairnex");
+/* crosshair */ ATTRIB(OverkillNex, w_crosshair_size, float, 0.65);
+/* reticle   */ ATTRIB(OverkillNex, w_reticle, string, "gfx/reticle_nex");
+/* wepimg    */ ATTRIB(OverkillNex, model2, string, "ok_weapon_rail");
+/* refname   */ ATTRIB(OverkillNex, netname, string, "oknex");
+/* wepname   */ ATTRIB(OverkillNex, m_name, string, _("Overkill Nex"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, PRI) \
+               P(class, prefix, animtime, float, PRI) \
+               P(class, prefix, chargepool, float, SEC) \
+               P(class, prefix, chargepool_pause_regen, float, SEC) \
+               P(class, prefix, chargepool_regen, float, SEC) \
+               P(class, prefix, charge, float, NONE) \
+               P(class, prefix, charge_animlimit, float, NONE) \
+               P(class, prefix, charge_limit, float, NONE) \
+               P(class, prefix, charge_maxspeed, float, NONE) \
+               P(class, prefix, charge_mindmg, float, NONE) \
+               P(class, prefix, charge_minspeed, float, NONE) \
+               P(class, prefix, charge_rate, float, NONE) \
+               P(class, prefix, charge_rot_pause, float, NONE) \
+               P(class, prefix, charge_rot_rate, float, NONE) \
+               P(class, prefix, charge_shot_multiplier, float, NONE) \
+               P(class, prefix, charge_start, float, NONE) \
+               P(class, prefix, charge_velocity_rate, float, NONE) \
+               P(class, prefix, damagefalloff_forcehalflife, float, BOTH) \
+               P(class, prefix, damagefalloff_halflife, float, BOTH) \
+               P(class, prefix, damagefalloff_maxdist, float, BOTH) \
+               P(class, prefix, damagefalloff_mindist, float, BOTH) \
+               P(class, prefix, damage, float, PRI) \
+               P(class, prefix, force, float, PRI) \
+               P(class, prefix, refire, float, PRI) \
+               P(class, prefix, secondary, float, NONE) \
+               P(class, prefix, reload_ammo, float, NONE) \
+        P(class, prefix, reload_time, float, NONE) \
+        P(class, prefix, switchdelay_raise, float, NONE) \
+        P(class, prefix, switchdelay_drop, float, NONE) \
+        P(class, prefix, weaponreplace, string, NONE) \
+        P(class, prefix, weaponstart, float, NONE) \
+        P(class, prefix, weaponstartoverride, float, NONE) \
+        P(class, prefix, weaponthrowable, float, NONE) \
+               P(class, prefix, ammo, float, SEC) \
+               P(class, prefix, animtime, float, SEC) \
+               P(class, prefix, damage, float, SEC) \
+               P(class, prefix, delay, float, SEC) \
+               P(class, prefix, edgedamage, float, SEC) \
+               P(class, prefix, force, float, SEC) \
+               P(class, prefix, lifetime, float, SEC) \
+               P(class, prefix, radius, float, SEC) \
+               P(class, prefix, refire, float, SEC) \
+               P(class, prefix, refire_type, float, SEC) \
+               P(class, prefix, shotangle, float, SEC) \
+               P(class, prefix, speed, float, SEC) \
+               P(class, prefix, spread, float, SEC) \
+       END()
+    W_PROPS(X, OverkillNex, oknex)
+#undef X
+
+ENDCLASS(OverkillNex)
+REGISTER_WEAPON(OVERKILL_NEX, oknex, NEW(OverkillNex));
+
+
+//SPAWNFUNC_WEAPON(weapon_oknex, WEP_OVERKILL_NEX)
diff --git a/qcsrc/common/mutators/mutator/overkill/okrpc.qc b/qcsrc/common/mutators/mutator/overkill/okrpc.qc
new file mode 100644 (file)
index 0000000..c786a92
--- /dev/null
@@ -0,0 +1,242 @@
+#include "okrpc.qh"
+
+#ifdef SVQC
+
+.float m_chainsaw_damage; // accumulated damage of the missile as it passes trough enemies
+
+void W_OverkillRocketPropelledChainsaw_Explode(entity this, entity directhitentity)
+{
+       this.event_damage = func_null;
+       this.takedamage = DAMAGE_NO;
+
+       float explosion_damage = RadiusDamage(this, this.realowner, WEP_CVAR_PRI(okrpc, damage), WEP_CVAR_PRI(okrpc, edgedamage), WEP_CVAR_PRI(okrpc, radius), NULL, NULL, WEP_CVAR_PRI(okrpc, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+       if (explosion_damage > 0 && this.m_chainsaw_damage > 0)
+       {
+               // if chainsaw hit something, it removed fired damage (so that direct hit is 100%)
+               // now that we also damaged something by explosion we'd go over 100% so let's add the fired damage back
+               accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, WEP_CVAR(okrpc, damage), 0);
+       }
+
+       delete(this);
+}
+
+void W_OverkillRocketPropelledChainsaw_Explode_think(entity this)
+{
+       W_OverkillRocketPropelledChainsaw_Explode(this, NULL);
+}
+
+void W_OverkillRocketPropelledChainsaw_Touch (entity this, entity toucher)
+{
+       if(WarpZone_Projectile_Touch(this, toucher))
+               if(wasfreed(this))
+                       return;
+
+       W_OverkillRocketPropelledChainsaw_Explode(this, toucher);
+}
+
+void W_OverkillRocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+       if (this.health <= 0)
+               return;
+
+       if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
+               return; // g_projectiles_damage says to halt
+
+       this.health = this.health - damage;
+
+       if (this.health <= 0)
+               W_PrepareExplosionByDamage(this, attacker, W_OverkillRocketPropelledChainsaw_Explode_think);
+}
+
+void W_OverkillRocketPropelledChainsaw_Think(entity this)
+{
+       if(this.cnt <= time)
+       {
+               delete(this);
+               return;
+       }
+
+       float myspeed = vlen(this.velocity);
+       float myspeed_accel = myspeed * sys_frametime;
+       vector mydir = normalize(this.velocity);
+
+       tracebox(this.origin, this.mins, this.maxs, this.origin + mydir * (2 * myspeed_accel), MOVE_NORMAL, this);
+       if (IS_PLAYER(trace_ent))
+       {
+               if (accuracy_isgooddamage(this.realowner, trace_ent))
+               {
+                       if (this.m_chainsaw_damage == 0) // first hit
+                       {
+                               // The fired damage of the explosion is already counted in the statistics (when launching the chainsaw).
+                               // We remove it here so that a direct hit that passes through and doesn't damage anything by the explosion later is still 100%.
+                               float fired_damage = WEP_CVAR_PRI(okrpc, damage2) - WEP_CVAR_PRI(okrpc, damage);
+                               float hit_damage = WEP_CVAR_PRI(okrpc, damage2);
+                               accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, fired_damage, hit_damage);
+                       }
+                       this.m_chainsaw_damage += WEP_CVAR_PRI(okrpc, damage2);
+               }
+               Damage(trace_ent, this, this.realowner, WEP_CVAR_PRI(okrpc, damage2), this.projectiledeathtype, this.weaponentity_fld, this.origin, normalize(this.origin - trace_ent.origin) * WEP_CVAR_PRI(okrpc, force));
+       }
+
+       this.velocity = mydir * (myspeed + (WEP_CVAR_PRI(okrpc, speedaccel) * sys_frametime));
+
+       UpdateCSQCProjectile(this);
+       this.nextthink = time;
+}
+
+void W_OverkillRocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity weaponentity)
+{
+       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor);
+       entity flash = spawn ();
+
+       W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(okrpc, ammo), weaponentity);
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okrpc, damage), WEP_OVERKILL_RPC.m_id);
+       Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+       PROJECTILE_MAKETRIGGER(missile);
+
+       missile.owner = missile.realowner = actor;
+       missile.bot_dodge = true;
+       missile.bot_dodgerating = WEP_CVAR_PRI(okrpc, damage) * 2;
+
+       missile.takedamage = DAMAGE_YES;
+       missile.damageforcescale = WEP_CVAR_PRI(okrpc, damageforcescale);
+       missile.health = WEP_CVAR_PRI(okrpc, health);
+       missile.event_damage = W_OverkillRocketPropelledChainsaw_Damage;
+       missile.damagedbycontents = true;
+       IL_PUSH(g_damagedbycontents, missile);
+       set_movetype(missile, MOVETYPE_FLY);
+
+       missile.projectiledeathtype = WEP_OVERKILL_RPC.m_id;
+       missile.weaponentity_fld = weaponentity;
+       setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+       setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
+       W_SetupProjVelocity_Basic(missile, WEP_CVAR_PRI(okrpc, speed), 0);
+
+       settouch(missile, W_OverkillRocketPropelledChainsaw_Touch);
+
+       setthink(missile, W_OverkillRocketPropelledChainsaw_Think);
+       missile.cnt = time + WEP_CVAR_PRI(okrpc, lifetime);
+       missile.nextthink = time;
+       missile.flags = FL_PROJECTILE;
+       IL_PUSH(g_projectiles, missile);
+       IL_PUSH(g_bot_dodge, missile);
+
+       CSQCProjectile(missile, true, PROJECTILE_RPC, false);
+
+       setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
+       SUB_SetFade (flash, time, 0.1);
+       flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+       W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
+       missile.m_chainsaw_damage = 0;
+
+       MUTATOR_CALLHOOK(EditProjectile, actor, missile);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+    PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+       if ((WEP_CVAR_SEC(okrpc, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okrpc, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okrpc, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+       if (WEP_CVAR(okrpc, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okrpc, ammo))
+       {
+               // Forced reload
+               thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(okrpc, refire)))
+               {
+                       return;
+               }
+               W_OverkillRocketPropelledChainsaw_Attack(thiswep, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okrpc, animtime), w_ready);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okrpc, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okrpc, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okrpc, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okrpc, animtime), w_ready);
+       }
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okrpc, ammo);
+       ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_RPC.m_id]) >= WEP_CVAR_PRI(okrpc, ammo);
+       return ammo_amount;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(okrpc, ammo);
+       ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_RPC.m_id]) >= WEP_CVAR_SEC(okrpc, ammo);
+       return ammo_amount;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+    W_Reload(actor, weaponentity, WEP_CVAR_PRI(okrpc, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
+{
+    if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+        return WEAPON_OVERKILL_RPC_SUICIDE_SPLASH;
+    else
+        return WEAPON_OVERKILL_RPC_SUICIDE_DIRECT;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_killmessage, Notification(entity thiswep))
+{
+    if(w_deathtype & HITTYPE_SECONDARY)
+        return WEAPON_BLASTER_MURDER;
+    else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+        return WEAPON_OVERKILL_RPC_MURDER_SPLASH;
+    else
+        return WEAPON_OVERKILL_RPC_MURDER_DIRECT;
+}
+
+#endif
+
+#ifdef CSQC
+
+METHOD(OverkillRocketPropelledChainsaw, wr_impacteffect, void(entity thiswep, entity actor))
+{
+    vector org2;
+    org2 = w_org + w_backoff * 12;
+    pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+    if(!w_issilent)
+        sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/okrpc.qh b/qcsrc/common/mutators/mutator/overkill/okrpc.qh
new file mode 100644 (file)
index 0000000..4f9bfe7
--- /dev/null
@@ -0,0 +1,66 @@
+#pragma once
+
+#include <common/weapons/all.qh>
+
+CLASS(OverkillRocketPropelledChainsaw, Weapon)
+/* spawnfunc */ ATTRIB(OverkillRocketPropelledChainsaw, m_canonical_spawnfunc, string, "weapon_okrpc");
+/* ammotype  */ ATTRIB(OverkillRocketPropelledChainsaw, ammo_type, int, RESOURCE_ROCKETS);
+/* impulse   */ ATTRIB(OverkillRocketPropelledChainsaw, impulse, int, 9);
+/* flags     */ ATTRIB(OverkillRocketPropelledChainsaw, 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(OverkillRocketPropelledChainsaw, bot_pickupbasevalue, float, 10000);
+/* color     */ ATTRIB(OverkillRocketPropelledChainsaw, wpcolor, vector, '0.5 0.5 0');
+/* modelname */ ATTRIB(OverkillRocketPropelledChainsaw, mdl, string, "ok_rl");
+#ifdef GAMEQC
+/* model     */ ATTRIB(OverkillRocketPropelledChainsaw, m_model, Model, MDL_RPC_ITEM);
+#endif
+/* crosshair */ ATTRIB(OverkillRocketPropelledChainsaw, w_crosshair, string, "gfx/crosshairrocketlauncher");
+/* crosshair */ ATTRIB(OverkillRocketPropelledChainsaw, w_crosshair_size, float, 0.6);
+/* wepimg    */ ATTRIB(OverkillRocketPropelledChainsaw, model2, string, "weaponrpc");
+/* refname   */ ATTRIB(OverkillRocketPropelledChainsaw, netname, string, "okrpc");
+/* wepname   */ ATTRIB(OverkillRocketPropelledChainsaw, m_name, string, _("Overkill Rocket Propelled Chainsaw"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, PRI) \
+               P(class, prefix, animtime, float, PRI) \
+               P(class, prefix, damage, float, PRI) \
+               P(class, prefix, damage2, float, PRI) \
+               P(class, prefix, damageforcescale, float, PRI) \
+               P(class, prefix, edgedamage, float, PRI) \
+               P(class, prefix, force, float, PRI) \
+               P(class, prefix, health, float, PRI) \
+               P(class, prefix, lifetime, float, PRI) \
+               P(class, prefix, radius, float, PRI) \
+               P(class, prefix, refire, float, PRI) \
+               P(class, prefix, speedaccel, float, PRI) \
+               P(class, prefix, speed, float, PRI) \
+               P(class, prefix, ammo, float, SEC) \
+               P(class, prefix, animtime, float, SEC) \
+               P(class, prefix, damage, float, SEC) \
+               P(class, prefix, delay, float, SEC) \
+               P(class, prefix, edgedamage, float, SEC) \
+               P(class, prefix, force, float, SEC) \
+               P(class, prefix, lifetime, float, SEC) \
+               P(class, prefix, radius, float, SEC) \
+               P(class, prefix, refire, float, SEC) \
+               P(class, prefix, refire_type, float, SEC) \
+               P(class, prefix, shotangle, float, SEC) \
+               P(class, prefix, speed, float, SEC) \
+               P(class, prefix, spread, float, SEC) \
+               P(class, prefix, reload_ammo, float, NONE) \
+        P(class, prefix, reload_time, 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, OverkillRocketPropelledChainsaw, okrpc)
+#undef X
+
+ENDCLASS(OverkillRocketPropelledChainsaw)
+REGISTER_WEAPON(OVERKILL_RPC, okrpc, NEW(OverkillRocketPropelledChainsaw));
+
+//SPAWNFUNC_WEAPON(weapon_okrpc, WEP_OVERKILL_RPC)
+//SPAWNFUNC_WEAPON(weapon_rpc, WEP_OVERKILL_RPC)
diff --git a/qcsrc/common/mutators/mutator/overkill/okshotgun.qc b/qcsrc/common/mutators/mutator/overkill/okshotgun.qc
new file mode 100644 (file)
index 0000000..2f16517
--- /dev/null
@@ -0,0 +1,116 @@
+#include "okshotgun.qh"
+
+#ifdef SVQC
+METHOD(OverkillShotgun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       if (vdist(actor.origin - actor.enemy.origin, >, WEP_CVAR_PRI(okshotgun, bot_range)))
+       {
+               PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+       }
+       else
+       {
+               PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+       }
+}
+
+METHOD(OverkillShotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+       if ((WEP_CVAR_SEC(okshotgun, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+       {
+               // Secondary uses it's own refire timer if refire_type is 1.
+               actor.jump_interval = time + WEP_CVAR_SEC(okshotgun, refire) * W_WeaponRateFactor(actor);
+               BLASTER_SECONDARY_ATTACK(okshotgun, actor, weaponentity);
+               if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+                       (actor.(weaponentity).wframe == WFRAME_FIRE2))
+               {
+                       // Set secondary fire animation.
+                       vector a = '0 0 0';
+                       actor.(weaponentity).wframe = WFRAME_FIRE2;
+                       a = actor.(weaponentity).anim_fire2;
+                       a.z *= g_weaponratefactor;
+                       FOREACH_CLIENT(true, LAMBDA(
+                               if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+                               {
+                                       wframe_send(it, actor.(weaponentity), a, true);
+                               }
+                       ));
+                       animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+               }
+       }
+       if (WEP_CVAR(okshotgun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okshotgun, ammo))
+       {
+               // Forced reload
+               thiswep.wr_reload(thiswep, actor, weaponentity);
+               return;
+       }
+       if (fire & 1) // Primary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(okshotgun, animtime)))
+               {
+                       return;
+               }
+               W_Shotgun_Attack(thiswep, actor, weaponentity, true,
+                       WEP_CVAR_PRI(okshotgun, ammo),
+                       WEP_CVAR_PRI(okshotgun, damage),
+                       WEP_CVAR_PRI(okshotgun, bullets),
+                       WEP_CVAR_PRI(okshotgun, spread),
+                       WEP_CVAR_PRI(okshotgun, solidpenetration),
+                       WEP_CVAR_PRI(okshotgun, force));
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okshotgun, animtime), w_ready);
+               return;
+       }
+       if ((fire & 2) && (WEP_CVAR_SEC(okshotgun, refire_type) == 0)) // Secondary attack
+       {
+               if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okshotgun, refire)))
+               {
+                       return;
+               }
+               BLASTER_SECONDARY_ATTACK(okshotgun, actor, weaponentity);
+               weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okshotgun, animtime), w_ready);
+       }
+}
+
+METHOD(OverkillShotgun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okshotgun, ammo);
+       ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_SHOTGUN.m_id]) >= WEP_CVAR_PRI(okshotgun, ammo);
+       return ammo_amount;
+}
+
+METHOD(OverkillShotgun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+       return true; // Blaster secondary is unlimited.
+}
+
+METHOD(OverkillShotgun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+       W_Reload(actor, weaponentity, WEP_CVAR_PRI(okshotgun, ammo), SND_RELOAD); // WEAPONTODO
+}
+
+METHOD(OverkillShotgun, wr_suicidemessage, Notification(entity thiswep))
+{
+       return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillShotgun, wr_killmessage, Notification(entity thiswep))
+{
+       return WEAPON_OVERKILL_SHOTGUN_MURDER;
+}
+
+#endif
+#ifdef CSQC
+.float prevric;
+
+METHOD(OverkillShotgun, wr_impacteffect, void(entity thiswep, entity actor))
+{
+       vector org2 = w_org + w_backoff * 2;
+       pointparticles(EFFECT_SHOTGUN_IMPACT, org2, w_backoff * 1000, 1);
+       if(!w_issilent && time - actor.prevric > 0.25)
+       {
+               if(w_random < 0.05)
+                       sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+               actor.prevric = time;
+       }
+}
+
+#endif
diff --git a/qcsrc/common/mutators/mutator/overkill/okshotgun.qh b/qcsrc/common/mutators/mutator/overkill/okshotgun.qh
new file mode 100644 (file)
index 0000000..a383c9d
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+
+CLASS(OverkillShotgun, Weapon)
+/* spawnfunc */ ATTRIB(OverkillShotgun, m_canonical_spawnfunc, string, "weapon_okshotgun");
+/* ammotype  */ ATTRIB(OverkillShotgun, ammo_type, int, RESOURCE_SHELLS);
+/* impulse   */ ATTRIB(OverkillShotgun, impulse, int, 2);
+/* flags     */ ATTRIB(OverkillShotgun, spawnflags, int, WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_MUTATORBLOCKED);
+/* rating    */ ATTRIB(OverkillShotgun, bot_pickupbasevalue, float, 6000);
+/* color     */ ATTRIB(OverkillShotgun, wpcolor, vector, '0.5 0.25 0');
+/* modelname */ ATTRIB(OverkillShotgun, mdl, string, "ok_shotgun");
+#ifdef GAMEQC
+/* model     */ ATTRIB(OverkillShotgun, m_model, Model, MDL_OK_SHOTGUN_ITEM);
+#endif
+/* crosshair */ ATTRIB(OverkillShotgun, w_crosshair, string, "gfx/crosshairshotgun");
+/* crosshair */ ATTRIB(OverkillShotgun, w_crosshair_size, float, 0.65);
+/* wepimg    */ ATTRIB(OverkillShotgun, model2, string, "ok_weapon_shotgun");
+/* refname   */ ATTRIB(OverkillShotgun, netname, string, "okshotgun");
+/* wepname   */ ATTRIB(OverkillShotgun, m_name, string, _("Overkill Shotgun"));
+
+#define X(BEGIN, P, END, class, prefix) \
+       BEGIN(class) \
+               P(class, prefix, ammo, float, PRI) \
+               P(class, prefix, animtime, float, PRI) \
+               P(class, prefix, bot_range, float, PRI) \
+               P(class, prefix, bullets, float, PRI) \
+               P(class, prefix, damage, float, PRI) \
+               P(class, prefix, force, float, PRI) \
+               P(class, prefix, refire, float, PRI) \
+               P(class, prefix, solidpenetration, float, PRI) \
+               P(class, prefix, spread, float, PRI) \
+               P(class, prefix, animtime, float, SEC) \
+               P(class, prefix, damage, float, SEC) \
+               P(class, prefix, delay, float, SEC) \
+               P(class, prefix, edgedamage, float, SEC) \
+               P(class, prefix, force, float, SEC) \
+               P(class, prefix, lifetime, float, SEC) \
+               P(class, prefix, radius, float, SEC) \
+               P(class, prefix, refire, float, SEC) \
+               P(class, prefix, refire_type, float, SEC) \
+               P(class, prefix, shotangle, float, SEC) \
+               P(class, prefix, speed, float, SEC) \
+               P(class, prefix, spread, float, SEC) \
+               P(class, prefix, reload_ammo, float, NONE) \
+               P(class, prefix, reload_time, 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, OverkillShotgun, okshotgun)
+#undef X
+
+ENDCLASS(OverkillShotgun)
+REGISTER_WEAPON(OVERKILL_SHOTGUN, okshotgun, NEW(OverkillShotgun));
+
+//SPAWNFUNC_WEAPON(weapon_okshotgun, WEP_OVERKILL_SHOTGUN)
diff --git a/qcsrc/common/mutators/mutator/overkill/overkill.qc b/qcsrc/common/mutators/mutator/overkill/overkill.qc
deleted file mode 100644 (file)
index 3cb64ce..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include "overkill.qh"
diff --git a/qcsrc/common/mutators/mutator/overkill/overkill.qh b/qcsrc/common/mutators/mutator/overkill/overkill.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/mutators/mutator/overkill/rpc.qh b/qcsrc/common/mutators/mutator/overkill/rpc.qh
deleted file mode 100644 (file)
index 78d5de5..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-
-#include <common/weapons/all.qh>
-
-CLASS(RocketPropelledChainsaw, Weapon)
-/* spawnfunc */ ATTRIB(RocketPropelledChainsaw, m_canonical_spawnfunc, string, "weapon_rpc");
-/* ammotype  */ ATTRIB(RocketPropelledChainsaw, ammo_type, int, RESOURCE_ROCKETS);
-/* impulse   */ ATTRIB(RocketPropelledChainsaw, impulse, int, 9);
-/* 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, 10000);
-/* 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));
-
-SPAWNFUNC_WEAPON(weapon_rpc, WEP_RPC)
index e9106239467ffc7432cda21fa887481db192a6cc..9fa66e8b2a18c12523da72e4c45820d0c711fe7e 100644 (file)
@@ -1,9 +1,8 @@
 #include "sv_overkill.qh"
 
-#include "hmg.qh"
-#include "rpc.qh"
-
-string autocvar_g_overkill;
+#include "okshotgun.qh"
+#include "okhmg.qh"
+#include "okrpc.qh"
 
 bool autocvar_g_overkill_powerups_replace;
 
@@ -11,50 +10,63 @@ bool autocvar_g_overkill_itemwaypoints = true;
 
 .Weapon ok_lastwep[MAX_WEAPONSLOTS];
 
-REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !cvar("g_instagib") && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+IntrusiveList g_overkill_items;
+STATIC_INIT()
 {
-       MUTATOR_ONADD
-       {
-               precache_all_playermodels("models/ok_player/*.dpm");
+       g_overkill_items = IL_NEW();
+       IL_PUSH(g_overkill_items, ITEM_HealthMega);
+       IL_PUSH(g_overkill_items, ITEM_ArmorSmall);
+       IL_PUSH(g_overkill_items, ITEM_ArmorMedium);
+       IL_PUSH(g_overkill_items, ITEM_ArmorBig);
+       IL_PUSH(g_overkill_items, ITEM_ArmorMega);
+}
 
-               if (autocvar_g_overkill_filter_healthmega)
-               {
-                       ITEM_HealthMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armormedium)
-               {
-                       ITEM_ArmorMedium.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armorbig)
-               {
-                       ITEM_ArmorBig.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
-               }
-               if (autocvar_g_overkill_filter_armormega)
+/// \brief Returns a random classname of the overkill item.
+/// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \return Random classname of the overkill item.
+string RandomItems_GetRandomOverkillItemClassName(string prefix)
+{
+       RandomSelection_Init();
+       IL_EACH(g_overkill_items, !(it.spawnflags & ITEM_FLAG_MUTATORBLOCKED) &&
+               Item_IsDefinitionAllowed(it),
+       {
+               string cvar_name = sprintf("g_%s_%s_probability", prefix,
+                       it.m_canonical_spawnfunc);
+               if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
                {
-                       ITEM_ArmorMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+                       LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       continue;
                }
-
-               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";
+               RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
+       });
+       string cvar_name = sprintf("g_%s_weapon_okhmg_probability", prefix);
+       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+       {
+               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
        }
-
-       MUTATOR_ONREMOVE
+       else
        {
-               ITEM_HealthMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorMedium.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorBig.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-               ITEM_ArmorMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
-
-               WEP_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
-               WEP_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               RandomSelection_AddString("weapon_okhmg", cvar(cvar_name), 1);
+       }
+       cvar_name = sprintf("g_%s_weapon_okrpc_probability", prefix);
+       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+       {
+               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+       }
+       else
+       {
+               RandomSelection_AddString("weapon_okrpc", cvar(cvar_name), 1);
        }
+       return RandomSelection_chosen_string;
 }
 
-void W_Blaster_Attack(entity, .entity, float, float, float, float, float, float, float, float, float, float);
+
+MUTATOR_HOOKFUNCTION(ok, RandomItems_GetRandomItemClassName)
+{
+       M_ARGV(1, string) = RandomItems_GetRandomOverkillItemClassName(
+               M_ARGV(0, string));
+       return true;
+}
 
 MUTATOR_HOOKFUNCTION(ok, Damage_Calculate, CBC_ORDER_LAST)
 {
@@ -122,32 +134,31 @@ MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
 
 MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
 {
-       if(game_stopped)
+       if (game_stopped)
+       {
                return;
-
+       }
        entity player = M_ARGV(0, entity);
-
-       if(IS_DEAD(player) || !IS_PLAYER(player) || STAT(FROZEN, player))
+       if (!IS_PLAYER(player) || IS_DEAD(player) || STAT(FROZEN, player))
+       {
                return;
-
-       if(PHYS_INPUT_BUTTON_ATCK2(player) && time >= player.jump_interval)
-       if( !forbidWeaponUse(player)
-               || (round_handler_IsActive() && !round_handler_IsRoundStarted()) )
+       }
+       if (!PHYS_INPUT_BUTTON_ATCK2(player) || forbidWeaponUse(player) ||
+               !(round_handler_IsActive() && !round_handler_IsRoundStarted()))
        {
-               player.jump_interval = time + WEP_CVAR_PRI(blaster, refire) * W_WeaponRateFactor(player);
-               makevectors(player.v_angle);
-
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+               return;
+       }
+       // Allow secondary blaster during countdown.
+       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               Weapon weapon = player.(weaponentity).m_weapon;
+               if (weapon == WEP_Null && slot != 0)
                {
-                       .entity weaponentity = weaponentities[slot];
-
-                       if(player.(weaponentity).m_weapon == WEP_Null && slot != 0)
-                               continue;
-
-                       BLASTER_SECONDARY_ATTACK(vaporizer, player, weaponentity);
+                       continue;
                }
+               weapon.wr_think(weapon, player, weaponentity, 2);
        }
-
        PHYS_INPUT_BUTTON_ATCK2(player) = false;
 }
 
@@ -168,10 +179,10 @@ MUTATOR_HOOKFUNCTION(ok, PlayerWeaponSelect)
                if(player.ok_lastwep[slot] && player.ok_lastwep[slot] != WEP_Null)
                {
                        Weapon newwep = player.ok_lastwep[slot];
-                       if(player.ok_lastwep[slot] == WEP_HMG)
-                               newwep = WEP_MACHINEGUN;
-                       if(player.ok_lastwep[slot] == WEP_RPC)
-                               newwep = WEP_VORTEX;
+                       if(player.ok_lastwep[slot] == WEP_OVERKILL_HMG)
+                               newwep = WEP_OVERKILL_MACHINEGUN;
+                       if(player.ok_lastwep[slot] == WEP_OVERKILL_RPC)
+                               newwep = WEP_OVERKILL_NEX;
                        thiswep.m_switchweapon = newwep;
                        player.ok_lastwep[slot] = WEP_Null;
                }
@@ -227,7 +238,7 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem)
        }
        if (item.classname == "item_strength")
        {
-               entity wep = new(weapon_hmg);
+               entity wep = new(weapon_okhmg);
                setorigin(wep, item.origin);
                wep.ok_item = true;
                wep.noalign = Item_ShouldKeepPosition(item);
@@ -236,12 +247,12 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem)
                wep.respawntime = g_pickup_respawntime_superweapon;
                wep.pickup_anyway = true;
                wep.spawnfunc_checked = true;
-               Item_Initialize(wep, "weapon_hmg");
+               Item_Initialize(wep, "weapon_okhmg"); // doesn't actually use spawnfunc
                return true;
        }
        else if (item.classname == "item_shield")
        {
-               entity wep = new(weapon_rpc);
+               entity wep = new(weapon_okrpc);
                setorigin(wep, item.origin);
                wep.ok_item = true;
                wep.noalign = Item_ShouldKeepPosition(item);
@@ -250,7 +261,7 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem)
                wep.respawntime = g_pickup_respawntime_superweapon;
                wep.pickup_anyway = true;
                wep.spawnfunc_checked = true;
-               Item_Initialize(wep, "weapon_rpc");
+               Item_Initialize(wep, "weapon_okrpc"); // doesn't actually use spawnfunc
                return true;
        }
        return true;
@@ -258,10 +269,10 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem)
 
 MUTATOR_HOOKFUNCTION(ok, SetStartItems, CBC_ORDER_LAST)
 {
-       WepSet ok_start_items = (WEPSET(MACHINEGUN) | WEPSET(VORTEX) | WEPSET(SHOTGUN));
+       WepSet ok_start_items = (WEPSET(OVERKILL_MACHINEGUN) | WEPSET(OVERKILL_NEX) | WEPSET(OVERKILL_SHOTGUN));
 
-       if(WEP_RPC.weaponstart > 0) { ok_start_items |= WEPSET(RPC); }
-       if(WEP_HMG.weaponstart > 0) { ok_start_items |= WEPSET(HMG); }
+       if(WEP_OVERKILL_RPC.weaponstart > 0) { ok_start_items |= WEPSET(OVERKILL_RPC); }
+       if(WEP_OVERKILL_HMG.weaponstart > 0) { ok_start_items |= WEPSET(OVERKILL_HMG); }
 
        start_items |= IT_UNLIMITED_WEAPON_AMMO;
        start_weapons = warmup_start_weapons = ok_start_items;
@@ -288,3 +299,4 @@ MUTATOR_HOOKFUNCTION(ok, SetModname)
        M_ARGV(0, string) = "Overkill";
        return true;
 }
+
index 72324e6dbb01b375b00010231235a03d7a35e649..79e5dd3c5b0cbce85cee0d53108046f8a14bf3fa 100644 (file)
@@ -1,8 +1,42 @@
 #pragma once
 
+string autocvar_g_overkill;
 bool autocvar_g_overkill_filter_healthmega;
 bool autocvar_g_overkill_filter_armormedium;
 bool autocvar_g_overkill_filter_armorbig;
 bool autocvar_g_overkill_filter_armormega;
 
 .float ok_item;
+
+REGISTER_MUTATOR(ok, expr_evaluate(autocvar_g_overkill) && !MUTATOR_IS_ENABLED(mutator_instagib) && !g_nexball && cvar_string("g_mod_balance") == "Overkill")
+{
+       MUTATOR_ONADD
+       {
+               precache_all_playermodels("models/ok_player/*.dpm");
+
+               if (autocvar_g_overkill_filter_healthmega)
+               {
+                       ITEM_HealthMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armormedium)
+               {
+                       ITEM_ArmorMedium.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armorbig)
+               {
+                       ITEM_ArmorBig.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+               if (autocvar_g_overkill_filter_armormega)
+               {
+                       ITEM_ArmorMega.spawnflags |= ITEM_FLAG_MUTATORBLOCKED;
+               }
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               ITEM_HealthMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorMedium.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorBig.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+               ITEM_ArmorMega.spawnflags &= ~ITEM_FLAG_MUTATORBLOCKED;
+       }
+}
diff --git a/qcsrc/common/mutators/mutator/overkill/sv_weapons.qc b/qcsrc/common/mutators/mutator/overkill/sv_weapons.qc
new file mode 100644 (file)
index 0000000..4a131e3
--- /dev/null
@@ -0,0 +1,22 @@
+string autocvar_g_overkill_weapons;
+
+REGISTER_MUTATOR(ok_weapons, expr_evaluate(autocvar_g_overkill_weapons) || MUTATOR_IS_ENABLED(ok))
+{
+       MUTATOR_ONADD
+       {
+               WEP_OVERKILL_SHOTGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_MACHINEGUN.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_NEX.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_HMG.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_RPC.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+       }
+
+       MUTATOR_ONREMOVE
+       {
+               WEP_OVERKILL_SHOTGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_MACHINEGUN.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_NEX.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_HMG.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+               WEP_OVERKILL_RPC.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+       }
+}
index 1084ff77895aa079e2dd9104ffe1159551f54db2..779e562b4a4286235891a56c8e43e43cfd0fb716 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_pinata.qh"
 
 string autocvar_g_pinata;
-REGISTER_MUTATOR(pinata, expr_evaluate(autocvar_g_pinata) && !cvar("g_instagib") && !cvar("g_overkill"));
+REGISTER_MUTATOR(pinata, expr_evaluate(autocvar_g_pinata) && !MUTATOR_IS_ENABLED(mutator_instagib) && !MUTATOR_IS_ENABLED(ok));
 
 MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
 {
@@ -15,7 +15,7 @@ MUTATOR_HOOKFUNCTION(pinata, PlayerDies)
                        continue;
 
                FOREACH(Weapons, it != WEP_Null, {
-                       if(frag_target.weapons & WepSet_FromWeapon(it))
+                       if(STAT(WEAPONS, frag_target) & WepSet_FromWeapon(it))
                        if(frag_target.(weaponentity).m_weapon != 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', weaponentity);
index 3d305746269e1a29cbfb718ceb536175d04693af..183808021b92ecdbdc2324a2431a5ecdbe135c9d 100644 (file)
@@ -7,15 +7,6 @@
 
 //============================ Constants ======================================
 
-enum
-{
-       RANDOM_ITEM_TYPE_HEALTH = 1,
-       RANDOM_ITEM_TYPE_ARMOR,
-       RANDOM_ITEM_TYPE_RESOURCE,
-       RANDOM_ITEM_TYPE_WEAPON,
-       RANDOM_ITEM_TYPE_POWERUP
-};
-
 //======================= Global variables ====================================
 
 // Replace cvars
@@ -33,8 +24,6 @@ enum
 
 // Loot
 
-bool autocvar_g_random_loot; ///< Whether to enable random loot.
-
 float autocvar_g_random_loot_min; ///< Minimum amount of loot items.
 float autocvar_g_random_loot_max; ///< Maximum amount of loot items.
 float autocvar_g_random_loot_time; ///< Amount of time the loot will stay.
@@ -64,162 +53,143 @@ string RandomItems_GetRandomItemClassNameWithProperty(string prefix,
 
 string RandomItems_GetRandomItemClassName(string prefix)
 {
-       if (autocvar_g_instagib)
+       if (MUTATOR_CALLHOOK(RandomItems_GetRandomItemClassName, prefix))
        {
-               return RandomItems_GetRandomInstagibItemClassName(prefix);
+               return M_ARGV(1, string);
        }
-       if (expr_evaluate(autocvar_g_overkill))
-       {
-               return RandomItems_GetRandomOverkillItemClassName(prefix);
-       }
-       return RandomItems_GetRandomVanillaItemClassName(prefix);
+       return RandomItems_GetRandomVanillaItemClassName(prefix,
+               RANDOM_ITEM_TYPE_ALL);
 }
 
-string RandomItems_GetRandomVanillaItemClassName(string prefix)
+string RandomItems_GetRandomVanillaItemClassName(string prefix, int types)
 {
-       RandomSelection_Init();
-       string cvar_name = sprintf("g_%s_health_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH, cvar(cvar_name), 1);
-       }
-       cvar_name = sprintf("g_%s_armor_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+       if (types == 0)
        {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR, cvar(cvar_name), 1);
-       }
-       cvar_name = sprintf("g_%s_resource_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE, cvar(cvar_name), 1);
-       }
-       cvar_name = sprintf("g_%s_weapon_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON, cvar(cvar_name), 1);
-       }
-       cvar_name = sprintf("g_%s_powerup_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP, cvar(cvar_name), 1);
+               return "";
        }
-       int item_type = RandomSelection_chosen_float;
-       switch (item_type)
+       while (types != 0)
        {
-               case RANDOM_ITEM_TYPE_HEALTH:
+               string cvar_name;
+               RandomSelection_Init();
+               if (types & RANDOM_ITEM_TYPE_HEALTH)
                {
-                       return RandomItems_GetRandomItemClassNameWithProperty(prefix,
-                               instanceOfHealth);
+                       cvar_name = sprintf("g_%s_health_probability", prefix);
+                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+                       {
+                               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       }
+                       else
+                       {
+                               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_HEALTH,
+                                       cvar(cvar_name), 1);
+                       }
                }
-               case RANDOM_ITEM_TYPE_ARMOR:
+               if (types & RANDOM_ITEM_TYPE_ARMOR)
                {
-                       return RandomItems_GetRandomItemClassNameWithProperty(prefix,
-                               instanceOfArmor);
+                       cvar_name = sprintf("g_%s_armor_probability", prefix);
+                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+                       {
+                               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       }
+                       else
+                       {
+                               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_ARMOR,
+                                       cvar(cvar_name), 1);
+                       }
                }
-               case RANDOM_ITEM_TYPE_RESOURCE:
+               if (types & RANDOM_ITEM_TYPE_RESOURCE)
                {
-                       return RandomItems_GetRandomItemClassNameWithProperty(prefix,
-                               instanceOfAmmo);
+                       cvar_name = sprintf("g_%s_resource_probability", prefix);
+                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+                       {
+                               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       }
+                       else
+                       {
+                               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_RESOURCE,
+                                       cvar(cvar_name), 1);
+                       }
                }
-               case RANDOM_ITEM_TYPE_WEAPON:
+               if (types & RANDOM_ITEM_TYPE_WEAPON)
                {
-                       RandomSelection_Init();
-                       FOREACH(Weapons, it != WEP_Null &&
-                               !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED),
+                       cvar_name = sprintf("g_%s_weapon_probability", prefix);
+                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
                        {
-                               cvar_name = sprintf("g_%s_%s_probability", prefix,
-                                       it.m_canonical_spawnfunc);
-                               if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-                               {
-                                       LOG_WARNF("Random items: cvar %s doesn't exist.",
-                                               cvar_name);
-                                       continue;
-                               }
-                               RandomSelection_AddString(it.m_canonical_spawnfunc,
-                                       cvar(cvar_name), 1);
-                       });
-                       return RandomSelection_chosen_string;
+                               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       }
+                       else
+                       {
+                               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_WEAPON, cvar(cvar_name), 1);
+                       }
                }
-               case RANDOM_ITEM_TYPE_POWERUP:
+               if (types & RANDOM_ITEM_TYPE_POWERUP)
                {
-                       return RandomItems_GetRandomItemClassNameWithProperty(prefix,
-                               instanceOfPowerup);
+                       cvar_name = sprintf("g_%s_powerup_probability", prefix);
+                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+                       {
+                               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+                       }
+                       else
+                       {
+                               RandomSelection_AddFloat(RANDOM_ITEM_TYPE_POWERUP, cvar(cvar_name), 1);
+                       }
                }
-       }
-       return "";
-}
-
-string RandomItems_GetRandomInstagibItemClassName(string prefix)
-{
-       RandomSelection_Init();
-       FOREACH(Items, it.spawnflags & ITEM_FLAG_INSTAGIB,
-       {
-               string cvar_name = sprintf("g_%s_%s_probability", prefix,
-                       it.m_canonical_spawnfunc);
-               if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+               int item_type = RandomSelection_chosen_float;
+               string class_name = "";
+               switch (item_type)
                {
-                       LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-                       continue;
+                       case RANDOM_ITEM_TYPE_HEALTH:
+                       {
+                               class_name = RandomItems_GetRandomItemClassNameWithProperty(
+                                       prefix, instanceOfHealth);
+                               break;
+                       }
+                       case RANDOM_ITEM_TYPE_ARMOR:
+                       {
+                               class_name = RandomItems_GetRandomItemClassNameWithProperty(
+                                       prefix, instanceOfArmor);
+                               break;
+                       }
+                       case RANDOM_ITEM_TYPE_RESOURCE:
+                       {
+                               class_name = RandomItems_GetRandomItemClassNameWithProperty(
+                                       prefix, instanceOfAmmo);
+                               break;
+                       }
+                       case RANDOM_ITEM_TYPE_WEAPON:
+                       {
+                               RandomSelection_Init();
+                               FOREACH(Weapons, it != WEP_Null &&
+                                       !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED),
+                               {
+                                       cvar_name = sprintf("g_%s_%s_probability", prefix,
+                                               it.m_canonical_spawnfunc);
+                                       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+                                       {
+                                               LOG_WARNF("Random items: cvar %s doesn't exist.",
+                                                       cvar_name);
+                                               continue;
+                                       }
+                                       RandomSelection_AddString(it.m_canonical_spawnfunc,
+                                               cvar(cvar_name), 1);
+                               });
+                               class_name = RandomSelection_chosen_string;
+                               break;
+                       }
+                       case RANDOM_ITEM_TYPE_POWERUP:
+                       {
+                               class_name = RandomItems_GetRandomItemClassNameWithProperty(
+                                       prefix, instanceOfPowerup);
+                               break;
+                       }
                }
-               RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
-       });
-       return RandomSelection_chosen_string;
-}
-
-string RandomItems_GetRandomOverkillItemClassName(string prefix)
-{
-       RandomSelection_Init();
-       FOREACH(Items, (it.spawnflags & ITEM_FLAG_OVERKILL) &&
-               !(it.spawnflags & ITEM_FLAG_MUTATORBLOCKED),
-       {
-               string cvar_name = sprintf("g_%s_overkill_%s_probability", prefix,
-                       it.m_canonical_spawnfunc);
-               if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
+               if (class_name != "")
                {
-                       LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-                       continue;
+                       return class_name;
                }
-               RandomSelection_AddString(it.m_canonical_spawnfunc, cvar(cvar_name), 1);
-       });
-       string cvar_name = sprintf("g_%s_overkill_weapon_hmg_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
+               types &= ~item_type;
        }
-       else
-       {
-               RandomSelection_AddString("weapon_hmg", cvar(cvar_name), 1);
-       }
-       cvar_name = sprintf("g_%s_overkill_weapon_rpc_probability", prefix);
-       if (!(cvar_type(cvar_name) & CVAR_TYPEFLAG_EXISTS))
-       {
-               LOG_WARNF("Random items: cvar %s doesn't exist.", cvar_name);
-       }
-       else
-       {
-               RandomSelection_AddString("weapon_rpc", cvar(cvar_name), 1);
-       }
-       return RandomSelection_chosen_string;
+       return "";
 }
 
 //========================= Free functions ====================================
@@ -242,7 +212,8 @@ string RandomItems_GetRandomItemClassNameWithProperty(string prefix,
        .bool item_property)
 {
        RandomSelection_Init();
-       FOREACH(Items, it.item_property && (it.spawnflags & ITEM_FLAG_NORMAL),
+       FOREACH(Items, it.item_property && (it.spawnflags & ITEM_FLAG_NORMAL) &&
+               Item_IsDefinitionAllowed(it),
        {
                string cvar_name = sprintf("g_%s_%s_probability", prefix,
                        it.m_canonical_spawnfunc);
@@ -296,7 +267,7 @@ entity RandomItems_ReplaceMapItem(entity item)
        }
        random_items_is_spawning = true;
        entity new_item;
-       if (!expr_evaluate(autocvar_g_overkill))
+       if (!MUTATOR_IS_ENABLED(ok))
        {
                new_item = Item_Create(strzone(new_classname), item.origin,
                        Item_ShouldKeepPosition(item));
@@ -342,7 +313,7 @@ void RandomItems_SpawnLootItem(vector position)
        spread.z = autocvar_g_random_loot_spread / 2;
        spread += randomvec() * autocvar_g_random_loot_spread;
        random_items_is_spawning = true;
-       if (!expr_evaluate(autocvar_g_overkill))
+       if (!MUTATOR_IS_ENABLED(ok))
        {
                Item_CreateLoot(class_name, position, spread,
                        autocvar_g_random_loot_time);
@@ -360,9 +331,6 @@ void RandomItems_SpawnLootItem(vector position)
 
 //============================= Hooks ========================================
 
-REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
-       autocvar_g_random_loot));
-
 MUTATOR_HOOKFUNCTION(random_items, BuildMutatorsString)
 {
        M_ARGV(0, string) = strcat(M_ARGV(0, string), ":random_items");
index c9b4dbb9011ca91cd905d0c7221e3f089f4745b0..c94375ceaeeb98d7648179ed6845bfff251dacd1 100644 (file)
@@ -6,6 +6,17 @@
 /// \copyright GNU GPLv2 or any later version.
 
 bool autocvar_g_random_items; ///< Whether to enable random items.
+bool autocvar_g_random_loot; ///< Whether to enable random loot.
+
+enum
+{
+       RANDOM_ITEM_TYPE_HEALTH = BIT(0),
+       RANDOM_ITEM_TYPE_ARMOR = BIT(1),
+       RANDOM_ITEM_TYPE_RESOURCE = BIT(2),
+       RANDOM_ITEM_TYPE_WEAPON = BIT(3),
+       RANDOM_ITEM_TYPE_POWERUP = BIT(4),
+       RANDOM_ITEM_TYPE_ALL = BITS(5)
+};
 
 /// \brief Returns a random classname of the item.
 /// \param[in] prefix Prefix of the cvars that hold probabilities.
@@ -16,17 +27,19 @@ string RandomItems_GetRandomItemClassName(string prefix);
 
 /// \brief Returns a random classname of the vanilla item.
 /// \param[in] prefix Prefix of the cvars that hold probabilities.
+/// \param[in] types Bitmask of the types. See RANDOM_ITEM_TYPE constants.
 /// \return Random classname of the vanilla item.
 /// \note This includes mutator items that don't change gameplay a lot such as
 /// jetpack and new toys.
-string RandomItems_GetRandomVanillaItemClassName(string prefix);
+string RandomItems_GetRandomVanillaItemClassName(string prefix, int types);
 
-/// \brief Returns a random classname of the instagib item.
-/// \param[in] prefix Prefix of the cvars that hold probabilities.
-/// \return Random classname of the instagib item.
-string RandomItems_GetRandomInstagibItemClassName(string prefix);
+/// \brief Called when random item classname is requested.
+#define EV_RandomItems_GetRandomItemClassName(i, o) \
+       /** prefix */    i(string, MUTATOR_ARGV_0_string) \
+       /** classname */ o(string, MUTATOR_ARGV_1_string) \
+    /**/
+MUTATOR_HOOKABLE(RandomItems_GetRandomItemClassName,
+       EV_RandomItems_GetRandomItemClassName);
 
-/// \brief Returns a random classname of the overkill item.
-/// \param[in] prefix Prefix of the cvars that hold probabilities.
-/// \return Random classname of the overkill item.
-string RandomItems_GetRandomOverkillItemClassName(string prefix);
+REGISTER_MUTATOR(random_items, (autocvar_g_random_items ||
+       autocvar_g_random_loot));
index 7edef9813de0fd3c13ca1d79d6593674202c32c1..c6def68e1b61f6ddb56f76bdac458ad3ef5db931 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/deathtypes/all.qh>
 #include <server/round_handler.qh>
 
-REGISTER_MUTATOR(rm, cvar("g_instagib"));
+REGISTER_MUTATOR(rm, autocvar_g_instagib);
 
 MUTATOR_HOOKFUNCTION(rm, Damage_Calculate)
 {
index d121cf1094685ac9263f55143b59da831cf37610..d80b21d5a6e0cec3b4a59f5c403b948eece5cd85 100644 (file)
@@ -212,11 +212,11 @@ void sandbox_ObjectRemove(entity e)
        // 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, { 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;       }
+       strfree(e.material);
+       strfree(e.crypto_idfp);
+       strfree(e.netname);
+       strfree(e.message);
+       strfree(e.message2);
        delete(e);
        e = NULL;
 
@@ -357,14 +357,14 @@ entity sandbox_ObjectPort_Load(entity this, string s, float database)
                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;
+               strfree(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;
+                       strfree(e.crypto_idfp); if(argv(argv_num) != "")        e.crypto_idfp = strzone(argv(argv_num));        else    e.crypto_idfp = string_null;    ++argv_num;
+                       strcpy(e.netname, argv(argv_num));      ++argv_num;
+                       strcpy(e.message, argv(argv_num));      ++argv_num;
+                       strcpy(e.message2, argv(argv_num));     ++argv_num;
                }
 
                // attach last
@@ -702,7 +702,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                        e.damageforcescale = stof(argv(3));
                                                        break;
                                                case "material":
-                                                       if(e.material)  strunzone(e.material);
+                                                       strfree(e.material);
                                                        if(argv(3))
                                                        {
                                                                for (j = 1; j <= 5; j++) // precache material sounds, 5 in total
@@ -718,8 +718,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                        }
 
                                        // update last editing time
-                                       if(e.message2)  strunzone(e.message2);
-                                       e.message2 = strzone(strftime(true, "%d-%m-%Y %H:%M:%S"));
+                                       strcpy(e.message2, strftime(true, "%d-%m-%Y %H:%M:%S"));
 
                                        if(autocvar_g_sandbox_info > 1)
                                                LOG_INFO("^3SANDBOX - SERVER: ^7", player.netname, " edited property ^3", argv(2), " ^7of an object at origin ^3", vtos(e.origin));
@@ -745,8 +744,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                        // 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);
+                                               strcpy(e.netname, player.netname);
                                                print_to(player, "^2SANDBOX - INFO: ^7Object owner name updated");
                                        }
 
@@ -756,8 +754,7 @@ MUTATOR_HOOKFUNCTION(sandbox, SV_ParseClientCommand)
                                                return true;
                                        }
 
-                                       if(e.crypto_idfp)       strunzone(e.crypto_idfp);
-                                       e.crypto_idfp = strzone(player.crypto_idfp);
+                                       strcpy(e.crypto_idfp, player.crypto_idfp);
 
                                        print_to(player, "^2SANDBOX - INFO: ^7Object claimed successfully");
                                }
index 199b4e202a7351a9b2d25bfb4364ec02119a259d..b446c927052e0fc824a07708f03a9633f4c4fdad 100644 (file)
@@ -1,7 +1,7 @@
 #include "sv_vampire.qh"
 
 string autocvar_g_vampire;
-REGISTER_MUTATOR(vampire, expr_evaluate(autocvar_g_vampire) && !cvar("g_instagib"));
+REGISTER_MUTATOR(vampire, expr_evaluate(autocvar_g_vampire) && !MUTATOR_IS_ENABLED(mutator_instagib));
 
 MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
 {
index be5b40c14c40c99301f8e91a7d54e08a017f9f65..326a26219b34e8008fe275f5b6d22076c958454a 100644 (file)
@@ -106,9 +106,9 @@ NET_HANDLE(waypointsprites, bool isnew) {
 
 void Ent_RemoveWaypointSprite(entity this)
 {
-    if (this.netname) strunzone(this.netname);
-    if (this.netname2) strunzone(this.netname2);
-    if (this.netname3) strunzone(this.netname3);
+    strfree(this.netname);
+    strfree(this.netname2);
+    strfree(this.netname3);
 }
 
 /** flags origin [team displayrule] [spritename] [spritename2] [spritename3] [lifetime maxdistance hideable] */
@@ -169,23 +169,17 @@ void Ent_WaypointSprite(entity this, bool isnew)
 
     if (sendflags & 2)
     {
-        if (this.netname)
-            strunzone(this.netname);
-        this.netname = strzone(ReadString());
+        strcpy(this.netname, ReadString());
     }
 
     if (sendflags & 4)
     {
-        if (this.netname2)
-            strunzone(this.netname2);
-        this.netname2 = strzone(ReadString());
+        strcpy(this.netname2, ReadString());
     }
 
     if (sendflags & 8)
     {
-        if (this.netname3)
-            strunzone(this.netname3);
-        this.netname3 = strzone(ReadString());
+        strcpy(this.netname3, ReadString());
     }
 
     if (sendflags & 16)
@@ -589,15 +583,16 @@ void Draw_WaypointSprite(entity this)
     {
         // scale it to be just in view
         vector d;
-        float f1, f2;
 
         d = o - '0.5 0 0' * vid_conwidth - '0 0.5 0' * vid_conheight;
         ang = atan2(-d.x, -d.y);
         if (o.z < 0)
             ang += M_PI;
 
-        f1 = d.x / vid_conwidth;
-        f2 = d.y / vid_conheight;
+               float f1 = d.x / vid_conwidth;
+               float f2 = d.y / vid_conheight; 
+               if (f1 == 0) { f1 = 0.000001; }
+               if (f2 == 0) { f2 = 0.000001; }
 
         if (max(f1, -f1) > max(f2, -f2)) {
             if (d.z * f1 > 0) {
index 95b8890ccce07b10765c5dae8218d9d265b223bc..94d735a1f6096b2f3a77a0b712e4124912bb0aa3 100644 (file)
@@ -11,21 +11,21 @@ const int SPRITERULE_SPECTATOR = 2;
 
 #ifdef CSQC
 entityclass(WaypointSprite);
-class(WaypointSprite) .float helpme;
-class(WaypointSprite) .float rule;
-class(WaypointSprite) .string netname; // primary picture
-class(WaypointSprite) .string netname2; // secondary picture
-class(WaypointSprite) .string netname3; // tertiary picture
-class(WaypointSprite) .int team; // team that gets netname2
-class(WaypointSprite) .float lifetime;
-class(WaypointSprite) .float fadetime;
-class(WaypointSprite) .float maxdistance;
-class(WaypointSprite) .int hideflags;
-class(WaypointSprite) .float spawntime;
-class(WaypointSprite) .float health;
-class(WaypointSprite) .float build_started;
-class(WaypointSprite) .float build_starthealth;
-class(WaypointSprite) .float build_finished;
+classfield(WaypointSprite) .float helpme;
+classfield(WaypointSprite) .float rule;
+classfield(WaypointSprite) .string netname; // primary picture
+classfield(WaypointSprite) .string netname2; // secondary picture
+classfield(WaypointSprite) .string netname3; // tertiary picture
+classfield(WaypointSprite) .int team; // team that gets netname2
+classfield(WaypointSprite) .float lifetime;
+classfield(WaypointSprite) .float fadetime;
+classfield(WaypointSprite) .float maxdistance;
+classfield(WaypointSprite) .int hideflags;
+classfield(WaypointSprite) .float spawntime;
+classfield(WaypointSprite) .float health;
+classfield(WaypointSprite) .float build_started;
+classfield(WaypointSprite) .float build_starthealth;
+classfield(WaypointSprite) .float build_finished;
 
 float autocvar_g_waypointsprite_alpha;
 float autocvar_g_waypointsprite_crosshairfadealpha;
index 7ac4504ec9049aaf0083a7a4b7e59008a6eda376..32b6f3930595ec6376b56e204b39bf46c5fc3db9 100644 (file)
@@ -3,12 +3,73 @@
 // WEAPONTODO: rename the cvars
 REGISTER_MUTATOR(weaponarena_random, true);
 
+MUTATOR_HOOKFUNCTION(weaponarena_random, SetStartItems)
+{
+       if(g_weaponarena)
+               g_weaponarena_random = cvar("g_weaponarena_random");
+       else
+               g_weaponarena_random = 0;
+       
+       g_weaponarena_random_with_blaster = cvar("g_weaponarena_random_with_blaster");
+}
+
 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);
+    if (g_weaponarena_random_with_blaster) STAT(WEAPONS, player) &= ~WEPSET(BLASTER);
+    STAT(WEAPONS, player) = W_RandomWeapons(player, STAT(WEAPONS, player), g_weaponarena_random);
+    if (g_weaponarena_random_with_blaster) STAT(WEAPONS, player) |= WEPSET(BLASTER);
+}
+
+MUTATOR_HOOKFUNCTION(weaponarena_random, GiveFragsForKill)
+{
+       if(!g_weaponarena_random) return;
+       entity attacker = M_ARGV(0, entity);
+       entity targ = M_ARGV(1, entity);
+       float deathtype = M_ARGV(3, float);
+       entity wep_ent = M_ARGV(4, entity);
+       .entity weaponentity = wep_ent.weaponentity_fld;
+
+       if(targ == attacker) return; // not for suicides
+
+       // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon
+       Weapon culprit = DEATH_WEAPONOF(deathtype);
+       if(!culprit) culprit = wep_ent.m_weapon;
+       else if(!(STAT(WEAPONS, attacker) & (culprit.m_wepset))) culprit = wep_ent.m_weapon;
+
+       if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER)
+       {
+               // no exchange
+       }
+       else
+       {
+               if(!GiveFrags_randomweapons)
+               {
+                       GiveFrags_randomweapons = new(GiveFrags_randomweapons);
+               }
+
+               if(warmup_stage)
+                       STAT(WEAPONS, GiveFrags_randomweapons) = WARMUP_START_WEAPONS;
+               else
+                       STAT(WEAPONS, GiveFrags_randomweapons) = start_weapons;
+
+               // all others (including the culprit): remove
+               STAT(WEAPONS, GiveFrags_randomweapons) &= ~STAT(WEAPONS, attacker);
+               STAT(WEAPONS, GiveFrags_randomweapons) &= ~(culprit.m_wepset);
+
+               // among the remaining ones, choose one by random
+               STAT(WEAPONS, GiveFrags_randomweapons) = W_RandomWeapons(GiveFrags_randomweapons, STAT(WEAPONS, GiveFrags_randomweapons), 1);
+
+               if(STAT(WEAPONS, GiveFrags_randomweapons))
+               {
+                       STAT(WEAPONS, attacker) |= STAT(WEAPONS, GiveFrags_randomweapons);
+                       STAT(WEAPONS, attacker) &= ~(culprit.m_wepset);
+               }
+       }
+
+       // after a frag, choose another random weapon set
+       if (!(STAT(WEAPONS, attacker) & WepSet_FromWeapon(wep_ent.m_weapon)))
+               W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker, weaponentity), weaponentity);
 }
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..4af3cf03622565bbb5e9a45f1481222dec37c230 100644 (file)
@@ -1 +1,5 @@
 #pragma once
+
+float g_weaponarena_random_with_blaster;
+
+entity GiveFrags_randomweapons;
index 7b69ad5030c9fb9d6ec510612001f2551f37e255..6651c6cb9b75fae79d13d8a38681883c557873a1 100644 (file)
@@ -22,6 +22,7 @@ const int RACE_NET_SERVER_RANKINGS = 11;
 const int RACE_NET_SERVER_STATUS = 12;
 const int RACE_NET_CHECKPOINT_HIT_SELF_QUALIFYING = 13; // byte checkpoint, short time, short recordtime
 const int RACE_NET_CHECKPOINT_NEXT_SELF_QUALIFYING = 14; // byte nextcheckpoint, short recordtime
+const int RACE_NET_RANKINGS_CNT = 15;
 
 REGISTER_NET_LINKED(_ENT_CLIENT_INIT)
 #ifdef CSQC
@@ -55,3 +56,5 @@ REGISTER_NET_LINKED(ENT_CLIENT_SPAWNEVENT)
 REGISTER_NET_LINKED(ENT_CLIENT_WALL)
 
 #include <lib/csqcmodel/net.qh>
+
+REGISTER_NET_C2S(fpsreport)
index 1134205185474bda2be0142568448d3e711ac494..0eecd6bdf317e9a4bc67dfd45a9d5582a69062a6 100644 (file)
@@ -11,4 +11,6 @@ void sv_notice_join(entity _to);
 
 #ifdef CSQC
 void cl_notice_read();
+
+void cl_notice_run();
 #endif
index b4c6146bb6662535e983df75a4e73962e6289636..b4d14034def463e93ce6747dc98bcb9bdac73c61 100644 (file)
     MSG_INFO_NOTIF(WEAPON_HAGAR_SUICIDE,                    N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponhagar",              _("^BG%s^K1 played with tiny Hagar rockets%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_HLAC_MURDER,                      N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhlac",               _("^BG%s%s^K1 was cut down with ^BG%s^K1's HLAC%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_HLAC_SUICIDE,                     N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponhlac",               _("^BG%s^K1 got a little jumpy with their HLAC%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_HMG_MURDER_SNIPE,                 N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhmg",                _("^BG%s%s^K1 was sniped by ^BG%s^K1's Heavy Machine Gun%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_HMG_MURDER_SPRAY,                 N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhmg",                _("^BG%s%s^K1 was torn to bits by ^BG%s^K1's Heavy Machine Gun%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_HOOK_MURDER,                      N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhook",               _("^BG%s%s^K1 was caught in ^BG%s^K1's Hook gravity bomb%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_KLEINBOTTLE_MURDER,               N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weapontuba",               _("^BG%s%s^K1 died of ^BG%s^K1's great playing on the @!#%%'n Klein Bottle%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_KLEINBOTTLE_SUICIDE,              N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weapontuba",               _("^BG%s^K1 hurt their own ears with the @!#%%'n Klein Bottle%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_MORTAR_MURDER_EXPLODE,            N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weapongrenadelauncher",    _("^BG%s%s^K1 ate ^BG%s^K1's Mortar grenade%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_MORTAR_SUICIDE_BOUNCE,            N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weapongrenadelauncher",    _("^BG%s^K1 didn't see their own Mortar grenade%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_MORTAR_SUICIDE_EXPLODE,           N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weapongrenadelauncher",    _("^BG%s^K1 blew themself up with their own Mortar%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_HMG_MURDER_SNIPE,        N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhmg",                _("^BG%s%s^K1 was sniped by ^BG%s^K1's Overkill Heavy Machine Gun%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_HMG_MURDER_SPRAY,        N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponhmg",                _("^BG%s%s^K1 was torn to bits by ^BG%s^K1's Overkill Heavy Machine Gun%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_MACHINEGUN_MURDER,       N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponuzi",                _("^BG%s%s^K1 was riddled full of holes by ^BG%s^K1's Overkill Machine Gun%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_NEX_MURDER,              N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponnex",                _("^BG%s%s^K1 has been vaporized by ^BG%s^K1's Overkill Nex%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_RPC_MURDER_DIRECT,       N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrpc",                _("^BG%s%s^K1 was sawn in half by ^BG%s^K1's Overkill Rocket Propelled Chainsaw%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_RPC_MURDER_SPLASH,       N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrpc",                _("^BG%s%s^K1 almost dodged ^BG%s^K1's Overkill Rocket Propelled Chainsaw%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_RPC_SUICIDE_DIRECT,      N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponrpc",                _("^BG%s^K1 was sawn in half by their own Overkill Rocket Propelled Chainsaw%s%s"), "")
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_RPC_SUICIDE_SPLASH,      N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponrpc",                _("^BG%s^K1 blew themself up with their Overkill Rocket Propelled Chainsaw%s%s"), "")
+
+    MSG_INFO_NOTIF(WEAPON_OVERKILL_SHOTGUN_MURDER,          N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponshotgun",            _("^BG%s%s^K1 was gunned down by ^BG%s^K1's Overkill Shotgun%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_RIFLE_MURDER,                     N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrifle",              _("^BG%s%s^K1 was sniped with a Rifle by ^BG%s^K1%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_RIFLE_MURDER_HAIL,                N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrifle",              _("^BG%s%s^K1 died in ^BG%s^K1's Rifle bullet hail%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_RIFLE_MURDER_HAIL_PIERCING,       N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrifle",              _("^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle bullet hail%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_RIFLE_MURDER_PIERCING,            N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrifle",              _("^BG%s%s^K1 failed to hide from ^BG%s^K1's Rifle%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_RPC_MURDER_DIRECT,                N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrpc",                _("^BG%s%s^K1 was sawn in half by ^BG%s^K1's Rocket Propelled Chainsaw%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_RPC_MURDER_SPLASH,                N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponrpc",                _("^BG%s%s^K1 almost dodged ^BG%s^K1's Rocket Propelled Chainsaw%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_RPC_SUICIDE_DIRECT,               N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponrpc",                _("^BG%s^K1 was sawn in half by their own Rocket Propelled Chainsaw%s%s"), "")
-    MSG_INFO_NOTIF(WEAPON_RPC_SUICIDE_SPLASH,               N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponrpc",                _("^BG%s^K1 blew themself up with their Rocket Propelled Chainsaw%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_SEEKER_MURDER_SPRAY,              N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponseeker",             _("^BG%s%s^K1 was pummeled by ^BG%s^K1's Seeker rockets%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_SEEKER_MURDER_TAG,                N_CONSOLE,  3, 2, "spree_inf s1 s2 s3loc spree_end", "s2 s1",       "weaponseeker",             _("^BG%s%s^K1 was tagged by ^BG%s^K1's Seeker%s%s"), "")
     MSG_INFO_NOTIF(WEAPON_SEEKER_SUICIDE,                   N_CONSOLE,  2, 1, "s1 s2loc spree_lost", "s1",                      "weaponseeker",             _("^BG%s^K1 played with tiny Seeker rockets%s%s"), "")
     MSG_MULTI_NOTIF(WEAPON_HAGAR_SUICIDE,               N_ENABLE,  NULL,           INFO_WEAPON_HAGAR_SUICIDE,              CENTER_DEATH_SELF_GENERIC)
     MSG_MULTI_NOTIF(WEAPON_HLAC_MURDER,                 N_ENABLE,  NULL,           INFO_WEAPON_HLAC_MURDER,                NULL)
     MSG_MULTI_NOTIF(WEAPON_HLAC_SUICIDE,                N_ENABLE,  NULL,           INFO_WEAPON_HLAC_SUICIDE,               CENTER_DEATH_SELF_GENERIC)
-    MSG_MULTI_NOTIF(WEAPON_HMG_MURDER_SNIPE,            N_ENABLE,  NULL,           INFO_WEAPON_HMG_MURDER_SNIPE,           NULL)
-    MSG_MULTI_NOTIF(WEAPON_HMG_MURDER_SPRAY,            N_ENABLE,  NULL,           INFO_WEAPON_HMG_MURDER_SPRAY,           NULL)
     MSG_MULTI_NOTIF(WEAPON_HOOK_MURDER,                 N_ENABLE,  NULL,           INFO_WEAPON_HOOK_MURDER,                NULL)
     MSG_MULTI_NOTIF(WEAPON_KLEINBOTTLE_MURDER,          N_ENABLE,  NULL,           INFO_WEAPON_KLEINBOTTLE_MURDER,         NULL)
     MSG_MULTI_NOTIF(WEAPON_KLEINBOTTLE_SUICIDE,         N_ENABLE,  NULL,           INFO_WEAPON_KLEINBOTTLE_SUICIDE,        CENTER_DEATH_SELF_GENERIC)
     MSG_MULTI_NOTIF(WEAPON_MORTAR_MURDER_EXPLODE,       N_ENABLE,  NULL,           INFO_WEAPON_MORTAR_MURDER_EXPLODE,      NULL)
     MSG_MULTI_NOTIF(WEAPON_MORTAR_SUICIDE_BOUNCE,       N_ENABLE,  NULL,           INFO_WEAPON_MORTAR_SUICIDE_BOUNCE,      CENTER_DEATH_SELF_GENERIC)
     MSG_MULTI_NOTIF(WEAPON_MORTAR_SUICIDE_EXPLODE,      N_ENABLE,  NULL,           INFO_WEAPON_MORTAR_SUICIDE_EXPLODE,     CENTER_DEATH_SELF_GENERIC)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_HMG_MURDER_SNIPE,   N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_HMG_MURDER_SNIPE,  NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_HMG_MURDER_SPRAY,   N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_HMG_MURDER_SPRAY,  NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_MACHINEGUN_MURDER,  N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_MACHINEGUN_MURDER, NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_NEX_MURDER,         N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_NEX_MURDER,        NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_RPC_MURDER_DIRECT,  N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_RPC_MURDER_DIRECT, NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_RPC_MURDER_SPLASH,  N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_RPC_MURDER_SPLASH, NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_RPC_SUICIDE_DIRECT, N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_RPC_SUICIDE_DIRECT,NULL)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_RPC_SUICIDE_SPLASH, N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_RPC_SUICIDE_SPLASH,CENTER_DEATH_SELF_GENERIC)
+    MSG_MULTI_NOTIF(WEAPON_OVERKILL_SHOTGUN_MURDER,     N_ENABLE,  NULL,           INFO_WEAPON_OVERKILL_SHOTGUN_MURDER,    NULL)
     MSG_MULTI_NOTIF(WEAPON_RIFLE_MURDER,                N_ENABLE,  NULL,           INFO_WEAPON_RIFLE_MURDER,               NULL)
     MSG_MULTI_NOTIF(WEAPON_RIFLE_MURDER_HAIL,           N_ENABLE,  NULL,           INFO_WEAPON_RIFLE_MURDER_HAIL,          NULL)
     MSG_MULTI_NOTIF(WEAPON_RIFLE_MURDER_HAIL_PIERCING,  N_ENABLE,  NULL,           INFO_WEAPON_RIFLE_MURDER_HAIL_PIERCING, NULL)
     MSG_MULTI_NOTIF(WEAPON_RIFLE_MURDER_PIERCING,       N_ENABLE,  NULL,           INFO_WEAPON_RIFLE_MURDER_PIERCING,      NULL)
-    MSG_MULTI_NOTIF(WEAPON_RPC_MURDER_DIRECT,           N_ENABLE,  NULL,           INFO_WEAPON_RPC_MURDER_DIRECT,          NULL)
-    MSG_MULTI_NOTIF(WEAPON_RPC_MURDER_SPLASH,           N_ENABLE,  NULL,           INFO_WEAPON_RPC_MURDER_SPLASH,          NULL)
-    MSG_MULTI_NOTIF(WEAPON_RPC_SUICIDE_DIRECT,          N_ENABLE,  NULL,           INFO_WEAPON_RPC_SUICIDE_DIRECT,         NULL)
-    MSG_MULTI_NOTIF(WEAPON_RPC_SUICIDE_SPLASH,          N_ENABLE,  NULL,           INFO_WEAPON_RPC_SUICIDE_SPLASH,         CENTER_DEATH_SELF_GENERIC)
     MSG_MULTI_NOTIF(WEAPON_SEEKER_MURDER_SPRAY,         N_ENABLE,  NULL,           INFO_WEAPON_SEEKER_MURDER_SPRAY,        NULL)
     MSG_MULTI_NOTIF(WEAPON_SEEKER_MURDER_TAG,           N_ENABLE,  NULL,           INFO_WEAPON_SEEKER_MURDER_TAG,          NULL)
     MSG_MULTI_NOTIF(WEAPON_SEEKER_SUICIDE,              N_ENABLE,  NULL,           INFO_WEAPON_SEEKER_SUICIDE,             CENTER_DEATH_SELF_GENERIC)
index b9350758a115fb6ab3558c86e867a5e62d549c73..644d049d38e8d92c6f86ad49c8e3487fd5092380 100644 (file)
@@ -1063,8 +1063,7 @@ void Local_Notification_sound(int soundchannel, string soundfile, float soundvol
 
                _sound(NULL, soundchannel, AnnouncerFilename(soundfile), soundvolume, soundposition);
 
-               if (prev_soundfile) strunzone(prev_soundfile);
-               prev_soundfile = strzone(soundfile);
+               strcpy(prev_soundfile, soundfile);
                prev_soundtime = time;
        }
        else
@@ -1467,7 +1466,7 @@ void Net_Notification_Remove(entity this)
                this.owner.nent_name
        ));
        #endif
-       for (int i = 0; i < this.nent_stringcount; ++i) { if (this.nent_strings[i]) strunzone(this.nent_strings[i]); }
+       for (int i = 0; i < this.nent_stringcount; ++i) { strfree(this.nent_strings[i]); }
        delete(this);
 }
 
index 1721303ab526a6d2fc93d5a406d99b5ad1973d43..7982ee01f73acfc3348bed12334f125d60af494e 100644 (file)
@@ -5,6 +5,7 @@
 #include <common/constants.qh>
 #include <common/teams.qh>
 #include <common/util.qh>
+#include <common/sounds/sound.qh>
 
 #ifdef CSQC
 #include <client/autocvars.qh>
@@ -676,7 +677,8 @@ string notif_arg_spree_inf(float type, string input, string player, float spree)
 
 REGISTRY(Notifications, BITS(11))
 REGISTER_REGISTRY(Notifications)
-REGISTRY_SORT(Notifications); STATIC_INIT(Notifications) { FOREACH(Notifications, true, it.m_id = i); }
+REGISTRY_SORT(Notifications);
+STATIC_INIT(Notifications) { FOREACH(Notifications, true, it.m_id = i); }
 REGISTRY_CHECK(Notifications)
 
 const int NOTIF_CHOICE_MAX = 50;
index 7d3cab007b508fa6dafceb84a14585d0fd68f327..2b9808a5540fd95733660635f89e108f52deb41f 100644 (file)
@@ -1,11 +1,11 @@
 #include "player.qh"
-#include "../triggers/include.qh"
+#include "../mapobjects/_mod.qh"
 #include "../viewloc.qh"
 
 #ifdef SVQC
 
 #include <server/miscfunctions.qh>
-#include "../triggers/trigger/viewloc.qh"
+#include "../mapobjects/trigger/viewloc.qh"
 
 // client side physics
 bool Physics_Valid(string thecvar)
@@ -77,6 +77,8 @@ void Physics_UpdateStats(entity this)
        STAT(MOVEVARS_JUMPVELOCITY, this) = Physics_ClientOption(this, "jumpvelocity", autocvar_sv_jumpvelocity);
        STAT(MOVEVARS_JUMPVELOCITY_CROUCH, this) = Physics_ClientOption(this, "jumpvelocity_crouch", autocvar_sv_jumpvelocity_crouch);
        STAT(MOVEVARS_TRACK_CANJUMP, this) = Physics_ClientOption(this, "track_canjump", autocvar_sv_track_canjump);
+
+       MUTATOR_CALLHOOK(PlayerPhysics_PostUpdateStats, this, maxspd_mod);
 }
 #endif
 
@@ -98,42 +100,51 @@ float GeomLerp(float a, float _lerp, float b)
 
 void PM_ClientMovement_UpdateStatus(entity this)
 {
-#ifdef CSQC
        if(!IS_PLAYER(this))
                return;
 
-       // set crouched
-       bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+       bool have_hook = false;
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
-               entity wep = viewmodels[slot];
-               if(wep.hook && !wasfreed(wep.hook))
+       #if defined(CSQC)
+               entity wepent = viewmodels[slot];
+       #elif defined(SVQC)
+               .entity weaponentity = weaponentities[slot];
+               entity wepent = this.(weaponentity);
+       #endif
+               if(wepent.hook && !wasfreed(wepent.hook))
                {
-                       do_crouch = false;
-                       break; // don't bother checking the others
+                       have_hook = true;
+                       break;
                }
        }
-       if(this.waterlevel >= WATERLEVEL_SWIMMING)
+       bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
+       if (have_hook) {
                do_crouch = false;
-       if(hud != HUD_NORMAL)
+       //} else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
+               //do_crouch = false;
+       } else if (PHYS_INVEHICLE(this)) {
                do_crouch = false;
-       if(STAT(FROZEN, this))
+       } else if (STAT(FROZEN, this)) {
                do_crouch = false;
+    }
 
-       if (do_crouch)
-       {
-               // wants to crouch, this always works
-               if (!IS_DUCKED(this)) SET_DUCKED(this);
-       }
-       else
-       {
-               // wants to stand, if currently crouching we need to check for a low ceiling first
-               if (IS_DUCKED(this))
-               {
-                       tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, MOVE_NORMAL, this);
-                       if (!trace_startsolid) UNSET_DUCKED(this);
+       if (do_crouch) {
+               if (!IS_DUCKED(this)) {
+                       SET_DUCKED(this);
+                       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 (IS_DUCKED(this)) {
+        tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this);
+        if (!trace_startsolid) {
+            UNSET_DUCKED(this);
+            this.view_ofs = STAT(PL_VIEW_OFS, this);
+            setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
+        }
        }
+#ifdef CSQC
 
        if (IS_ONGROUND(this) || this.velocity.z <= 0 || PHYS_WATERJUMP_TIME(this) <= 0)
                PHYS_WATERJUMP_TIME(this) = 0;
index 4b2ffc55f90595c9eb3efc3cbb65db7a5858da48..da48fa698c2086e34049c7fc1ffeb0f9599d5a87 100644 (file)
@@ -101,15 +101,6 @@ bool IsFlying(entity a);
 #define PHYS_INPUT_BUTTON_ZOOM(s)           PHYS_INPUT_BUTTON_BUTTON4(s)
 #define PHYS_INPUT_BUTTON_CROUCH(s)         PHYS_INPUT_BUTTON_BUTTON5(s)
 #define PHYS_INPUT_BUTTON_HOOK(s)           PHYS_INPUT_BUTTON_BUTTON6(s)
-
-#ifdef CSQC
-STATIC_INIT(PHYS_INPUT_BUTTON_HOOK)
-{
-       localcmd("alias +hook +button6\n");
-       localcmd("alias -hook -button6\n");
-}
-#endif
-
 #define PHYS_INPUT_BUTTON_INFO(s)           PHYS_INPUT_BUTTON_BUTTON7(s)
 #define PHYS_INPUT_BUTTON_DRAG(s)           PHYS_INPUT_BUTTON_BUTTON8(s)
 #define PHYS_INPUT_BUTTON_USE(s)            PHYS_INPUT_BUTTON_BUTTON_USE(s)
@@ -120,16 +111,16 @@ STATIC_INIT(PHYS_INPUT_BUTTON_HOOK)
 #define PHYS_INPUT_BUTTON_DODGE(s)                     PHYS_INPUT_BUTTON_BUTTON11(s)
 
 #ifdef CSQC
-STATIC_INIT(PHYS_INPUT_BUTTON_JETPACK)
+STATIC_INIT(PHYS_INPUT_BUTTON)
 {
+       localcmd("alias +hook +button6\n");
+       localcmd("alias -hook -button6\n");
+
        localcmd("alias +jetpack +button10\n");
-    localcmd("alias -jetpack -button10\n");
-}
+       localcmd("alias -jetpack -button10\n");
 
-STATIC_INIT(PHYS_INPUT_BUTTON_DODGE)
-{
-    localcmd("alias +dodge +button11\n");
-    localcmd("alias -dodge -button11\n");
+       localcmd("alias +dodge +button11\n");
+       localcmd("alias -dodge -button11\n");
 }
 #endif
 
@@ -240,6 +231,8 @@ STATIC_INIT(PHYS_INPUT_BUTTON_DODGE)
        #define SET_DUCKED(s)                       ((s).flags |= FL_DUCKED)
        #define UNSET_DUCKED(s)                     ((s).flags &= ~FL_DUCKED)
 
+       #define PHYS_INVEHICLE(s)                                       (boolean(hud != HUD_NORMAL))
+
        #define PHYS_JUMPSPEEDCAP_MIN               autocvar_cl_jumpspeedcap_min
        #define PHYS_JUMPSPEEDCAP_MAX               autocvar_cl_jumpspeedcap_max
 
@@ -292,6 +285,8 @@ STATIC_INIT(PHYS_INPUT_BUTTON_DODGE)
        #define SET_DUCKED(s)                       ((s).crouch = true)
        #define UNSET_DUCKED(s)                     ((s).crouch = false)
 
+       #define PHYS_INVEHICLE(s)                                       (boolean((s).vehicle != NULL))
+
        #define PHYS_JUMPSPEEDCAP_MIN               autocvar_sv_jumpspeedcap_min
        #define PHYS_JUMPSPEEDCAP_MAX               autocvar_sv_jumpspeedcap_max
 
index 0fcd70dfc08fd8e7afd9bdc2cd2b31c063331c79..cde6a519028093268ef95fc568e91184a40d3368 100644 (file)
@@ -154,8 +154,7 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
                }
        }
 
-       strunzone(p.playerstats_id);
-       p.playerstats_id = string_null;
+       strfree(p.playerstats_id);
 }
 
 void PlayerStats_GameReport(float finished)
index 476d0dbbaa612445241bd1450c48642a7f78f347..377a780770300554275d3685e3e6d53e90122bb8 100644 (file)
@@ -39,6 +39,8 @@ REGISTER_SP(FRAGS);
 
 REGISTER_SP(ELO);
 
+REGISTER_SP(FPS);
+
 // TODO: move to common mutators
 
 REGISTER_SP(RACE_TIME);
index 8c4aecbda029829c753e9b1641ceeb490cc04259..d46ac9eafc7c36cccbeb07c7d302fe9b25f250d3 100644 (file)
@@ -22,7 +22,7 @@ const int CH_PLAYER_SINGLE = 7;
 // const int CH_BGM_SINGLE = -8;
 const int CH_BGM_SINGLE = 8;
 const int CH_AMBIENT = -9;
-// const int CH_AMBIENT_SINGLE = 9;
+const int CH_AMBIENT_SINGLE = 9;
 
 const float ATTEN_NONE = 0;
 const float ATTEN_MIN = 0.015625;
@@ -92,40 +92,55 @@ const float VOL_MUFFLED = 0.35;
                } \
        } MACRO_END
 
+string _Sound_fixpath(string base)
+{
+       if (base == "") return string_null;
+#ifdef SVQC
+       return strcat(base, ".wav");  // let the client engine decide
+#else
+#define extensions(x) \
+       x(wav) \
+       x(ogg) \
+       x(flac) \
+       /**/
+#define tryext(ext) { \
+               string s = strcat(base, "." #ext); \
+               if (fexists(strcat("sound/", s))) { \
+                       return s; \
+               } \
+       }
+       extensions(tryext);
+       LOG_WARNF("Missing sound: \"%s\"", strcat("sound/", base));
+#undef tryext
+#undef extensions
+       return string_null;
+#endif
+}
+
 CLASS(Sound, Object)
        ATTRIB(Sound, m_id, int, 0);
        ATTRIB(Sound, sound_str, string());
+       ATTRIB(Sound, sound_str_, string);
        CONSTRUCTOR(Sound, string() path)
        {
                CONSTRUCT(Sound);
                this.sound_str = path;
        }
-       #define Sound_fixpath(this) _Sound_fixpath((this).sound_str())
-       string _Sound_fixpath(string base)
-       {
-               if (base == "") return string_null;
-#ifdef SVQC
-               return strcat(base, ".wav");  // let the client engine decide
-#else
-               #define extensions(x) \
-                       x(wav) \
-                       x(ogg) \
-                       x(flac) \
-                       /**/
-               #define tryext(ext) { string s = strcat(base, "." #ext); if (fexists(strcat("sound/", s))) return s; }
-               extensions(tryext);
-               LOG_WARNF("Missing sound: \"%s\"", strcat("sound/", base));
-               #undef tryext
-               #undef extensions
-               return string_null;
-#endif
-       }
        METHOD(Sound, sound_precache, void(Sound this))
        {
            TC(Sound, this);
-               string s = Sound_fixpath(this);
+               string s = _Sound_fixpath(this.sound_str());
                if (!s) return;
                profile(sprintf("precache_sound(\"%s\")", s));
                precache_sound(s);
+               strcpy(this.sound_str_, s);
        }
 ENDCLASS(Sound)
+
+entity _Sound_fixpath_this;
+string _Sound_fixpath_cached;
+#define Sound_fixpath(this) ( \
+       _Sound_fixpath_this = (this), \
+       _Sound_fixpath_cached = _Sound_fixpath_this.sound_str_, \
+       _Sound_fixpath_cached ? _Sound_fixpath_cached : _Sound_fixpath(_Sound_fixpath_this.sound_str()) \
+)
index db681315a6c4d27b3d804f5fb4a90bc13bf7e196..9b8f04041780fd55f707331540c74ab99b0e8e88 100644 (file)
@@ -120,6 +120,13 @@ REGISTER_STAT(ENTRAP_ORB, float)
 REGISTER_STAT(ENTRAP_ORB_ALPHA, float)
 REGISTER_STAT(ITEMSTIME, int, autocvar_sv_itemstime)
 REGISTER_STAT(KILL_TIME, float)
+REGISTER_STAT(VEIL_ORB, float)
+REGISTER_STAT(VEIL_ORB_ALPHA, float)
+
+#ifdef SVQC
+float autocvar_sv_showfps = 5;
+#endif
+REGISTER_STAT(SHOWFPS, float, autocvar_sv_showfps)
 
 #ifdef SVQC
 bool autocvar_g_ctf_leaderboard;
index 249615d2d392b8b5fe828e531c11586921ca3737..f4ed4f1bf423e83e62be4463a76e0ab9a72aaac6 100644 (file)
@@ -15,7 +15,7 @@
     #include "constants.qh"
     #include <common/deathtypes/all.qh>
     #include <common/notifications/all.qh>
-       #include "triggers/subs.qh"
+       #include "mapobjects/subs.qh"
     #include "util.qh"
 
     #include <common/monsters/_mod.qh>
@@ -50,13 +50,8 @@ void Item_SetAlpha(entity this)
        }
        else
        {
-               if (autocvar_cl_ghost_items_color)
-               {
-                       this.alpha = autocvar_cl_ghost_items;
-                       this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
-               }
-               else
-                       this.alpha = -1;
+               this.alpha = autocvar_cl_ghost_items;
+               this.colormod = this.glowmod = autocvar_cl_ghost_items_color;
        }
 
        if((!veh_hud) && (this.ItemStatus & ITS_STAYWEP))
@@ -148,8 +143,17 @@ void Item_PreDraw(entity this)
 
 void ItemRemove(entity this)
 {
-       if(this.mdl)
-               strunzone(this.mdl);
+       strfree(this.mdl);
+}
+
+HashMap ENT_CLIENT_ITEM_simple;
+STATIC_INIT(ENT_CLIENT_ITEM_simple)
+{
+       HM_NEW(ENT_CLIENT_ITEM_simple);
+}
+SHUTDOWN(ENT_CLIENT_ITEM_simple)
+{
+       HM_DELETE(ENT_CLIENT_ITEM_simple);
 }
 
 NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
@@ -211,10 +215,8 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
         if(!warpzone_warpzones_exist && this.fade_start && !autocvar_cl_items_nofade)
                setpredraw(this, Item_PreDraw);
 
-        if(this.mdl)
-            strunzone(this.mdl);
+               strfree(this.mdl);
 
-        this.mdl = "";
         string _fn = ReadString();
         this.item_simple = false; // reset it!
 
@@ -223,27 +225,37 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
             string _fn2 = substring(_fn, 0 , strlen(_fn) -4);
             this.item_simple = true;
 
-            if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".md3")))
-                this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".md3"));
-            else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".dpm")))
-                this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".dpm"));
-            else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".iqm")))
-                this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".iqm"));
-            else if(fexists(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".mdl")))
-                this.mdl = strzone(strcat(_fn2, autocvar_cl_simpleitems_postfix, ".mdl"));
-            else
-            {
-                this.item_simple = false;
-                LOG_TRACE("Simple item requested for ", _fn, " but no model exists for it");
-            }
+                       #define extensions(x) \
+                               x(md3) \
+                               x(dpm) \
+                               x(iqm) \
+                               x(mdl) \
+                               /**/
+                       #define tryext(ext) { \
+                               string s = strcat(_fn2, autocvar_cl_simpleitems_postfix, "." #ext); \
+                               string cached = HM_gets(ENT_CLIENT_ITEM_simple, s); \
+                               if (cached == "") { \
+                                       HM_sets(ENT_CLIENT_ITEM_simple, s, cached = fexists(s) ? "1" : "0"); \
+                               } \
+                               if (cached != "0") { \
+                                       strcpy(this.mdl, s); \
+                                       break; \
+                               } \
+                       }
+                       do {
+                               extensions(tryext);
+                               this.item_simple = false;
+                LOG_TRACEF("Simple item requested for %s but no model exists for it", _fn);
+                       } while (0);
+                       #undef tryext
+                       #undef extensions
         }
 
         if(!this.item_simple)
-            this.mdl = strzone(_fn);
-
+            strcpy(this.mdl, _fn);
 
         if(this.mdl == "")
-            LOG_TRACE("^1WARNING!^7 this.mdl is unset for item ", this.classname, ", tell tZork about this!");
+            LOG_WARNF("this.mdl is unset for item %s", this.classname);
 
         precache_model(this.mdl);
         _setmodel(this, this.mdl);
@@ -384,39 +396,12 @@ bool have_pickup_item(entity this)
                if(autocvar_g_pickup_items == 0)
                        return false;
                if(g_weaponarena)
-                       if(this.weapons || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
+                       if(STAT(WEAPONS, this) || this.itemdef.instanceOfAmmo) // no item or ammo pickups in weaponarena
                                return false;
        }
        return true;
 }
 
-/*
-float Item_Customize()
-{
-       if(this.spawnshieldtime)
-               return true;
-       if(this.weapons & ~other.weapons)
-       {
-               this.colormod = '0 0 0';
-               this.glowmod = this.colormod;
-               this.alpha = 0.5 + 0.5 * g_ghost_items; // halfway more alpha
-               return true;
-       }
-       else
-       {
-               if(g_ghost_items)
-               {
-                       this.colormod = stov(autocvar_g_ghost_items_color);
-                       this.glowmod = this.colormod;
-                       this.alpha = g_ghost_items;
-                       return true;
-               }
-               else
-                       return false;
-       }
-}
-*/
-
 void Item_Show (entity e, float mode)
 {
        e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
@@ -440,7 +425,7 @@ void Item_Show (entity e, float mode)
        }
        else
        {
-               bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.weapons & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
+               bool nostay = def.instanceOfWeaponPickup ? !!(def.m_weapon.m_wepset & WEPSET_SUPERWEAPONS) : false // no weapon-stay on superweapons
                        || e.team // weapon stay isn't supported for teamed weapons
                        ;
                if(def.instanceOfWeaponPickup && !nostay && g_weapon_stay)
@@ -500,7 +485,7 @@ void Item_Respawn (entity this)
        sound(this, CH_TRIGGER, this.itemdef.m_respawnsound, VOL_BASE, ATTEN_NORM);     // play respawn sound
        setorigin(this, this.origin);
 
-    if (Item_ItemsTime_Allow(this.itemdef) || (this.weapons & WEPSET_SUPERWEAPONS))
+    if (Item_ItemsTime_Allow(this.itemdef) || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
        {
                float t = Item_ItemsTime_UpdateTime(this, 0);
                Item_ItemsTime_SetTime(this, t);
@@ -585,13 +570,13 @@ void Item_RespawnThink(entity this)
 void Item_ScheduleRespawnIn(entity e, float t)
 {
        // if the respawn time is longer than 10 seconds, show a waypoint, otherwise, just respawn normally
-       if ((Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
+       if ((Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS) || MUTATOR_CALLHOOK(Item_ScheduleRespawn, e, t)) && (t - ITEM_RESPAWN_TICKS) > 0)
        {
                setthink(e, Item_RespawnCountdown);
                e.nextthink = time + max(0, t - ITEM_RESPAWN_TICKS);
                e.scheduledrespawntime = e.nextthink + ITEM_RESPAWN_TICKS;
                e.item_respawncounter = 0;
-               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
                        Item_ItemsTime_SetTime(e, t);
@@ -605,7 +590,7 @@ void Item_ScheduleRespawnIn(entity e, float t)
                e.scheduledrespawntime = time + t;
                e.wait = time + t;
 
-               if(Item_ItemsTime_Allow(e.itemdef) || (e.weapons & WEPSET_SUPERWEAPONS))
+               if(Item_ItemsTime_Allow(e.itemdef) || (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
                {
                        t = Item_ItemsTime_UpdateTime(e, e.scheduledrespawntime);
                        Item_ItemsTime_SetTime(e, t);
@@ -663,8 +648,6 @@ void Item_ScheduleRespawn(entity e)
 AUTOCVAR(g_pickup_respawntime_initial_random, int, 1,
        "For items that don't start spawned: 0: spawn after their normal respawntime; 1: spawn after `random * respawntime` with the *same* random; 2: same as 1 but each item has separate random");
 
-float shared_random;
-STATIC_INIT(shared_random) { shared_random = random(); }
 void Item_ScheduleInitialRespawn(entity e)
 {
        Item_Show(e, 0);
@@ -675,18 +658,26 @@ void Item_ScheduleInitialRespawn(entity e)
                // range: respawntime .. respawntime + respawntimejitter
                spawn_in = e.respawntime + random() * e.respawntimejitter;
        }
-       else if (autocvar_g_pickup_respawntime_initial_random == 1)
+       else
        {
+               float rnd;
+               if (autocvar_g_pickup_respawntime_initial_random == 1)
+               {
+                       static float shared_random = 0;
+                       // NOTE this code works only if items are scheduled at the same time (normal case)
+                       // NOTE2 random() can't return exactly 1 so this check always work as intended
+                       if (!shared_random || floor(time) > shared_random)
+                               shared_random = floor(time) + random();
+                       rnd = shared_random - floor(time);
+               }
+               else
+                       rnd = random();
+
                // range:
                // if respawntime >= ITEM_RESPAWN_TICKS: ITEM_RESPAWN_TICKS .. respawntime + respawntimejitter
                // else: 0 .. ITEM_RESPAWN_TICKS
                // this is to prevent powerups spawning unexpectedly without waypoints
-               spawn_in = ITEM_RESPAWN_TICKS + shared_random * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
-       }
-       else
-       {
-               // range: same as 1
-               spawn_in = ITEM_RESPAWN_TICKS + random() * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
+               spawn_in = ITEM_RESPAWN_TICKS + rnd * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
        }
 
        Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : spawn_in));
@@ -710,7 +701,7 @@ void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
                        FOREACH(Weapons, it != WEP_Null,
                        {
                                // Finding a weapon which player doesn't have.
-                               if (!(receiver.weapons & it.m_wepset) && (it.netname == weapon))
+                               if (!(STAT(WEAPONS, receiver) & it.m_wepset) && (it.netname == weapon))
                                {
                                        RandomSelection_AddEnt(it, 1, 1);
                                        break;
@@ -721,7 +712,7 @@ void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
                {
                        return;
                }
-               receiver.weapons |= RandomSelection_chosen_ent.m_wepset;
+               STAT(WEAPONS, receiver) |= RandomSelection_chosen_ent.m_wepset;
                if (RandomSelection_chosen_ent.ammo_type == RESOURCE_NONE)
                {
                        continue;
@@ -783,7 +774,7 @@ float Item_GiveTo(entity item, entity player)
                                if(player.(weaponentity).m_switchweapon == w_getbestweapon(player, weaponentity))
                                        _switchweapon |= BIT(slot);
 
-                               if(!(player.weapons & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
+                               if(!(STAT(WEAPONS, player) & WepSet_FromWeapon(player.(weaponentity).m_switchweapon)))
                                        _switchweapon |= BIT(slot);
                        }
                }
@@ -799,8 +790,8 @@ float Item_GiveTo(entity item, entity player)
        if (item.itemdef.instanceOfWeaponPickup)
        {
                WepSet w;
-               w = item.weapons;
-               w &= ~player.weapons;
+               w = STAT(WEAPONS, item);
+               w &= ~STAT(WEAPONS, player);
 
                if (w || (item.spawnshieldtime && item.pickup_anyway > 0))
                {
@@ -990,7 +981,7 @@ void Item_Reset(entity this)
        {
                WaypointSprite_Kill(this.waypointsprite_attached);
        }
-       if (this.itemdef.instanceOfPowerup || (this.weapons & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
+       if (this.itemdef.instanceOfPowerup || (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)) // do not spawn powerups initially!
        {
                Item_ScheduleInitialRespawn(this);
        }
@@ -1049,7 +1040,7 @@ float generic_pickupevalfunc(entity player, entity item) {return item.bot_pickup
 float weapon_pickupevalfunc(entity player, entity item)
 {
        // See if I have it already
-       if(player.weapons & item.weapons)
+       if(STAT(WEAPONS, player) & STAT(WEAPONS, item))
        {
                // If I can pick it up
                if(!item.spawnshieldtime)
@@ -1060,7 +1051,7 @@ float weapon_pickupevalfunc(entity player, entity item)
        // reduce weapon value if bot already got a good arsenal
        float c = 1;
        int weapons_value = 0;
-       FOREACH(Weapons, it != WEP_Null && (player.weapons & it.m_wepset), {
+       FOREACH(Weapons, it != WEP_Null && (STAT(WEAPONS, player) & it.m_wepset), {
                weapons_value += it.bot_pickupbasevalue;
        });
        c -= bound(0, weapons_value / 20000, 1) * 0.5;
@@ -1094,7 +1085,7 @@ float ammo_pickupevalfunc(entity player, entity item)
        else
        {
                FOREACH(Weapons, it != WEP_Null, {
-                       if(!(player.weapons & (it.m_wepset)))
+                       if(!(STAT(WEAPONS, player) & (it.m_wepset)))
                                continue;
 
                        switch(it.ammo_type)
@@ -1112,23 +1103,23 @@ float ammo_pickupevalfunc(entity player, entity item)
 
        float noammorating = 0.5;
 
-       if ((need_shells) && (item.ammo_shells) && (player.ammo_shells < g_pickup_shells_max))
-               c = item.ammo_shells / max(noammorating, player.ammo_shells);
+       if ((need_shells) && (item.ammo_shells) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
+               c = item.ammo_shells / max(noammorating, GetResourceAmount(player, RESOURCE_SHELLS));
 
-       if ((need_nails) && (item.ammo_nails) && (player.ammo_nails < g_pickup_nails_max))
-               c = item.ammo_nails / max(noammorating, player.ammo_nails);
+       if ((need_nails) && (item.ammo_nails) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
+               c = item.ammo_nails / max(noammorating, GetResourceAmount(player, RESOURCE_BULLETS));
 
-       if ((need_rockets) && (item.ammo_rockets) && (player.ammo_rockets < g_pickup_rockets_max))
-               c = item.ammo_rockets / max(noammorating, player.ammo_rockets);
+       if ((need_rockets) && (item.ammo_rockets) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
+               c = item.ammo_rockets / max(noammorating, GetResourceAmount(player, RESOURCE_ROCKETS));
 
-       if ((need_cells) && (item.ammo_cells) && (player.ammo_cells < g_pickup_cells_max))
-               c = item.ammo_cells / max(noammorating, player.ammo_cells);
+       if ((need_cells) && (item.ammo_cells) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
+               c = item.ammo_cells / max(noammorating, GetResourceAmount(player, RESOURCE_CELLS));
 
-       if ((need_plasma) && (item.ammo_plasma) && (player.ammo_plasma < g_pickup_plasma_max))
-               c = item.ammo_plasma / max(noammorating, player.ammo_plasma);
+       if ((need_plasma) && (item.ammo_plasma) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
+               c = item.ammo_plasma / max(noammorating, GetResourceAmount(player, RESOURCE_PLASMA));
 
-       if ((need_fuel) && (item.ammo_fuel) && (player.ammo_fuel < g_pickup_fuel_max))
-               c = item.ammo_fuel / max(noammorating, player.ammo_fuel);
+       if ((need_fuel) && (item.ammo_fuel) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
+               c = item.ammo_fuel / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
 
        rating *= min(c, 2);
        if(wpn)
@@ -1187,7 +1178,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
     this.item_pickupsound_ent = pickupsound;
 
     if(def.m_iteminit)
-       def.m_iteminit(this);
+       def.m_iteminit(def, this);
 
        if(!this.respawntime) // both need to be set
        {
@@ -1210,7 +1201,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
        }
 
        if(weaponid)
-               this.weapons = WepSet_FromWeapon(Weapons_from(weaponid));
+               STAT(WEAPONS, this) = WepSet_FromWeapon(Weapons_from(weaponid));
 
        this.flags = FL_ITEM | itemflags;
        IL_PUSH(g_items, this);
@@ -1519,7 +1510,7 @@ spawnfunc(target_items)
                                        s = W_UndeprecateName(argv(j));
                                        if(s == it.netname)
                                        {
-                                               this.weapons |= (it.m_wepset);
+                                               STAT(WEAPONS, this) |= (it.m_wepset);
                                                if(this.spawnflags == 0 || this.spawnflags == 2)
                                                        it.wr_init(it);
                                                break;
@@ -1572,7 +1563,7 @@ spawnfunc(target_items)
                if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
                if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
                FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
-               FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
+               FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
        //print(this.netname, "\n");
@@ -1591,30 +1582,30 @@ float GiveWeapon(entity e, float wpn, float op, float val)
 {
        WepSet v0, v1;
        WepSet s = WepSet_FromWeapon(Weapons_from(wpn));
-       v0 = (e.weapons & s);
+       v0 = (STAT(WEAPONS, e) & s);
        switch(op)
        {
                case OP_SET:
                        if(val > 0)
-                               e.weapons |= s;
+                               STAT(WEAPONS, e) |= s;
                        else
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
                case OP_MIN:
                case OP_PLUS:
                        if(val > 0)
-                               e.weapons |= s;
+                               STAT(WEAPONS, e) |= s;
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               e.weapons &= ~s;
+                               STAT(WEAPONS, e) &= ~s;
                        break;
        }
-       v1 = (e.weapons & s);
+       v1 = (STAT(WEAPONS, e) & s);
        return (v0 != v1);
 }
 
@@ -1832,7 +1823,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        FOREACH(Weapons, it != WEP_Null, {
                POSTGIVE_WEAPON(e, it, SND_WEAPONPICKUP, SND_Null);
                if(!(save_weapons & (it.m_wepset)))
-                       if(e.weapons & (it.m_wepset))
+                       if(STAT(WEAPONS, e) & (it.m_wepset))
                                it.wr_init(it);
        });
        POSTGIVE_VALUE(e, strength_finished, 1, SND_POWERUP, SND_POWEROFF);
@@ -1848,7 +1839,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        POSTGIVE_VALUE_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
 
        if(e.superweapons_finished <= 0)
-               if(e.weapons & WEPSET_SUPERWEAPONS)
+               if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
                        e.superweapons_finished = autocvar_g_balance_superweapons_time;
 
        if(e.strength_finished <= 0)
@@ -1868,7 +1859,7 @@ float GiveItems(entity e, float beginarg, float endarg)
        {
                .entity weaponentity = weaponentities[slot];
                if(e.(weaponentity).m_weapon != WEP_Null || slot == 0)
-               if(!(e.weapons & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
+               if(!(STAT(WEAPONS, e) & WepSet_FromWeapon(e.(weaponentity).m_switchweapon)))
                        _switchweapon |= BIT(slot);
        }
 
index 315a100375bd4fc7cfd45911919d0ac9ce42d60d..50228a0a8f02c94a2f79b6a8c1f13d7b741e7b2b 100644 (file)
@@ -124,9 +124,11 @@ void GiveSound(entity e, float v0, float v1, float t, Sound snd_incr, Sound snd_
 
 void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime);
 
-#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = e.weapons
+spawnfunc(target_items);
+
+#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = STAT(WEAPONS, e)
 #define PREGIVE(e,f) float save_##f; save_##f = (e).f
-#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(e.weapons & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
+#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(STAT(WEAPONS, e) & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
 #define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
 #define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
 #define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
diff --git a/qcsrc/common/triggers/_mod.inc b/qcsrc/common/triggers/_mod.inc
deleted file mode 100644 (file)
index 9b327de..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/include.qc>
-#include <common/triggers/platforms.qc>
-#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>
diff --git a/qcsrc/common/triggers/_mod.qh b/qcsrc/common/triggers/_mod.qh
deleted file mode 100644 (file)
index d3bb2dc..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/include.qh>
-#include <common/triggers/platforms.qh>
-#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>
diff --git a/qcsrc/common/triggers/func/_mod.inc b/qcsrc/common/triggers/func/_mod.inc
deleted file mode 100644 (file)
index 675e368..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/func/bobbing.qc>
-#include <common/triggers/func/breakable.qc>
-#include <common/triggers/func/button.qc>
-#include <common/triggers/func/conveyor.qc>
-#include <common/triggers/func/door.qc>
-#include <common/triggers/func/door_rotating.qc>
-#include <common/triggers/func/door_secret.qc>
-#include <common/triggers/func/fourier.qc>
-#include <common/triggers/func/include.qc>
-#include <common/triggers/func/ladder.qc>
-#include <common/triggers/func/pendulum.qc>
-#include <common/triggers/func/plat.qc>
-#include <common/triggers/func/pointparticles.qc>
-#include <common/triggers/func/rainsnow.qc>
-#include <common/triggers/func/rotating.qc>
-#include <common/triggers/func/stardust.qc>
-#include <common/triggers/func/train.qc>
-#include <common/triggers/func/vectormamamam.qc>
diff --git a/qcsrc/common/triggers/func/_mod.qh b/qcsrc/common/triggers/func/_mod.qh
deleted file mode 100644 (file)
index fb179a4..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/func/bobbing.qh>
-#include <common/triggers/func/breakable.qh>
-#include <common/triggers/func/button.qh>
-#include <common/triggers/func/conveyor.qh>
-#include <common/triggers/func/door.qh>
-#include <common/triggers/func/door_rotating.qh>
-#include <common/triggers/func/door_secret.qh>
-#include <common/triggers/func/fourier.qh>
-#include <common/triggers/func/include.qh>
-#include <common/triggers/func/ladder.qh>
-#include <common/triggers/func/pendulum.qh>
-#include <common/triggers/func/plat.qh>
-#include <common/triggers/func/pointparticles.qh>
-#include <common/triggers/func/rainsnow.qh>
-#include <common/triggers/func/rotating.qh>
-#include <common/triggers/func/stardust.qh>
-#include <common/triggers/func/train.qh>
-#include <common/triggers/func/vectormamamam.qh>
diff --git a/qcsrc/common/triggers/func/bobbing.qc b/qcsrc/common/triggers/func/bobbing.qc
deleted file mode 100644 (file)
index ff8841a..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "bobbing.qh"
-#ifdef SVQC
-.float height;
-void func_bobbing_controller_think(entity this)
-{
-       vector v;
-       this.nextthink = time + 0.1;
-
-       if(this.owner.active != ACTIVE_ACTIVE)
-       {
-               this.owner.velocity = '0 0 0';
-               return;
-       }
-
-       // calculate sinewave using makevectors
-       makevectors((this.nextthink * this.owner.cnt + this.owner.phase * 360) * '0 1 0');
-       v = this.owner.destvec + this.owner.movedir * v_forward_y;
-       if(this.owner.classname == "func_bobbing") // don't brake stuff if the func_bobbing was killtarget'ed
-               // * 10 so it will arrive in 0.1 sec
-               this.owner.velocity = (v - this.owner.origin) * 10;
-}
-
-/*QUAKED spawnfunc_func_bobbing (0 .5 .8) ? X_AXIS Y_AXIS
-Brush model that moves back and forth on one axis (default Z).
-speed : how long one cycle takes in seconds (default 4)
-height : how far the cycle moves (default 32)
-phase : cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
-noise : path/name of looping .wav file to play.
-dmg : Do this mutch dmg every .dmgtime intervall when blocked
-dmgtime : See above.
-*/
-spawnfunc(func_bobbing)
-{
-       entity controller;
-       if (this.noise != "")
-       {
-               precache_sound(this.noise);
-               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
-       }
-       if (!this.speed)
-               this.speed = 4;
-       if (!this.height)
-               this.height = 32;
-       // center of bobbing motion
-       this.destvec = this.origin;
-       // time scale to get degrees
-       this.cnt = 360 / this.speed;
-
-       this.active = ACTIVE_ACTIVE;
-
-       // damage when blocked
-       setblocked(this, generic_plat_blocked);
-       if(this.dmg && (this.message == ""))
-               this.message = " was squished";
-    if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-       if(this.dmg && (!this.dmgtime))
-               this.dmgtime = 0.25;
-       this.dmgtime2 = time;
-
-       // how far to bob
-       if (this.spawnflags & 1) // X
-               this.movedir = '1 0 0' * this.height;
-       else if (this.spawnflags & 2) // Y
-               this.movedir = '0 1 0' * this.height;
-       else // Z
-               this.movedir = '0 0 1' * this.height;
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-
-       // wait for targets to spawn
-       controller = new(func_bobbing_controller);
-       controller.owner = this;
-       controller.nextthink = time + 1;
-       setthink(controller, func_bobbing_controller_think);
-       this.nextthink = this.ltime + 999999999;
-       setthink(this, SUB_NullThink);
-
-       // Savage: Reduce bandwith, critical on e.g. nexdm02
-       this.effects |= EF_LOWPRECISION;
-
-       // TODO make a reset function for this one
-}
-#endif
diff --git a/qcsrc/common/triggers/func/bobbing.qh b/qcsrc/common/triggers/func/bobbing.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/breakable.qc b/qcsrc/common/triggers/func/breakable.qc
deleted file mode 100644 (file)
index ec71bc3..0000000
+++ /dev/null
@@ -1,373 +0,0 @@
-#include "breakable.qh"
-#ifdef SVQC
-
-#include <server/g_subs.qh>
-#include <server/g_damage.qh>
-#include <server/bot/api.qh>
-#include <common/csqcmodel_settings.qh>
-#include <lib/csqcmodel/sv_model.qh>
-#include <server/weapons/common.qh>
-
-.entity sprite;
-
-.float dmg;
-.float dmg_edge;
-.float dmg_radius;
-.float dmg_force;
-.float debrismovetype;
-.float debrissolid;
-.vector debrisvelocity;
-.vector debrisvelocityjitter;
-.vector debrisavelocityjitter;
-.float debristime;
-.float debristimejitter;
-.float debrisfadetime;
-.float debrisdamageforcescale;
-.float debrisskin;
-
-.string mdl_dead; // or "" to hide when broken
-.string debris; // space separated list of debris models
-// other fields:
-//   mdl = particle effect name
-//   count = particle effect multiplier
-//   targetname = target to trigger to unbreak the model
-//   target = targets to trigger when broken
-//   health = amount of damage it can take
-//   spawnflags:
-//     1 = start disabled (needs to be triggered to activate)
-//     2 = indicate damage
-//     4 = don't take direct damage (needs to be triggered to 'explode', then triggered again to restore)
-// notes:
-//   for mdl_dead to work, origin must be set (using a common/origin brush).
-//   Otherwise mdl_dead will be displayed at the map origin, and nobody would
-//   want that!
-
-void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
-
-//
-// func_breakable
-// - basically func_assault_destructible for general gameplay use
-//
-void LaunchDebris (entity this, string debrisname, vector force)
-{
-       entity dbr = spawn();
-       vector org = this.absmin
-                  + '1 0 0' * random() * (this.absmax.x - this.absmin.x)
-                  + '0 1 0' * random() * (this.absmax.y - this.absmin.y)
-                  + '0 0 1' * random() * (this.absmax.z - this.absmin.z);
-       setorigin(dbr, org);
-       _setmodel (dbr, debrisname );
-       dbr.skin = this.debrisskin;
-       dbr.colormap = this.colormap; // inherit team colors
-       dbr.owner = this; // do not be affected by our own explosion
-       set_movetype(dbr, this.debrismovetype);
-       dbr.solid = this.debrissolid;
-       if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
-               setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
-       dbr.velocity_x = this.debrisvelocity.x + this.debrisvelocityjitter.x * crandom();
-       dbr.velocity_y = this.debrisvelocity.y + this.debrisvelocityjitter.y * crandom();
-       dbr.velocity_z = this.debrisvelocity.z + this.debrisvelocityjitter.z * crandom();
-       dbr.velocity = dbr.velocity + force * this.debrisdamageforcescale;
-       dbr.angles = this.angles;
-       dbr.avelocity_x = random()*this.debrisavelocityjitter.x;
-       dbr.avelocity_y = random()*this.debrisavelocityjitter.y;
-       dbr.avelocity_z = random()*this.debrisavelocityjitter.z;
-       dbr.damageforcescale = this.debrisdamageforcescale;
-       if(dbr.damageforcescale)
-               dbr.takedamage = DAMAGE_YES;
-       SUB_SetFade(dbr, time + this.debristime + crandom() * this.debristimejitter, this.debrisfadetime);
-}
-
-void func_breakable_colormod(entity this)
-{
-       float h;
-       if (!(this.spawnflags & 2))
-               return;
-       h = this.health / this.max_health;
-       if(h < 0.25)
-               this.colormod = '1 0 0';
-       else if(h <= 0.75)
-               this.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
-       else
-               this.colormod = '1 1 1';
-}
-
-void func_breakable_look_destroyed(entity this)
-{
-       float floorZ;
-
-       if(this.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
-               this.dropped_origin = this.origin;
-
-       if(this.mdl_dead == "")
-               this.effects |= EF_NODRAW;
-       else {
-               if (this.origin == '0 0 0')     {       // probably no origin brush, so don't spawn in the middle of the map..
-                       floorZ = this.absmin.z;
-                       setorigin(this, ((this.absmax + this.absmin) * 0.5));
-                       this.origin_z = floorZ;
-               }
-               _setmodel(this, this.mdl_dead);
-               ApplyMinMaxScaleAngles(this);
-               this.effects &= ~EF_NODRAW;
-       }
-
-       this.solid = SOLID_NOT;
-}
-
-void func_breakable_look_restore(entity this)
-{
-       _setmodel(this, this.mdl);
-       ApplyMinMaxScaleAngles(this);
-       this.effects &= ~EF_NODRAW;
-
-       if(this.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
-               setorigin(this, this.dropped_origin);
-
-       this.solid = SOLID_BSP;
-}
-
-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;
-       if(this.spawnflags & 4)
-               this.use = func_null;
-       func_breakable_colormod(this);
-       if (this.noise1)
-               stopsound (this, CH_TRIGGER_SINGLE);
-}
-
-void func_breakable_think(entity this)
-{
-       this.nextthink = time;
-       CSQCMODEL_AUTOUPDATE(this);
-}
-
-void func_breakable_destroy(entity this, entity actor, entity trigger);
-void func_breakable_behave_restore(entity this)
-{
-       this.health = this.max_health;
-       if(this.sprite)
-       {
-               WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
-       }
-       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;
-       }
-       if(this.spawnflags & 4)
-               this.use = func_breakable_destroy; // don't need to set it usually, as .use isn't reset
-       this.state = 0;
-       //this.nextthink = 0; // cancel auto respawn
-       setthink(this, func_breakable_think);
-       this.nextthink = time + 0.1;
-       func_breakable_colormod(this);
-       if (this.noise1)
-               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-}
-
-void func_breakable_init_for_player(entity this, entity player)
-{
-       if (this.noise1 && this.state == 0 && IS_REAL_CLIENT(player))
-       {
-               msg_entity = player;
-               soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       }
-}
-
-void func_breakable_destroyed(entity this)
-{
-       func_breakable_look_destroyed(this);
-       func_breakable_behave_destroyed(this);
-}
-
-void func_breakable_restore(entity this, entity actor, entity trigger)
-{
-       func_breakable_look_restore(this);
-       func_breakable_behave_restore(this);
-}
-
-void func_breakable_restore_self(entity this)
-{
-       func_breakable_restore(this, NULL, NULL);
-}
-
-vector debrisforce; // global, set before calling this
-void func_breakable_destroy(entity this, entity actor, entity trigger)
-{
-       float n, i;
-       string oldmsg;
-
-       entity act = this.owner;
-       this.owner = NULL; // set by W_PrepareExplosionByDamage
-
-       // now throw around the debris
-       n = tokenize_console(this.debris);
-       for(i = 0; i < n; ++i)
-               LaunchDebris(this, argv(i), debrisforce);
-
-       func_breakable_destroyed(this);
-
-       if(this.noise)
-               _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-
-       if(this.dmg)
-               RadiusDamage(this, act, this.dmg, this.dmg_edge, this.dmg_radius, this, NULL, this.dmg_force, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, NULL);
-
-       if(this.cnt) // TODO
-               __pointparticles(this.cnt, this.absmin * 0.5 + this.absmax * 0.5, '0 0 0', this.count);
-
-       if(this.respawntime)
-       {
-               CSQCMODEL_AUTOUPDATE(this);
-               setthink(this, func_breakable_restore_self);
-               this.nextthink = time + this.respawntime + crandom() * this.respawntimejitter;
-       }
-
-       oldmsg = this.message;
-       this.message = "";
-       SUB_UseTargets(this, act, trigger);
-       this.message = oldmsg;
-}
-
-void func_breakable_destroy_self(entity this)
-{
-       func_breakable_destroy(this, NULL, NULL);
-}
-
-void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(this.state == 1)
-               return;
-       if(this.spawnflags & DOOR_NOSPLASH)
-               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
-                       return;
-       if(this.team)
-               if(attacker.team == this.team)
-                       return;
-       this.pain_finished = time;
-       this.health = this.health - damage;
-       if(this.sprite)
-       {
-               WaypointSprite_Ping(this.sprite);
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
-       }
-       func_breakable_colormod(this);
-
-       if(this.health <= 0)
-       {
-               debrisforce = force;
-
-               this.takedamage = DAMAGE_NO;
-               this.event_damage = func_null;
-
-               if(IS_CLIENT(attacker)) //&& this.classname == "func_assault_destructible")
-               {
-                       this.owner = attacker;
-                       this.realowner = attacker;
-               }
-
-               // do not explode NOW but in the NEXT FRAME!
-               // because recursive calls to RadiusDamage are not allowed
-               this.nextthink = time;
-               CSQCMODEL_AUTOUPDATE(this);
-               setthink(this, func_breakable_destroy_self);
-       }
-}
-
-void func_breakable_reset(entity this)
-{
-       this.team = this.team_saved;
-       func_breakable_look_restore(this);
-       if(this.spawnflags & 1)
-               func_breakable_behave_destroyed(this);
-       else
-               func_breakable_behave_restore(this);
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-spawnfunc(func_breakable)
-{
-       float n, i;
-       if(!this.health)
-               this.health = 100;
-       this.max_health = this.health;
-
-       // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
-       if(!this.debrismovetype) this.debrismovetype = MOVETYPE_BOUNCE;
-       if(!this.debrissolid) this.debrissolid = SOLID_NOT;
-       if(this.debrisvelocity == '0 0 0') this.debrisvelocity = '0 0 140';
-       if(this.debrisvelocityjitter == '0 0 0') this.debrisvelocityjitter = '70 70 70';
-       if(this.debrisavelocityjitter == '0 0 0') this.debrisavelocityjitter = '600 600 600';
-       if(!this.debristime) this.debristime = 3.5;
-       if(!this.debristimejitter) this.debristime = 2.5;
-
-       if(this.mdl != "")
-               this.cnt = _particleeffectnum(this.mdl);
-       if(this.count == 0)
-               this.count = 1;
-
-       if(this.message == "")
-               this.message = "got too close to an explosion";
-       if(this.message2 == "")
-               this.message2 = "was pushed into an explosion by";
-       if(!this.dmg_radius)
-               this.dmg_radius = 150;
-       if(!this.dmg_force)
-               this.dmg_force = 200;
-
-       this.mdl = this.model;
-       SetBrushEntityModel(this);
-
-       if(this.spawnflags & 4)
-               this.use = func_breakable_destroy;
-       else
-               this.use = func_breakable_restore;
-
-       if(this.spawnflags & 4)
-       {
-               this.takedamage = DAMAGE_NO;
-               this.event_damage = func_null;
-               this.bot_attack = false;
-       }
-
-       // precache all the models
-       if (this.mdl_dead)
-               precache_model(this.mdl_dead);
-       n = tokenize_console(this.debris);
-       for(i = 0; i < n; ++i)
-               precache_model(argv(i));
-       if(this.noise)
-               precache_sound(this.noise);
-       if(this.noise1)
-               precache_sound(this.noise1);
-
-       this.team_saved = this.team;
-       IL_PUSH(g_saved_team, this);
-       this.dropped_origin = this.origin;
-
-       this.reset = func_breakable_reset;
-       this.reset(this);
-
-       IL_PUSH(g_initforplayer, this);
-       this.init_for_player = func_breakable_init_for_player;
-
-       CSQCMODEL_AUTOINIT(this);
-}
-
-// for use in maps with a "model" key set
-spawnfunc(misc_breakablemodel) {
-       spawnfunc_func_breakable(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/func/breakable.qh b/qcsrc/common/triggers/func/breakable.qh
deleted file mode 100644 (file)
index 761a2c7..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#ifdef SVQC
-spawnfunc(func_breakable);
-#endif
diff --git a/qcsrc/common/triggers/func/button.qc b/qcsrc/common/triggers/func/button.qc
deleted file mode 100644 (file)
index c51c034..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-#include "button.qh"
-#ifdef SVQC
-// button and multiple button
-
-void button_wait(entity this);
-void button_return(entity this);
-
-void button_wait(entity this)
-{
-       this.state = STATE_TOP;
-       if(this.wait >= 0)
-       {
-               this.nextthink = this.ltime + this.wait;
-               setthink(this, button_return);
-       }
-       SUB_UseTargets(this, this.enemy, NULL);
-       this.frame = 1;                 // use alternate textures
-}
-
-void button_done(entity this)
-{
-       this.state = STATE_BOTTOM;
-}
-
-void button_return(entity this)
-{
-       this.state = STATE_DOWN;
-       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, button_done);
-       this.frame = 0;                 // use normal textures
-       if (this.health)
-               this.takedamage = DAMAGE_YES;   // can be shot again
-}
-
-
-void button_blocked(entity this, entity blocker)
-{
-       // do nothing, just don't come all the way back out
-}
-
-
-void button_fire(entity this)
-{
-       this.health = this.max_health;
-       this.takedamage = DAMAGE_NO;    // will be reset upon return
-
-       if (this.state == STATE_UP || this.state == STATE_TOP)
-               return;
-
-       if (this.noise != "")
-               _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-
-       this.state = STATE_UP;
-       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, button_wait);
-}
-
-void button_reset(entity this)
-{
-       this.health = this.max_health;
-       setorigin(this, this.pos1);
-       this.frame = 0;                 // use normal textures
-       this.state = STATE_BOTTOM;
-       this.velocity = '0 0 0';
-       setthink(this, func_null);
-       this.nextthink = 0;
-       if (this.health)
-               this.takedamage = DAMAGE_YES;   // can be shot again
-}
-
-void button_use(entity this, entity actor, entity trigger)
-{
-       if(this.active != ACTIVE_ACTIVE)
-               return;
-
-       this.enemy = actor;
-       button_fire(this);
-}
-
-void button_touch(entity this, entity toucher)
-{
-       if (!toucher)
-               return;
-       if (!toucher.iscreature)
-               return;
-       if(toucher.velocity * this.movedir < 0)
-               return;
-       this.enemy = toucher;
-       if (toucher.owner)
-               this.enemy = toucher.owner;
-       button_fire (this);
-}
-
-void button_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(this.spawnflags & DOOR_NOSPLASH)
-               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
-                       return;
-       if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
-       {
-               if (this.health <= damage)
-               {
-                       this.enemy = attacker;
-                       button_fire(this);
-               }
-       }
-       else
-       {
-               this.health = this.health - damage;
-               if (this.health <= 0)
-               {
-                       this.enemy = attacker;
-                       button_fire(this);
-               }
-       }
-}
-
-
-/*QUAKED spawnfunc_func_button (0 .5 .8) ?
-When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
-
-"angle"                determines the opening direction
-"target"       all entities with a matching targetname will be used
-"speed"                override the default 40 speed
-"wait"         override the default 1 second wait (-1 = never return)
-"lip"          override the default 4 pixel lip remaining at end of move
-"health"       if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
-"sounds"
-0) steam metal
-1) wooden clunk
-2) metallic click
-3) in-out
-*/
-spawnfunc(func_button)
-{
-       SetMovedir(this);
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-       this.effects |= EF_LOWPRECISION;
-
-       setblocked(this, button_blocked);
-       this.use = button_use;
-
-//     if (this.health == 0) // all buttons are now shootable
-//             this.health = 10;
-       if (this.health)
-       {
-               this.max_health = this.health;
-               this.event_damage = button_damage;
-               this.takedamage = DAMAGE_YES;
-       }
-       else
-               settouch(this, button_touch);
-
-       if (!this.speed)
-               this.speed = 40;
-       if (!this.wait)
-               this.wait = 1;
-       if (!this.lip)
-               this.lip = 4;
-
-    if(this.noise != "")
-        precache_sound(this.noise);
-
-       this.active = ACTIVE_ACTIVE;
-
-       this.pos1 = this.origin;
-       this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
-    this.flags |= FL_NOTARGET;
-
-    this.reset = button_reset;
-
-       button_reset(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/func/button.qh b/qcsrc/common/triggers/func/button.qh
deleted file mode 100644 (file)
index 75a6006..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-const int BUTTON_DONTACCUMULATEDMG = 128;
diff --git a/qcsrc/common/triggers/func/conveyor.qc b/qcsrc/common/triggers/func/conveyor.qc
deleted file mode 100644 (file)
index 1802a75..0000000
+++ /dev/null
@@ -1,192 +0,0 @@
-#include "conveyor.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_CONVEYOR)
-
-void conveyor_think(entity this)
-{
-#ifdef CSQC
-       // TODO: check if this is what is causing the glitchiness when switching between them
-       float dt = time - this.move_time;
-       this.move_time = time;
-       if(dt <= 0) { return; }
-#endif
-
-       // set myself as current conveyor where possible
-       IL_EACH(g_conveyed, it.conveyor == this,
-       {
-               it.conveyor = NULL;
-               IL_REMOVE(g_conveyed, it);
-       });
-
-       if(this.state)
-       {
-               FOREACH_ENTITY_RADIUS((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1, !it.conveyor.state && isPushable(it),
-               {
-                       vector emin = it.absmin;
-                       vector emax = it.absmax;
-                       if(this.solid == SOLID_BSP)
-                       {
-                               emin -= '1 1 1';
-                               emax += '1 1 1';
-                       }
-                       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;
-                               }
-               });
-
-               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;
-
-                       setorigin(it, it.origin + this.movedir * PHYS_INPUT_FRAMETIME);
-                       move_out_of_solid(it);
-#ifdef SVQC
-                       UpdateCSQCProjectile(it);
-#endif
-                       /*
-                       // stupid conveyor code
-                       tracebox(it.origin, it.mins, it.maxs, it.origin + this.movedir * sys_frametime, MOVE_NORMAL, it);
-                       if(trace_fraction > 0)
-                               setorigin(it, trace_endpos);
-                       */
-               });
-       }
-
-#ifdef SVQC
-       this.nextthink = time;
-#endif
-}
-
-#ifdef SVQC
-
-void conveyor_use(entity this, entity actor, entity trigger)
-{
-       this.state = !this.state;
-
-       this.SendFlags |= 2;
-}
-
-void conveyor_reset(entity this)
-{
-       this.state = (this.spawnflags & 1);
-
-       this.SendFlags |= 2;
-}
-
-bool conveyor_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_CONVEYOR);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & 1)
-       {
-               WriteByte(MSG_ENTITY, this.warpzone_isboxy);
-               WriteVector(MSG_ENTITY, this.origin);
-
-               WriteVector(MSG_ENTITY, this.mins);
-               WriteVector(MSG_ENTITY, this.maxs);
-
-               WriteVector(MSG_ENTITY, this.movedir);
-
-               WriteByte(MSG_ENTITY, this.speed);
-               WriteByte(MSG_ENTITY, this.state);
-
-               WriteString(MSG_ENTITY, this.targetname);
-               WriteString(MSG_ENTITY, this.target);
-       }
-
-       if(sf & 2)
-               WriteByte(MSG_ENTITY, this.state);
-
-       return true;
-}
-
-void conveyor_init(entity this)
-{
-       if (!this.speed) this.speed = 200;
-       this.movedir *= this.speed;
-       setthink(this, conveyor_think);
-       this.nextthink = time;
-       IFTARGETED
-       {
-               this.use = conveyor_use;
-               this.reset = conveyor_reset;
-               this.reset(this);
-       }
-       else
-               this.state = 1;
-
-       FixSize(this);
-
-       Net_LinkEntity(this, 0, false, conveyor_send);
-
-       this.SendFlags |= 1;
-}
-
-spawnfunc(trigger_conveyor)
-{
-       SetMovedir(this);
-       EXACTTRIGGER_INIT;
-       conveyor_init(this);
-}
-
-spawnfunc(func_conveyor)
-{
-       SetMovedir(this);
-       InitMovingBrushTrigger(this);
-       set_movetype(this, MOVETYPE_NONE);
-       conveyor_init(this);
-}
-
-#elif defined(CSQC)
-
-void conveyor_draw(entity this) { conveyor_think(this); }
-
-void conveyor_init(entity this, bool isnew)
-{
-       if(isnew)
-               IL_PUSH(g_drawables, this);
-       this.draw = conveyor_draw;
-       this.drawmask = MASK_NORMAL;
-
-       set_movetype(this, MOVETYPE_NONE);
-       this.model = "";
-       this.solid = SOLID_TRIGGER;
-       this.move_time = time;
-}
-
-NET_HANDLE(ENT_CLIENT_CONVEYOR, bool isnew)
-{
-       int sf = ReadByte();
-
-       if(sf & 1)
-       {
-               this.warpzone_isboxy = ReadByte();
-               this.origin = ReadVector();
-               setorigin(this, this.origin);
-
-               this.mins = ReadVector();
-               this.maxs = ReadVector();
-               setsize(this, this.mins, this.maxs);
-
-               this.movedir = ReadVector();
-
-               this.speed = ReadByte();
-               this.state = ReadByte();
-
-               this.targetname = strzone(ReadString());
-               this.target = strzone(ReadString());
-
-               conveyor_init(this, isnew);
-       }
-
-       if(sf & 2)
-               this.state = ReadByte();
-
-       return true;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/conveyor.qh b/qcsrc/common/triggers/func/conveyor.qh
deleted file mode 100644 (file)
index c12b52d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-IntrusiveList g_conveyed;
-STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
diff --git a/qcsrc/common/triggers/func/door.qc b/qcsrc/common/triggers/func/door.qc
deleted file mode 100644 (file)
index f768717..0000000
+++ /dev/null
@@ -1,829 +0,0 @@
-#include "door.qh"
-/*
-
-Doors are similar to buttons, but can spawn a fat trigger field around them
-to open without a touch, and they link together to form simultanious
-double/quad doors.
-
-Door.owner is the master door.  If there is only one door, it points to itself.
-If multiple doors, all will point to a single one.
-
-Door.enemy chains from the master door through all doors linked in the chain.
-
-*/
-
-
-/*
-=============================================================================
-
-THINK FUNCTIONS
-
-=============================================================================
-*/
-
-void door_go_down(entity this);
-void door_go_up(entity this, entity actor, entity trigger);
-void door_rotating_go_down(entity this);
-void door_rotating_go_up(entity this, entity oth);
-
-void door_blocked(entity this, entity blocker)
-{
-       if((this.spawnflags & 8)
-#ifdef SVQC
-               && (blocker.takedamage != DAMAGE_NO)
-#elif defined(CSQC)
-               && !IS_DEAD(blocker)
-#endif
-       )
-       { // KIll Kill Kill!!
-#ifdef SVQC
-               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-       }
-       else
-       {
-#ifdef SVQC
-               if((this.dmg) && (blocker.takedamage == DAMAGE_YES))    // Shall we bite?
-                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-
-                // don't change direction for dead or dying stuff
-               if(IS_DEAD(blocker)
-#ifdef SVQC
-                       && (blocker.takedamage == DAMAGE_NO)
-#endif
-               )
-               {
-                       if (this.wait >= 0)
-                       {
-                               if (this.state == STATE_DOWN)
-                       if (this.classname == "door")
-                       {
-                               door_go_up (this, NULL, NULL);
-                       } else
-                       {
-                               door_rotating_go_up(this, blocker);
-                       }
-                               else
-                       if (this.classname == "door")
-                       {
-                               door_go_down (this);
-                       } else
-                       {
-                               door_rotating_go_down (this);
-                       }
-                       }
-               }
-#ifdef SVQC
-               else
-               {
-                       //gib dying stuff just to make sure
-                       if((this.dmg) && (blocker.takedamage != DAMAGE_NO))    // Shall we bite?
-                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-               }
-#endif
-       }
-}
-
-void door_hit_top(entity this)
-{
-       if (this.noise1 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.state = STATE_TOP;
-       if (this.spawnflags & DOOR_TOGGLE)
-               return;         // don't come down automatically
-       if (this.classname == "door")
-       {
-               setthink(this, door_go_down);
-       } else
-       {
-               setthink(this, door_rotating_go_down);
-       }
-       this.nextthink = this.ltime + this.wait;
-}
-
-void door_hit_bottom(entity this)
-{
-       if (this.noise1 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.state = STATE_BOTTOM;
-}
-
-void door_go_down(entity this)
-{
-       if (this.noise2 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       if (this.max_health)
-       {
-               this.takedamage = DAMAGE_YES;
-               this.health = this.max_health;
-       }
-
-       this.state = STATE_DOWN;
-       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_hit_bottom);
-}
-
-void door_go_up(entity this, entity actor, entity trigger)
-{
-       if (this.state == STATE_UP)
-               return;         // already going up
-
-       if (this.state == STATE_TOP)
-       {       // reset top wait time
-               this.nextthink = this.ltime + this.wait;
-               return;
-       }
-
-       if (this.noise2 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       this.state = STATE_UP;
-       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_hit_top);
-
-       string oldmessage;
-       oldmessage = this.message;
-       this.message = "";
-       SUB_UseTargets(this, actor, trigger);
-       this.message = oldmessage;
-}
-
-
-/*
-=============================================================================
-
-ACTIVATION FUNCTIONS
-
-=============================================================================
-*/
-
-bool door_check_keys(entity door, entity player)
-{
-       if(door.owner)
-               door = door.owner;
-
-       // no key needed
-       if(!door.itemkeys)
-               return true;
-
-       // this door require a key
-       // only a player can have a key
-       if(!IS_PLAYER(player))
-               return false;
-
-       entity store = player;
-#ifdef SVQC
-       store = PS(player);
-#endif
-       int valid = (door.itemkeys & store.itemkeys);
-       door.itemkeys &= ~valid; // only some of the needed keys were given
-
-       if(!door.itemkeys)
-       {
-#ifdef SVQC
-               play2(player, SND(TALK));
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_UNLOCKED);
-#endif
-               return true;
-       }
-
-       if(!valid)
-       {
-#ifdef SVQC
-               if(player.key_door_messagetime <= time)
-               {
-                       play2(player, door.noise3);
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
-                       player.key_door_messagetime = time + 2;
-               }
-#endif
-               return false;
-       }
-
-       // door needs keys the player doesn't have
-#ifdef SVQC
-       if(player.key_door_messagetime <= time)
-       {
-               play2(player, door.noise3);
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
-               player.key_door_messagetime = time + 2;
-       }
-#endif
-
-       return false;
-}
-
-void door_fire(entity this, entity actor, entity trigger)
-{
-       if (this.owner != this)
-               objerror (this, "door_fire: this.owner != this");
-
-       if (this.spawnflags & DOOR_TOGGLE)
-       {
-               if (this.state == STATE_UP || this.state == STATE_TOP)
-               {
-                       entity e = this;
-                       do {
-                               if (e.classname == "door") {
-                                       door_go_down(e);
-                               } else {
-                                       door_rotating_go_down(e);
-                               }
-                               e = e.enemy;
-                       } while ((e != this) && (e != NULL));
-                       return;
-               }
-       }
-
-// trigger all paired doors
-       entity e = this;
-       do {
-               if (e.classname == "door") {
-                       door_go_up(e, actor, trigger);
-               } else {
-                       // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
-                       if ((e.spawnflags & 2) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
-                               e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
-                               e.pos2 = '0 0 0' - e.pos2;
-                       }
-                       // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
-                       if (!((e.spawnflags & 2) &&  (e.spawnflags & 8) && e.state == STATE_DOWN
-                               && (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
-                       {
-                               door_rotating_go_up(e, trigger);
-                       }
-               }
-               e = e.enemy;
-       } while ((e != this) && (e != NULL));
-}
-
-void door_use(entity this, entity actor, entity trigger)
-{
-       //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
-
-       if (this.owner)
-               door_fire(this.owner, actor, trigger);
-}
-
-void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(this.spawnflags & DOOR_NOSPLASH)
-               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
-                       return;
-       this.health = this.health - damage;
-
-       if (this.itemkeys)
-       {
-               // don't allow opening doors through damage if keys are required
-               return;
-       }
-
-       if (this.health <= 0)
-       {
-               this.owner.health = this.owner.max_health;
-               this.owner.takedamage = DAMAGE_NO;      // wil be reset upon return
-               door_use(this.owner, NULL, NULL);
-       }
-}
-
-.float door_finished;
-
-/*
-================
-door_touch
-
-Prints messages
-================
-*/
-
-void door_touch(entity this, entity toucher)
-{
-       if (!IS_PLAYER(toucher))
-               return;
-       if (this.owner.door_finished > time)
-               return;
-
-       this.owner.door_finished = time + 2;
-
-#ifdef SVQC
-       if (!(this.owner.dmg) && (this.owner.message != ""))
-       {
-               if (IS_CLIENT(toucher))
-                       centerprint(toucher, this.owner.message);
-               play2(toucher, this.owner.noise);
-       }
-#endif
-}
-
-void door_generic_plat_blocked(entity this, entity blocker)
-{
-       if((this.spawnflags & 8) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
-#ifdef SVQC
-               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-       }
-       else
-       {
-
-#ifdef SVQC
-               if((this.dmg) && (blocker.takedamage == DAMAGE_YES))    // Shall we bite?
-                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-
-                //Dont chamge direction for dead or dying stuff
-               if(IS_DEAD(blocker) && (blocker.takedamage == DAMAGE_NO))
-               {
-                       if (this.wait >= 0)
-                       {
-                               if (this.state == STATE_DOWN)
-                                       door_rotating_go_up (this, blocker);
-                               else
-                                       door_rotating_go_down (this);
-                       }
-               }
-#ifdef SVQC
-               else
-               {
-                       //gib dying stuff just to make sure
-                       if((this.dmg) && (blocker.takedamage != DAMAGE_NO))    // Shall we bite?
-                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-               }
-#endif
-       }
-}
-
-void door_rotating_hit_top(entity this)
-{
-       if (this.noise1 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.state = STATE_TOP;
-       if (this.spawnflags & DOOR_TOGGLE)
-               return;         // don't come down automatically
-       setthink(this, door_rotating_go_down);
-       this.nextthink = this.ltime + this.wait;
-}
-
-void door_rotating_hit_bottom(entity this)
-{
-       if (this.noise1 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       if (this.lip==666) // this.lip is used to remember reverse opening direction for door_rotating
-       {
-               this.pos2 = '0 0 0' - this.pos2;
-               this.lip = 0;
-       }
-       this.state = STATE_BOTTOM;
-}
-
-void door_rotating_go_down(entity this)
-{
-       if (this.noise2 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       if (this.max_health)
-       {
-               this.takedamage = DAMAGE_YES;
-               this.health = this.max_health;
-       }
-
-       this.state = STATE_DOWN;
-       SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
-}
-
-void door_rotating_go_up(entity this, entity oth)
-{
-       if (this.state == STATE_UP)
-               return;         // already going up
-
-       if (this.state == STATE_TOP)
-       {       // reset top wait time
-               this.nextthink = this.ltime + this.wait;
-               return;
-       }
-       if (this.noise2 != "")
-               _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       this.state = STATE_UP;
-       SUB_CalcAngleMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_rotating_hit_top);
-
-       string oldmessage;
-       oldmessage = this.message;
-       this.message = "";
-       SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
-       this.message = oldmessage;
-}
-
-
-/*
-=========================================
-door trigger
-
-Spawned if a door lacks a real activator
-=========================================
-*/
-
-void door_trigger_touch(entity this, entity toucher)
-{
-       if (toucher.health < 1)
-#ifdef SVQC
-               if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
-#elif defined(CSQC)
-               if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
-#endif
-                       return;
-
-       if (time < this.door_finished)
-               return;
-
-       // check if door is locked
-       if (!door_check_keys(this, toucher))
-               return;
-
-       this.door_finished = time + 1;
-
-       door_use(this.owner, toucher, NULL);
-}
-
-void door_spawnfield(entity this, vector fmins, vector fmaxs)
-{
-       entity  trigger;
-       vector  t1 = fmins, t2 = fmaxs;
-
-       trigger = new(doortriggerfield);
-       set_movetype(trigger, MOVETYPE_NONE);
-       trigger.solid = SOLID_TRIGGER;
-       trigger.owner = this;
-#ifdef SVQC
-       settouch(trigger, door_trigger_touch);
-#endif
-
-       setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
-}
-
-
-/*
-=============
-LinkDoors
-
-
-=============
-*/
-
-entity LinkDoors_nextent(entity cur, entity near, entity pass)
-{
-       while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & 4) || cur.enemy))
-       {
-       }
-       return cur;
-}
-
-bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
-{
-       float DELTA = 4;
-       if((e1.absmin_x > e2.absmax_x + DELTA)
-       || (e1.absmin_y > e2.absmax_y + DELTA)
-       || (e1.absmin_z > e2.absmax_z + DELTA)
-       || (e2.absmin_x > e1.absmax_x + DELTA)
-       || (e2.absmin_y > e1.absmax_y + DELTA)
-       || (e2.absmin_z > e1.absmax_z + DELTA)
-       ) { return false; }
-       return true;
-}
-
-#ifdef SVQC
-void door_link();
-#endif
-void LinkDoors(entity this)
-{
-       entity  t;
-       vector  cmins, cmaxs;
-
-#ifdef SVQC
-       door_link();
-#endif
-
-       if (this.enemy)
-               return;         // already linked by another door
-       if (this.spawnflags & 4)
-       {
-               this.owner = this.enemy = this;
-
-               if (this.health)
-                       return;
-               IFTARGETED
-                       return;
-               if (this.items)
-                       return;
-
-               door_spawnfield(this, this.absmin, this.absmax);
-
-               return;         // don't want to link this door
-       }
-
-       FindConnectedComponent(this, enemy, LinkDoors_nextent, LinkDoors_isconnected, this);
-
-       // set owner, and make a loop of the chain
-       LOG_TRACE("LinkDoors: linking doors:");
-       for(t = this; ; t = t.enemy)
-       {
-               LOG_TRACE(" ", etos(t));
-               t.owner = this;
-               if(t.enemy == NULL)
-               {
-                       t.enemy = this;
-                       break;
-               }
-       }
-       LOG_TRACE("");
-
-       // collect health, targetname, message, size
-       cmins = this.absmin;
-       cmaxs = this.absmax;
-       for(t = this; ; t = t.enemy)
-       {
-               if(t.health && !this.health)
-                       this.health = t.health;
-               if((t.targetname != "") && (this.targetname == ""))
-                       this.targetname = t.targetname;
-               if((t.message != "") && (this.message == ""))
-                       this.message = t.message;
-               if (t.absmin_x < cmins_x)
-                       cmins_x = t.absmin_x;
-               if (t.absmin_y < cmins_y)
-                       cmins_y = t.absmin_y;
-               if (t.absmin_z < cmins_z)
-                       cmins_z = t.absmin_z;
-               if (t.absmax_x > cmaxs_x)
-                       cmaxs_x = t.absmax_x;
-               if (t.absmax_y > cmaxs_y)
-                       cmaxs_y = t.absmax_y;
-               if (t.absmax_z > cmaxs_z)
-                       cmaxs_z = t.absmax_z;
-               if(t.enemy == this)
-                       break;
-       }
-
-       // distribute health, targetname, message
-       for(t = this; t; t = t.enemy)
-       {
-               t.health = this.health;
-               t.targetname = this.targetname;
-               t.message = this.message;
-               if(t.enemy == this)
-                       break;
-       }
-
-       // shootable, or triggered doors just needed the owner/enemy links,
-       // they don't spawn a field
-
-       if (this.health)
-               return;
-       IFTARGETED
-               return;
-       if (this.items)
-               return;
-
-       door_spawnfield(this, cmins, cmaxs);
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
-
-#ifdef SVQC
-/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
-if two doors touch, they are assumed to be connected and operate as a unit.
-
-TOGGLE causes the door to wait in both the start and end states for a trigger event.
-
-START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
-
-GOLD_KEY causes the door to open only if the activator holds a gold key.
-
-SILVER_KEY causes the door to open only if the activator holds a silver key.
-
-"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
-"angle"                determines the opening direction
-"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
-"health"       if set, door must be shot open
-"speed"                movement speed (100 default)
-"wait"         wait before returning (3 default, -1 = never return)
-"lip"          lip remaining at end of move (8 default)
-"dmg"          damage to inflict when blocked (2 default)
-"sounds"
-0)     no sound
-1)     stone
-2)     base
-3)     stone chain
-4)     screechy metal
-FIXME: only one sound set available at the time being
-
-*/
-
-float door_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               WriteString(MSG_ENTITY, this.classname);
-               WriteByte(MSG_ENTITY, this.spawnflags);
-
-               WriteString(MSG_ENTITY, this.model);
-
-               trigger_common_write(this, true);
-
-               WriteVector(MSG_ENTITY, this.pos1);
-               WriteVector(MSG_ENTITY, this.pos2);
-
-               WriteVector(MSG_ENTITY, this.size);
-
-               WriteShort(MSG_ENTITY, this.wait);
-               WriteShort(MSG_ENTITY, this.speed);
-               WriteByte(MSG_ENTITY, this.lip);
-               WriteByte(MSG_ENTITY, this.state);
-               WriteCoord(MSG_ENTITY, this.ltime);
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               // client makes use of this, we do not
-       }
-
-       if(sf & SF_TRIGGER_UPDATE)
-       {
-               WriteVector(MSG_ENTITY, this.origin);
-
-               WriteVector(MSG_ENTITY, this.pos1);
-               WriteVector(MSG_ENTITY, this.pos2);
-       }
-
-       return true;
-}
-
-void door_link()
-{
-       // set size now, as everything is loaded
-       //FixSize(this);
-       //Net_LinkEntity(this, false, 0, door_send);
-}
-#endif
-
-void door_init_startopen(entity this)
-{
-       setorigin(this, this.pos2);
-       this.pos2 = this.pos1;
-       this.pos1 = this.origin;
-
-#ifdef SVQC
-       this.SendFlags |= SF_TRIGGER_UPDATE;
-#endif
-}
-
-void door_reset(entity this)
-{
-       setorigin(this, this.pos1);
-       this.velocity = '0 0 0';
-       this.state = STATE_BOTTOM;
-       setthink(this, func_null);
-       this.nextthink = 0;
-
-#ifdef SVQC
-       this.SendFlags |= SF_TRIGGER_RESET;
-#endif
-}
-
-#ifdef SVQC
-
-// spawnflags require key (for now only func_door)
-spawnfunc(func_door)
-{
-       // Quake 1 keys compatibility
-       if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
-               this.itemkeys |= ITEM_KEY_BIT(0);
-       if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
-               this.itemkeys |= ITEM_KEY_BIT(1);
-
-       SetMovedir(this);
-
-       this.max_health = this.health;
-       if (!InitMovingBrushTrigger(this))
-               return;
-       this.effects |= EF_LOWPRECISION;
-       this.classname = "door";
-
-       if(this.noise == "")
-               this.noise = "misc/talk.wav";
-       if(this.noise3 == "")
-               this.noise3 = "misc/talk.wav";
-       precache_sound(this.noise);
-       precache_sound(this.noise3);
-
-       setblocked(this, door_blocked);
-       this.use = door_use;
-
-       if(this.dmg && (this.message == ""))
-               this.message = "was squished";
-       if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-
-       if (this.sounds > 0)
-       {
-               this.noise2 = "plats/medplat1.wav";
-               this.noise1 = "plats/medplat2.wav";
-       }
-
-       if(this.noise1 && this.noise1 != "") { precache_sound(this.noise1); }
-       if(this.noise2 && this.noise2 != "") { precache_sound(this.noise2); }
-
-       if (!this.speed)
-               this.speed = 100;
-       if (!this.wait)
-               this.wait = 3;
-       if (!this.lip)
-               this.lip = 8;
-
-       this.pos1 = this.origin;
-       this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
-
-       if(this.spawnflags & DOOR_NONSOLID)
-               this.solid = SOLID_NOT;
-
-// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
-// but spawn in the open position
-       if (this.spawnflags & DOOR_START_OPEN)
-               InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
-
-       this.state = STATE_BOTTOM;
-
-       if (this.health)
-       {
-               //this.canteamdamage = true; // TODO
-               this.takedamage = DAMAGE_YES;
-               this.event_damage = door_damage;
-       }
-
-       if (this.items)
-               this.wait = -1;
-
-       settouch(this, door_touch);
-
-// LinkDoors can't be done until all of the doors have been spawned, so
-// the sizes can be detected properly.
-       InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
-
-       this.reset = door_reset;
-}
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
-{
-       int sf = ReadByte();
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               this.classname = strzone(ReadString());
-               this.spawnflags = ReadByte();
-
-               this.mdl = strzone(ReadString());
-               _setmodel(this, this.mdl);
-
-               trigger_common_read(this, true);
-
-               this.pos1 = ReadVector();
-               this.pos2 = ReadVector();
-
-               this.size = ReadVector();
-
-               this.wait = ReadShort();
-               this.speed = ReadShort();
-               this.lip = ReadByte();
-               this.state = ReadByte();
-               this.ltime = ReadCoord();
-
-               this.solid = SOLID_BSP;
-               set_movetype(this, MOVETYPE_PUSH);
-               this.use = door_use;
-
-               LinkDoors(this);
-
-               if(this.spawnflags & DOOR_START_OPEN)
-                       door_init_startopen(this);
-
-               this.move_time = time;
-               set_movetype(this, MOVETYPE_PUSH);
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               door_reset(this);
-       }
-
-       if(sf & SF_TRIGGER_UPDATE)
-       {
-               this.origin = ReadVector();
-               setorigin(this, this.origin);
-
-               this.pos1 = ReadVector();
-               this.pos2 = ReadVector();
-       }
-       return true;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/func/door.qh b/qcsrc/common/triggers/func/door.qh
deleted file mode 100644 (file)
index 84a9d6a..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-// door constants
-const int DOOR_START_OPEN = 1;
-const int DOOR_DONT_LINK = 4;
-const int DOOR_TOGGLE = 32;
-
-const int DOOR_NOSPLASH = 256; // generic anti-splashdamage spawnflag
-
-const int DOOR_NONSOLID = 1024;
-
-const int SPAWNFLAGS_GOLD_KEY = 8;
-const int SPAWNFLAGS_SILVER_KEY = 16;
-
-#ifdef CSQC
-// stuff for preload
-
-.float door_finished;
-#endif
diff --git a/qcsrc/common/triggers/func/door_rotating.qc b/qcsrc/common/triggers/func/door_rotating.qc
deleted file mode 100644 (file)
index c61a026..0000000
+++ /dev/null
@@ -1,128 +0,0 @@
-#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.
-
-TOGGLE causes the door to wait in both the start and end states for a trigger event.
-
-BIDIR makes the door work bidirectional, so that the opening direction is always away from the requestor.
-The usage of bidirectional doors requires two manually instantiated triggers (trigger_multiple), the one to open it in the other direction
-must have set trigger_reverse to 1.
-BIDIR_IN_DOWN will the door prevent from reopening while closing if it is triggered from the other side.
-
-START_OPEN causes the door to move to its destination when spawned, and operate in reverse.  It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors).
-
-"message"      is printed when the door is touched if it is a trigger door and it hasn't been fired yet
-"angle"                determines the destination angle for opening. negative values reverse the direction.
-"targetname"    if set, no touch field will be spawned and a remote button or trigger field activates the door.
-"health"       if set, door must be shot open
-"speed"                movement speed (100 default)
-"wait"         wait before returning (3 default, -1 = never return)
-"dmg"          damage to inflict when blocked (2 default)
-"sounds"
-0)     no sound
-1)     stone
-2)     base
-3)     stone chain
-4)     screechy metal
-FIXME: only one sound set available at the time being
-*/
-
-void door_rotating_reset(entity this)
-{
-       this.angles = this.pos1;
-       this.avelocity = '0 0 0';
-       this.state = STATE_BOTTOM;
-       setthink(this, func_null);
-       this.nextthink = 0;
-}
-
-void door_rotating_init_startopen(entity this)
-{
-       this.angles = this.movedir;
-       this.pos2 = '0 0 0';
-       this.pos1 = this.movedir;
-}
-
-
-spawnfunc(func_door_rotating)
-{
-
-       //if (!this.deathtype) // map makers can override this
-       //      this.deathtype = " got in the way";
-
-       // I abuse "movedir" for denoting the axis for now
-       if (this.spawnflags & 64) // X (untested)
-               this.movedir = '0 0 1';
-       else if (this.spawnflags & 128) // Y (untested)
-               this.movedir = '1 0 0';
-       else // Z
-               this.movedir = '0 1 0';
-
-       if (this.angles_y==0) this.angles_y = 90;
-
-       this.movedir = this.movedir * this.angles_y;
-       this.angles = '0 0 0';
-
-       this.max_health = this.health;
-       this.avelocity = this.movedir;
-       if (!InitMovingBrushTrigger(this))
-               return;
-       this.velocity = '0 0 0';
-       //this.effects |= EF_LOWPRECISION;
-       this.classname = "door_rotating";
-
-       setblocked(this, door_blocked);
-       this.use = door_use;
-
-    if(this.spawnflags & 8)
-        this.dmg = 10000;
-
-    if(this.dmg && (this.message == ""))
-               this.message = "was squished";
-    if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-
-    if (this.sounds > 0)
-       {
-               precache_sound ("plats/medplat1.wav");
-               precache_sound ("plats/medplat2.wav");
-               this.noise2 = "plats/medplat1.wav";
-               this.noise1 = "plats/medplat2.wav";
-       }
-
-       if (!this.speed)
-               this.speed = 50;
-       if (!this.wait)
-               this.wait = 1;
-       this.lip = 0; // this.lip is used to remember reverse opening direction for door_rotating
-
-       this.pos1 = '0 0 0';
-       this.pos2 = this.movedir;
-
-// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
-// but spawn in the open position
-       if (this.spawnflags & DOOR_START_OPEN)
-               InitializeEntity(this, door_rotating_init_startopen, INITPRIO_SETLOCATION);
-
-       this.state = STATE_BOTTOM;
-
-       if (this.health)
-       {
-               //this.canteamdamage = true; // TODO
-               this.takedamage = DAMAGE_YES;
-               this.event_damage = door_damage;
-       }
-
-       if (this.items)
-               this.wait = -1;
-
-       settouch(this, door_touch);
-
-// LinkDoors can't be done until all of the doors have been spawned, so
-// the sizes can be detected properly.
-       InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
-
-       this.reset = door_rotating_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/door_rotating.qh b/qcsrc/common/triggers/func/door_rotating.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/door_secret.qc b/qcsrc/common/triggers/func/door_secret.qc
deleted file mode 100644 (file)
index 5558269..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-#include "door_secret.qh"
-#ifdef SVQC
-void fd_secret_move1(entity this);
-void fd_secret_move2(entity this);
-void fd_secret_move3(entity this);
-void fd_secret_move4(entity this);
-void fd_secret_move5(entity this);
-void fd_secret_move6(entity this);
-void fd_secret_done(entity this);
-
-const float SECRET_OPEN_ONCE = 1;              // stays open
-const float SECRET_1ST_LEFT = 2;               // 1st move is left of arrow
-const float SECRET_1ST_DOWN = 4;               // 1st move is down from arrow
-const float SECRET_NO_SHOOT = 8;               // only opened by trigger
-const float SECRET_YES_SHOOT = 16;     // shootable even if targeted
-
-void fd_secret_use(entity this, entity actor, entity trigger)
-{
-       float temp;
-       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...
-       if (this.origin != this.oldorigin)
-               return;
-
-       message_save = this.message;
-       this.message = ""; // no more message
-       SUB_UseTargets(this, actor, trigger);                           // fire all targets / killtargets
-       this.message = message_save;
-
-       this.velocity = '0 0 0';
-
-       // Make a sound, wait a little...
-
-       if (this.noise1 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.nextthink = this.ltime + 0.1;
-
-       temp = 1 - (this.spawnflags & SECRET_1ST_LEFT); // 1 or -1
-       makevectors(this.mangle);
-
-       if (!this.t_width)
-       {
-               if (this.spawnflags & SECRET_1ST_DOWN)
-                       this.t_width = fabs(v_up * this.size);
-               else
-                       this.t_width = fabs(v_right * this.size);
-       }
-
-       if (!this.t_length)
-               this.t_length = fabs(v_forward * this.size);
-
-       if (this.spawnflags & SECRET_1ST_DOWN)
-               this.dest1 = this.origin - v_up * this.t_width;
-       else
-               this.dest1 = this.origin + v_right * (this.t_width * temp);
-
-       this.dest2 = this.dest1 + v_forward * this.t_length;
-       SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move1);
-       if (this.noise2 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-}
-
-void fd_secret_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       fd_secret_use(this, NULL, NULL);
-}
-
-// Wait after first movement...
-void fd_secret_move1(entity this)
-{
-       this.nextthink = this.ltime + 1.0;
-       setthink(this, fd_secret_move2);
-       if (this.noise3 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-// Start moving sideways w/sound...
-void fd_secret_move2(entity this)
-{
-       if (this.noise2 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(this, this.dest2, TSPEED_LINEAR, this.speed, fd_secret_move3);
-}
-
-// Wait here until time to go back...
-void fd_secret_move3(entity this)
-{
-       if (this.noise3 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-       if (!(this.spawnflags & SECRET_OPEN_ONCE))
-       {
-               this.nextthink = this.ltime + this.wait;
-               setthink(this, fd_secret_move4);
-       }
-}
-
-// Move backward...
-void fd_secret_move4(entity this)
-{
-       if (this.noise2 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move5);
-}
-
-// Wait 1 second...
-void fd_secret_move5(entity this)
-{
-       this.nextthink = this.ltime + 1.0;
-       setthink(this, fd_secret_move6);
-       if (this.noise3 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-void fd_secret_move6(entity this)
-{
-       if (this.noise2 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
-       SUB_CalcMove(this, this.oldorigin, TSPEED_LINEAR, this.speed, fd_secret_done);
-}
-
-void fd_secret_done(entity this)
-{
-       if (this.spawnflags&SECRET_YES_SHOOT)
-       {
-               this.health = 10000;
-               this.takedamage = DAMAGE_YES;
-               //this.th_pain = fd_secret_use;
-       }
-       if (this.noise3 != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-.float door_finished;
-
-void secret_blocked(entity this, entity blocker)
-{
-       if (time < this.door_finished)
-               return;
-       this.door_finished = time + 0.5;
-       //T_Damage (other, this, this, this.dmg, this.dmg, this.deathtype, DT_IMPACT, (this.absmin + this.absmax) * 0.5, '0 0 0', Obituary_Generic);
-}
-
-/*
-==============
-secret_touch
-
-Prints messages
-================
-*/
-void secret_touch(entity this, entity toucher)
-{
-       if (!toucher.iscreature)
-               return;
-       if (this.door_finished > time)
-               return;
-
-       this.door_finished = time + 2;
-
-       if (this.message)
-       {
-               if (IS_CLIENT(toucher))
-                       centerprint(toucher, this.message);
-               play2(toucher, this.noise);
-       }
-}
-
-void secret_reset(entity this)
-{
-       if (this.spawnflags & SECRET_YES_SHOOT)
-       {
-               this.health = 10000;
-               this.takedamage = DAMAGE_YES;
-       }
-       setorigin(this, this.oldorigin);
-       setthink(this, func_null);
-       this.nextthink = 0;
-}
-
-/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
-Basic secret door. Slides back, then to the side. Angle determines direction.
-wait  = # of seconds before coming back
-1st_left = 1st move is left of arrow
-1st_down = 1st move is down from arrow
-always_shoot = even if targeted, keep shootable
-t_width = override WIDTH to move back (or height if going down)
-t_length = override LENGTH to move sideways
-"dmg"          damage to inflict when blocked (2 default)
-
-If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
-"sounds"
-1) medieval
-2) metal
-3) base
-*/
-
-spawnfunc(func_door_secret)
-{
-       /*if (!this.deathtype) // map makers can override this
-               this.deathtype = " got in the way";*/
-
-       if (!this.dmg) this.dmg = 2;
-
-       // Magic formula...
-       this.mangle = this.angles;
-       this.angles = '0 0 0';
-       this.classname = "door";
-       if (!InitMovingBrushTrigger(this)) return;
-       this.effects |= EF_LOWPRECISION;
-
-       if (this.noise == "") this.noise = "misc/talk.wav";
-       precache_sound(this.noise);
-
-       settouch(this, secret_touch);
-       setblocked(this, secret_blocked);
-       this.speed = 50;
-       this.use = fd_secret_use;
-       IFTARGETED
-       {
-       }
-       else
-               this.spawnflags |= SECRET_YES_SHOOT;
-
-       if (this.spawnflags & SECRET_YES_SHOOT)
-       {
-               //this.canteamdamage = true; // TODO
-               this.health = 10000;
-               this.takedamage = DAMAGE_YES;
-               this.event_damage = fd_secret_damage;
-       }
-       this.oldorigin = this.origin;
-       if (!this.wait) this.wait = 5; // seconds before closing
-
-       this.reset = secret_reset;
-       this.reset(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/func/door_secret.qh b/qcsrc/common/triggers/func/door_secret.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/fourier.qc b/qcsrc/common/triggers/func/fourier.qc
deleted file mode 100644 (file)
index 28e0f0f..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-#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.
-netname: list of <frequencymultiplier> <phase> <x> <y> <z> quadruples, separated by spaces; note that phase 0 represents a sine wave, and phase 0.25 a cosine wave (by default, it uses 1 0 0 0 1, to match func_bobbing's defaults
-speed: how long one cycle of frequency multiplier 1 in seconds (default 4)
-height: amplitude modifier (default 32)
-phase: cycle timing adjustment (0-1 as a fraction of the cycle, default 0)
-noise: path/name of looping .wav file to play.
-dmg: Do this mutch dmg every .dmgtime intervall when blocked
-dmgtime: See above.
-*/
-
-void func_fourier_controller_think(entity this)
-{
-       vector v;
-       float n, i, t;
-
-       this.nextthink = time + 0.1;
-       if(this.owner.active != ACTIVE_ACTIVE)
-       {
-               this.owner.velocity = '0 0 0';
-               return;
-       }
-
-
-       n = floor((tokenize_console(this.owner.netname)) / 5);
-       t = this.nextthink * this.owner.cnt + this.owner.phase * 360;
-
-       v = this.owner.destvec;
-
-       for(i = 0; i < n; ++i)
-       {
-               makevectors((t * stof(argv(i*5)) + stof(argv(i*5+1)) * 360) * '0 1 0');
-               v = v + ('1 0 0' * stof(argv(i*5+2)) + '0 1 0' * stof(argv(i*5+3)) + '0 0 1' * stof(argv(i*5+4))) * this.owner.height * v_forward_y;
-       }
-
-       if(this.owner.classname == "func_fourier") // don't brake stuff if the func_fourier was killtarget'ed
-               // * 10 so it will arrive in 0.1 sec
-               this.owner.velocity = (v - this.owner.origin) * 10;
-}
-
-spawnfunc(func_fourier)
-{
-       entity controller;
-       if (this.noise != "")
-       {
-               precache_sound(this.noise);
-               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
-       }
-
-       if (!this.speed)
-               this.speed = 4;
-       if (!this.height)
-               this.height = 32;
-       this.destvec = this.origin;
-       this.cnt = 360 / this.speed;
-
-       setblocked(this, generic_plat_blocked);
-       if(this.dmg && (this.message == ""))
-               this.message = " was squished";
-    if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-       if(this.dmg && (!this.dmgtime))
-               this.dmgtime = 0.25;
-       this.dmgtime2 = time;
-
-       if(this.netname == "")
-               this.netname = "1 0 0 0 1";
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-
-       this.active = ACTIVE_ACTIVE;
-
-       // wait for targets to spawn
-       controller = new(func_fourier_controller);
-       controller.owner = this;
-       controller.nextthink = time + 1;
-       setthink(controller, func_fourier_controller_think);
-       this.nextthink = this.ltime + 999999999;
-       setthink(this, SUB_NullThink); // for PushMove
-
-       // Savage: Reduce bandwith, critical on e.g. nexdm02
-       this.effects |= EF_LOWPRECISION;
-
-       // TODO make a reset function for this one
-}
-#endif
diff --git a/qcsrc/common/triggers/func/fourier.qh b/qcsrc/common/triggers/func/fourier.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/include.qc b/qcsrc/common/triggers/func/include.qc
deleted file mode 100644 (file)
index 290c2e9..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "include.qh"
-
-#include "bobbing.qc"
-#include "breakable.qc"
-#include "button.qc"
-#include "conveyor.qc"
-#include "door.qc"
-#include "door_rotating.qc"
-#include "door_secret.qc"
-#include "fourier.qc"
-#include "ladder.qc"
-#include "pendulum.qc"
-#include "plat.qc"
-#include "pointparticles.qc"
-#include "rainsnow.qc"
-#include "rotating.qc"
-#include "stardust.qc"
-#include "train.qc"
-#include "vectormamamam.qc"
diff --git a/qcsrc/common/triggers/func/include.qh b/qcsrc/common/triggers/func/include.qh
deleted file mode 100644 (file)
index 4e8b94c..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#include "door.qh"
-#include "ladder.qh"
-#include "train.qh"
diff --git a/qcsrc/common/triggers/func/ladder.qc b/qcsrc/common/triggers/func/ladder.qc
deleted file mode 100644 (file)
index 92f361a..0000000
+++ /dev/null
@@ -1,149 +0,0 @@
-#include "ladder.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_LADDER)
-
-void func_ladder_touch(entity this, entity toucher)
-{
-#ifdef SVQC
-       if (!toucher.iscreature)
-               return;
-       if(IS_VEHICLE(toucher))
-               return;
-#elif defined(CSQC)
-       if(!toucher.isplayermodel)
-               return;
-#endif
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       toucher.ladder_time = time + 0.1;
-       toucher.ladder_entity = this;
-}
-
-#ifdef SVQC
-bool func_ladder_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_LADDER);
-
-       WriteString(MSG_ENTITY, this.classname);
-       WriteByte(MSG_ENTITY, this.skin);
-       WriteCoord(MSG_ENTITY, this.speed);
-
-       trigger_common_write(this, false);
-
-       return true;
-}
-
-void func_ladder_link(entity this)
-{
-       trigger_link(this, func_ladder_send);
-       //this.model = "null";
-}
-
-void func_ladder_init(entity this)
-{
-       settouch(this, func_ladder_touch);
-       trigger_init(this);
-       func_ladder_link(this);
-
-       if(min(this.absmax.x - this.absmin.x, this.absmax.y - this.absmin.y) > 100)
-               return;
-
-       entity tracetest_ent = spawn();
-       setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
-       tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-
-       vector top_min = (this.absmin + this.absmax) / 2;
-       top_min.z = this.absmax.z;
-       vector top_max = top_min;
-       top_max.z += PL_MAX_CONST.z - PL_MIN_CONST.z;
-       tracebox(top_max + jumpstepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
-       if(trace_startsolid)
-       {
-               tracebox(top_max + stepheightvec, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
-               if(trace_startsolid)
-               {
-                       tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
-                       if(trace_startsolid)
-                       {
-                               if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
-                                       && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
-                               {
-                                       // move top on one side
-                                       top_max.y = top_min.y = this.absmin.y + (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
-                               }
-                               else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
-                                       && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
-                               {
-                                       // move top on one side
-                                       top_max.x = top_min.x = this.absmin.x + (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
-                               }
-                               tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
-                               if(trace_startsolid)
-                               {
-                                       if(this.absmax.x - this.absmin.x > PL_MAX_CONST.x - PL_MIN_CONST.x
-                                               && this.absmax.y - this.absmin.y < this.absmax.x - this.absmin.x)
-                                       {
-                                               // alternatively on the other side
-                                               top_max.y = top_min.y = this.absmax.y - (PL_MAX_CONST.y - PL_MIN_CONST.y) * 0.75;
-                                       }
-                                       else if(this.absmax.y - this.absmin.y > PL_MAX_CONST.y - PL_MIN_CONST.y
-                                               && this.absmax.x - this.absmin.x < this.absmax.y - this.absmin.y)
-                                       {
-                                               // alternatively on the other side
-                                               top_max.x = top_min.x = this.absmax.x - (PL_MAX_CONST.x - PL_MIN_CONST.x) * 0.75;
-                                       }
-                                       tracebox(top_max, PL_MIN_CONST, PL_MAX_CONST, top_min, MOVE_NOMONSTERS, tracetest_ent);
-                               }
-                       }
-               }
-       }
-       if(trace_startsolid || trace_endpos.z < this.absmax.z)
-       {
-               delete(tracetest_ent);
-               return;
-       }
-
-       this.bot_pickup = true; // allow bots to make use of this ladder
-       float cost = waypoint_getlinearcost(trace_endpos.z - this.absmin.z);
-       top_min = trace_endpos;
-       waypoint_spawnforteleporter_boxes(this, WAYPOINTFLAG_LADDER, this.absmin, this.absmax, top_min, top_min, cost);
-}
-
-spawnfunc(func_ladder)
-{
-       IL_PUSH(g_ladders, this); // TODO: also func_water? bots currently loop through func_ladder only
-
-       func_ladder_init(this);
-}
-
-spawnfunc(func_water)
-{
-       func_ladder_init(this);
-}
-
-#elif defined(CSQC)
-.float speed;
-
-void func_ladder_remove(entity this)
-{
-       if(this.classname) { strunzone(this.classname); }
-       this.classname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_LADDER, bool isnew)
-{
-       this.classname = strzone(ReadString());
-       this.skin = ReadByte();
-       this.speed = ReadCoord();
-
-       trigger_common_read(this, false);
-
-       this.solid = SOLID_TRIGGER;
-       settouch(this, func_ladder_touch);
-       this.drawmask = MASK_NORMAL;
-       this.move_time = time;
-       this.entremove = func_ladder_remove;
-
-       return true;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/ladder.qh b/qcsrc/common/triggers/func/ladder.qh
deleted file mode 100644 (file)
index 26cbbda..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-.float ladder_time;
-.entity ladder_entity;
diff --git a/qcsrc/common/triggers/func/pendulum.qc b/qcsrc/common/triggers/func/pendulum.qc
deleted file mode 100644 (file)
index a59f7a9..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-#include "pendulum.qh"
-#ifdef SVQC
-.float freq;
-void func_pendulum_controller_think(entity this)
-{
-       float v;
-       this.nextthink = time + 0.1;
-
-       if (!(this.owner.active == ACTIVE_ACTIVE))
-       {
-               this.owner.avelocity_x = 0;
-               return;
-       }
-
-       // calculate sinewave using makevectors
-       makevectors((this.nextthink * this.owner.freq + this.owner.phase) * '0 360 0');
-       v = this.owner.speed * v_forward_y + this.cnt;
-       if(this.owner.classname == "func_pendulum") // don't brake stuff if the func_bobbing was killtarget'ed
-       {
-               // * 10 so it will arrive in 0.1 sec
-               this.owner.avelocity_z = (remainder(v - this.owner.angles_z, 360)) * 10;
-       }
-}
-
-spawnfunc(func_pendulum)
-{
-       entity controller;
-       if (this.noise != "")
-       {
-               precache_sound(this.noise);
-               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
-       }
-
-       this.active = ACTIVE_ACTIVE;
-
-       // keys: angle, speed, phase, noise, freq
-
-       if(!this.speed)
-               this.speed = 30;
-       // not initializing this.dmg to 2, to allow damageless pendulum
-
-       if(this.dmg && (this.message == ""))
-               this.message = " was squished";
-       if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-       if(this.dmg && (!this.dmgtime))
-               this.dmgtime = 0.25;
-       this.dmgtime2 = time;
-
-       setblocked(this, generic_plat_blocked);
-
-       this.avelocity_z = 0.0000001;
-       if (!InitMovingBrushTrigger(this))
-               return;
-
-       if(!this.freq)
-       {
-               // find pendulum length (same formula as Q3A)
-               this.freq = 1 / (M_PI * 2) * sqrt(autocvar_sv_gravity / (3 * max(8, fabs(this.mins_z))));
-       }
-
-       // copy initial angle
-       this.cnt = this.angles_z;
-
-       // wait for targets to spawn
-       controller = new(func_pendulum_controller);
-       controller.owner = this;
-       controller.nextthink = time + 1;
-       setthink(controller, func_pendulum_controller_think);
-       this.nextthink = this.ltime + 999999999;
-       setthink(this, SUB_NullThink); // for PushMove
-
-       //this.effects |= EF_LOWPRECISION;
-
-       // TODO make a reset function for this one
-}
-#endif
diff --git a/qcsrc/common/triggers/func/pendulum.qh b/qcsrc/common/triggers/func/pendulum.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/plat.qc b/qcsrc/common/triggers/func/plat.qc
deleted file mode 100644 (file)
index 9f97a1c..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "plat.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_PLAT)
-
-#ifdef SVQC
-void plat_link(entity this);
-
-void plat_delayedinit(entity this)
-{
-       plat_link(this);
-       plat_spawn_inside_trigger(this); // the "start moving" trigger
-}
-
-float plat_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_PLAT);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               WriteByte(MSG_ENTITY, this.platmovetype_start);
-               WriteByte(MSG_ENTITY, this.platmovetype_turn);
-               WriteByte(MSG_ENTITY, this.platmovetype_end);
-               WriteByte(MSG_ENTITY, this.spawnflags);
-
-               WriteString(MSG_ENTITY, this.model);
-
-               trigger_common_write(this, true);
-
-               WriteVector(MSG_ENTITY, this.pos1);
-               WriteVector(MSG_ENTITY, this.pos2);
-
-               WriteVector(MSG_ENTITY, this.size);
-
-               WriteAngle(MSG_ENTITY, this.mangle_x);
-               WriteAngle(MSG_ENTITY, this.mangle_y);
-               WriteAngle(MSG_ENTITY, this.mangle_z);
-
-               WriteShort(MSG_ENTITY, this.speed);
-               WriteShort(MSG_ENTITY, this.height);
-               WriteByte(MSG_ENTITY, this.lip);
-               WriteByte(MSG_ENTITY, this.state);
-
-               WriteShort(MSG_ENTITY, this.dmg);
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               // used on client
-       }
-
-       return true;
-}
-
-void plat_link(entity this)
-{
-       //Net_LinkEntity(this, 0, false, plat_send);
-}
-
-spawnfunc(func_plat)
-{
-       if (this.sounds == 0) this.sounds = 2;
-
-    if (this.spawnflags & 4) this.dmg = 10000;
-
-    if (this.dmg && (this.message == "")) this.message = "was squished";
-    if (this.dmg && (this.message2 == "")) this.message2 = "was squished by";
-
-       if (this.sounds == 1)
-       {
-               this.noise = "plats/plat1.wav";
-               this.noise1 = "plats/plat2.wav";
-       }
-
-       if (this.sounds == 2)
-       {
-               this.noise = "plats/medplat1.wav";
-               this.noise1 = "plats/medplat2.wav";
-       }
-
-       if (this.sound1)
-               this.noise = this.sound1;
-       if (this.sound2)
-               this.noise1 = this.sound2;
-
-       if(this.noise && this.noise != "") { precache_sound(this.noise); }
-       if(this.noise1 && this.noise1 != "") { precache_sound(this.noise1); }
-
-       this.mangle = this.angles;
-       this.angles = '0 0 0';
-
-       this.classname = "plat";
-       if (!InitMovingBrushTrigger(this))
-               return;
-       this.effects |= EF_LOWPRECISION;
-       setsize (this, this.mins , this.maxs);
-
-       setblocked(this, plat_crush);
-
-       if (!this.speed) this.speed = 150;
-       if (!this.lip) this.lip = 16;
-       if (!this.height) this.height = this.size.z - this.lip;
-
-       this.pos1 = this.origin;
-       this.pos2 = this.origin;
-       this.pos2_z = this.origin.z - this.height;
-
-       this.reset = plat_reset;
-       this.reset(this);
-
-       InitializeEntity(this, plat_delayedinit, INITPRIO_FINDTARGET);
-}
-#elif defined(CSQC)
-void plat_draw(entity this)
-{
-       Movetype_Physics_NoMatchServer(this);
-       //Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
-}
-
-NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
-{
-       float sf = ReadByte();
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               this.platmovetype_start = ReadByte();
-               this.platmovetype_turn = ReadByte();
-               this.platmovetype_end = ReadByte();
-               this.spawnflags = ReadByte();
-
-               this.model = strzone(ReadString());
-               _setmodel(this, this.model);
-
-               trigger_common_read(this, true);
-
-               this.pos1 = ReadVector();
-               this.pos2 = ReadVector();
-
-               this.size = ReadVector();
-
-               this.mangle_x = ReadAngle();
-               this.mangle_y = ReadAngle();
-               this.mangle_z = ReadAngle();
-
-               this.speed = ReadShort();
-               this.height = ReadShort();
-               this.lip = ReadByte();
-               this.state = ReadByte();
-
-               this.dmg = ReadShort();
-
-               this.classname = "plat";
-               this.solid = SOLID_BSP;
-               set_movetype(this, MOVETYPE_PUSH);
-               this.drawmask = MASK_NORMAL;
-               this.draw = plat_draw;
-               if (isnew) IL_PUSH(g_drawables, this);
-               this.use = plat_use;
-               this.entremove = trigger_remove_generic;
-
-               plat_reset(this); // also called here
-
-               set_movetype(this, MOVETYPE_PUSH);
-               this.move_time = time;
-
-               plat_spawn_inside_trigger(this);
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               plat_reset(this);
-
-               this.move_time = time;
-       }
-       return true;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/plat.qh b/qcsrc/common/triggers/func/plat.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/pointparticles.qc b/qcsrc/common/triggers/func/pointparticles.qc
deleted file mode 100644 (file)
index 54fe212..0000000
+++ /dev/null
@@ -1,369 +0,0 @@
-#include "pointparticles.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_POINTPARTICLES)
-
-#ifdef SVQC
-// NOTE: also contains func_sparks
-
-bool pointparticles_SendEntity(entity this, entity to, float fl)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_POINTPARTICLES);
-
-       // optional features to save space
-       fl = fl & 0x0F;
-       if(this.spawnflags & 2)
-               fl |= 0x10; // absolute count on toggle-on
-       if(this.movedir != '0 0 0' || this.velocity != '0 0 0')
-               fl |= 0x20; // 4 bytes - saves CPU
-       if(this.waterlevel || this.count != 1)
-               fl |= 0x40; // 4 bytes - obscure features almost never used
-       if(this.mins != '0 0 0' || this.maxs != '0 0 0')
-               fl |= 0x80; // 14 bytes - saves lots of space
-
-       WriteByte(MSG_ENTITY, fl);
-       if(fl & 2)
-       {
-               if(this.state)
-                       WriteCoord(MSG_ENTITY, this.impulse);
-               else
-                       WriteCoord(MSG_ENTITY, 0); // off
-       }
-       if(fl & 4)
-       {
-               WriteVector(MSG_ENTITY, this.origin);
-       }
-       if(fl & 1)
-       {
-               if(this.model != "null")
-               {
-                       WriteShort(MSG_ENTITY, this.modelindex);
-                       if(fl & 0x80)
-                       {
-                               WriteVector(MSG_ENTITY, this.mins);
-                               WriteVector(MSG_ENTITY, this.maxs);
-                       }
-               }
-               else
-               {
-                       WriteShort(MSG_ENTITY, 0);
-                       if(fl & 0x80)
-                       {
-                               WriteVector(MSG_ENTITY, this.maxs);
-                       }
-               }
-               WriteShort(MSG_ENTITY, this.cnt);
-               WriteString(MSG_ENTITY, this.mdl);
-               if(fl & 0x20)
-               {
-                       WriteShort(MSG_ENTITY, compressShortVector(this.velocity));
-                       WriteShort(MSG_ENTITY, compressShortVector(this.movedir));
-               }
-               if(fl & 0x40)
-               {
-                       WriteShort(MSG_ENTITY, this.waterlevel * 16.0);
-                       WriteByte(MSG_ENTITY, this.count * 16.0);
-               }
-               WriteString(MSG_ENTITY, this.noise);
-               if(this.noise != "")
-               {
-                       WriteByte(MSG_ENTITY, floor(this.atten * 64));
-                       WriteByte(MSG_ENTITY, floor(this.volume * 255));
-               }
-               WriteString(MSG_ENTITY, this.bgmscript);
-               if(this.bgmscript != "")
-               {
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
-               }
-       }
-       return 1;
-}
-
-void pointparticles_use(entity this, entity actor, entity trigger)
-{
-       this.state = !this.state;
-       this.SendFlags |= 2;
-}
-
-void pointparticles_think(entity this)
-{
-       if(this.origin != this.oldorigin)
-       {
-               this.SendFlags |= 4;
-               this.oldorigin = this.origin;
-       }
-       this.nextthink = time;
-}
-
-void pointparticles_reset(entity this)
-{
-       if(this.spawnflags & 1)
-               this.state = 1;
-       else
-               this.state = 0;
-}
-
-spawnfunc(func_pointparticles)
-{
-       if(this.model != "") { precache_model(this.model); _setmodel(this, this.model); }
-       if(this.noise != "") precache_sound(this.noise);
-       if(this.mdl != "") this.cnt = 0; // use a good handler
-
-       if(!this.bgmscriptsustain) this.bgmscriptsustain = 1;
-       else if(this.bgmscriptsustain < 0) this.bgmscriptsustain = 0;
-
-       if(!this.atten) this.atten = ATTEN_NORM;
-       else if(this.atten < 0) this.atten = 0;
-       if(!this.volume) this.volume = 1;
-       if(!this.count) this.count = 1;
-       if(!this.impulse) this.impulse = 1;
-
-       if(!this.modelindex)
-       {
-               setorigin(this, this.origin + this.mins);
-               setsize(this, '0 0 0', this.maxs - this.mins);
-       }
-       //if(!this.cnt) this.cnt = _particleeffectnum(this.mdl);
-
-       Net_LinkEntity(this, (this.spawnflags & 4), 0, pointparticles_SendEntity);
-
-       IFTARGETED
-       {
-               this.use = pointparticles_use;
-               this.reset = pointparticles_reset;
-               this.reset(this);
-       }
-       else
-               this.state = 1;
-       setthink(this, pointparticles_think);
-       this.nextthink = time;
-}
-
-spawnfunc(func_sparks)
-{
-       // this.cnt is the amount of sparks that one burst will spawn
-       if(this.cnt < 1) {
-               this.cnt = 25.0; // nice default value
-       }
-
-       // this.wait is the probability that a sparkthink will spawn a spark shower
-       // range: 0 - 1, but 0 makes little sense, so...
-       if(this.wait < 0.05) {
-               this.wait = 0.25; // nice default value
-       }
-
-       this.count = this.cnt;
-       this.mins = '0 0 0';
-       this.maxs = '0 0 0';
-       this.velocity = '0 0 -1';
-       this.mdl = "TE_SPARK";
-       this.impulse = 10 * this.wait; // by default 2.5/sec
-       this.wait = 0;
-       this.cnt = 0; // use mdl
-
-       spawnfunc_func_pointparticles(this);
-}
-#elif defined(CSQC)
-
-.int dphitcontentsmask;
-
-entityclass(PointParticles);
-class(PointParticles) .int cnt; // effect number
-class(PointParticles) .vector velocity; // particle velocity
-class(PointParticles) .float waterlevel; // direction jitter
-class(PointParticles) .int count; // count multiplier
-class(PointParticles) .int impulse; // density
-class(PointParticles) .string noise; // sound
-class(PointParticles) .float atten;
-class(PointParticles) .float volume;
-class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
-class(PointParticles) .vector movedir; // trace direction
-class(PointParticles) .float glow_color; // palette index
-
-void Draw_PointParticles(entity this)
-{
-       float n, i, fail;
-       vector p;
-       vector sz;
-       vector o;
-       o = this.origin;
-       sz = this.maxs - this.mins;
-       n = doBGMScript(this);
-       if(this.absolute == 2)
-       {
-               if(n >= 0)
-                       n = this.just_toggled ? this.impulse : 0;
-               else
-                       n = this.impulse * drawframetime;
-       }
-       else
-       {
-               n *= this.impulse * drawframetime;
-               if(this.just_toggled)
-                       if(n < 1)
-                               n = 1;
-       }
-       if(n == 0)
-               return;
-       fail = 0;
-       for(i = random(); i <= n && fail <= 64*n; ++i)
-       {
-               p = o + this.mins;
-               p.x += random() * sz.x;
-               p.y += random() * sz.y;
-               p.z += random() * sz.z;
-               if(WarpZoneLib_BoxTouchesBrush(p, p, this, NULL))
-               {
-                       if(this.movedir != '0 0 0')
-                       {
-                               traceline(p, p + normalize(this.movedir) * 4096, 0, NULL);
-                               p = trace_endpos;
-                               int eff_num;
-                               if(this.cnt)
-                                       eff_num = this.cnt;
-                               else
-                                       eff_num = _particleeffectnum(this.mdl);
-                               __pointparticles(eff_num, p, trace_plane_normal * vlen(this.movedir) + this.velocity + randomvec() * this.waterlevel, this.count);
-                       }
-                       else
-                       {
-                               int eff_num;
-                               if(this.cnt)
-                                       eff_num = this.cnt;
-                               else
-                                       eff_num = _particleeffectnum(this.mdl);
-                               __pointparticles(eff_num, p, this.velocity + randomvec() * this.waterlevel, this.count);
-                       }
-                       if(this.noise != "")
-                       {
-                               setorigin(this, p);
-                               _sound(this, CH_AMBIENT, this.noise, VOL_BASE * this.volume, this.atten);
-                       }
-                       this.just_toggled = 0;
-               }
-               else if(this.absolute)
-               {
-                       ++fail;
-                       --i;
-               }
-       }
-       setorigin(this, o);
-}
-
-void Ent_PointParticles_Remove(entity this)
-{
-       if(this.noise)
-               strunzone(this.noise);
-       this.noise = string_null;
-       if(this.bgmscript)
-               strunzone(this.bgmscript);
-       this.bgmscript = string_null;
-       if(this.mdl)
-               strunzone(this.mdl);
-       this.mdl = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
-{
-       float i;
-       vector v;
-       int f = ReadByte();
-       if(f & 2)
-       {
-               i = ReadCoord(); // density (<0: point, >0: volume)
-               if(i && !this.impulse && (this.cnt || this.mdl)) // this.cnt check is so it only happens if the ent already existed
-                       this.just_toggled = 1;
-               this.impulse = i;
-       }
-       if(f & 4)
-       {
-               this.origin = ReadVector();
-       }
-       if(f & 1)
-       {
-               this.modelindex = ReadShort();
-               if(f & 0x80)
-               {
-                       if(this.modelindex)
-                       {
-                               this.mins = ReadVector();
-                               this.maxs = ReadVector();
-                       }
-                       else
-                       {
-                               this.mins    = '0 0 0';
-                               this.maxs = ReadVector();
-                       }
-               }
-               else
-               {
-                       this.mins = this.maxs = '0 0 0';
-               }
-
-               this.cnt = ReadShort(); // effect number
-               this.mdl = strzone(ReadString()); // effect string
-
-               if(f & 0x20)
-               {
-                       this.velocity = decompressShortVector(ReadShort());
-                       this.movedir = decompressShortVector(ReadShort());
-               }
-               else
-               {
-                       this.velocity = this.movedir = '0 0 0';
-               }
-               if(f & 0x40)
-               {
-                       this.waterlevel = ReadShort() / 16.0;
-                       this.count = ReadByte() / 16.0;
-               }
-               else
-               {
-                       this.waterlevel = 0;
-                       this.count = 1;
-               }
-               if(this.noise)
-                       strunzone(this.noise);
-               if(this.bgmscript)
-                       strunzone(this.bgmscript);
-               this.noise = strzone(ReadString());
-               if(this.noise != "")
-               {
-                       this.atten = ReadByte() / 64.0;
-                       this.volume = ReadByte() / 255.0;
-               }
-               this.bgmscript = strzone(ReadString());
-               if(this.bgmscript != "")
-               {
-                       this.bgmscriptattack = ReadByte() / 64.0;
-                       this.bgmscriptdecay = ReadByte() / 64.0;
-                       this.bgmscriptsustain = ReadByte() / 255.0;
-                       this.bgmscriptrelease = ReadByte() / 64.0;
-               }
-               BGMScript_InitEntity(this);
-       }
-
-       return = true;
-
-       if(f & 2)
-       {
-               this.absolute = (this.impulse >= 0);
-               if(!this.absolute)
-               {
-                       v = this.maxs - this.mins;
-                       this.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
-               }
-       }
-
-       if(f & 0x10)
-               this.absolute = 2;
-
-       setorigin(this, this.origin);
-       setsize(this, this.mins, this.maxs);
-       this.solid = SOLID_NOT;
-       this.draw = Draw_PointParticles;
-       if (isnew) IL_PUSH(g_drawables, this);
-       this.entremove = Ent_PointParticles_Remove;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/pointparticles.qh b/qcsrc/common/triggers/func/pointparticles.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/rainsnow.qc b/qcsrc/common/triggers/func/rainsnow.qc
deleted file mode 100644 (file)
index 1817a9c..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-#include "rainsnow.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
-
-#ifdef SVQC
-bool rainsnow_SendEntity(entity this, entity to, float sf)
-{
-       vector myorg = this.origin + this.mins;
-       vector mysize = this.maxs - this.mins;
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
-       WriteByte(MSG_ENTITY, this.state);
-       WriteVector(MSG_ENTITY, myorg);
-       WriteVector(MSG_ENTITY, mysize);
-       WriteShort(MSG_ENTITY, compressShortVector(this.dest));
-       WriteShort(MSG_ENTITY, this.count);
-       WriteByte(MSG_ENTITY, this.cnt);
-       return true;
-}
-
-/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
-This is an invisible area like a trigger, which rain falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-spawnfunc(func_rain)
-{
-       this.dest = this.velocity;
-       this.velocity = '0 0 0';
-       if (!this.dest)
-               this.dest = '0 0 -700';
-       this.angles = '0 0 0';
-       set_movetype(this, MOVETYPE_NONE);
-       this.solid = SOLID_NOT;
-       SetBrushEntityModel(this);
-       if (!this.cnt)
-               this.cnt = 12;
-       if (!this.count)
-               this.count = 2000;
-       this.count = 0.01 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
-       if (this.count < 1)
-               this.count = 1;
-       if(this.count > 65535)
-               this.count = 65535;
-
-       this.state = 1; // 1 is rain, 0 is snow
-       this.Version = 1;
-
-       Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
-}
-
-
-/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
-This is an invisible area like a trigger, which snow falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-spawnfunc(func_snow)
-{
-       this.dest = this.velocity;
-       this.velocity = '0 0 0';
-       if (!this.dest)
-               this.dest = '0 0 -300';
-       this.angles = '0 0 0';
-       set_movetype(this, MOVETYPE_NONE);
-       this.solid = SOLID_NOT;
-       SetBrushEntityModel(this);
-       if (!this.cnt)
-               this.cnt = 12;
-       if (!this.count)
-               this.count = 2000;
-       this.count = 0.01 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
-       if (this.count < 1)
-               this.count = 1;
-       if(this.count > 65535)
-               this.count = 65535;
-
-       this.state = 0; // 1 is rain, 0 is snow
-       this.Version = 1;
-
-       Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
-}
-#elif defined(CSQC)
-float autocvar_cl_rainsnow_maxdrawdist = 2048;
-
-void Draw_Rain(entity this)
-{
-       vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
-       maxdist.z = 5;
-       if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
-       //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
-       te_particlerain(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
-}
-
-void Draw_Snow(entity this)
-{
-       vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
-       maxdist.z = 5;
-       if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
-       //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
-       te_particlesnow(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
-}
-
-NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
-{
-       this.impulse = ReadByte(); // Rain, Snow, or Whatever
-       this.origin = ReadVector();
-       this.maxs = ReadVector();
-       this.velocity = decompressShortVector(ReadShort());
-       this.count = ReadShort() * 10;
-       this.glow_color = ReadByte(); // color
-
-       return = true;
-
-       this.mins    = -0.5 * this.maxs;
-       this.maxs    =  0.5 * this.maxs;
-       this.origin  = this.origin - this.mins;
-
-       setorigin(this, this.origin);
-       setsize(this, this.mins, this.maxs);
-       this.solid = SOLID_NOT;
-       if (isnew) IL_PUSH(g_drawables, this);
-       if(this.impulse)
-               this.draw = Draw_Rain;
-       else
-               this.draw = Draw_Snow;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/rainsnow.qh b/qcsrc/common/triggers/func/rainsnow.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/rotating.qc b/qcsrc/common/triggers/func/rotating.qc
deleted file mode 100644 (file)
index 6268dcf..0000000
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "rotating.qh"
-#ifdef SVQC
-const int FUNC_ROTATING_STARTOFF = BIT(4);
-
-void func_rotating_setactive(entity this, int astate)
-{
-       if (astate == ACTIVE_TOGGLE)
-       {
-               if(this.active == ACTIVE_ACTIVE)
-                       this.active = ACTIVE_NOT;
-               else
-                       this.active = ACTIVE_ACTIVE;
-       }
-       else
-               this.active = astate;
-
-       if(this.active  == ACTIVE_NOT)
-               this.avelocity = '0 0 0';
-       else
-               this.avelocity = this.pos1;
-}
-
-void func_rotating_reset(entity this)
-{
-       // TODO: reset angles as well?
-
-       if(this.spawnflags & FUNC_ROTATING_STARTOFF)
-       {
-               this.avelocity = '0 0 0';
-               this.active = ACTIVE_NOT;
-       }
-       else
-       {
-               this.avelocity = this.pos1;
-               this.active = ACTIVE_ACTIVE;
-       }
-}
-
-/*QUAKED spawnfunc_func_rotating (0 .5 .8) ? - - X_AXIS Y_AXIS
-Brush model that spins in place on one axis (default Z).
-speed   : speed to rotate (in degrees per second)
-noise   : path/name of looping .wav file to play.
-dmg     : Do this mutch dmg every .dmgtime intervall when blocked
-dmgtime : See above.
-*/
-
-spawnfunc(func_rotating)
-{
-       if (this.noise != "")
-       {
-               precache_sound(this.noise);
-               ambientsound(this.origin, this.noise, VOL_BASE, ATTEN_IDLE);
-       }
-
-       this.setactive = func_rotating_setactive;
-
-       if (!this.speed)
-               this.speed = 100;
-       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
-       if (this.spawnflags & BIT(2)) // X (untested)
-               this.avelocity = '0 0 1' * this.speed;
-       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
-       else if (this.spawnflags & BIT(3)) // Y (untested)
-               this.avelocity = '1 0 0' * this.speed;
-       // FIXME: test if this turns the right way, then remove this comment (negate as needed)
-       else // Z
-               this.avelocity = '0 1 0' * this.speed;
-
-       this.pos1 = this.avelocity;
-
-       // do this after setting pos1, so we can safely reactivate the func_rotating
-       if(this.spawnflags & FUNC_ROTATING_STARTOFF)
-       {
-               this.avelocity = '0 0 0';
-               this.active = ACTIVE_NOT;
-       }
-       else
-               this.active = ACTIVE_ACTIVE;
-
-    if(this.dmg && (this.message == ""))
-        this.message = " was squished";
-    if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-
-
-    if(this.dmg && (!this.dmgtime))
-        this.dmgtime = 0.25;
-
-    this.dmgtime2 = time;
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-       // no EF_LOWPRECISION here, as rounding angles is bad
-
-    setblocked(this, generic_plat_blocked);
-
-       // wait for targets to spawn
-       this.nextthink = this.ltime + 999999999;
-       setthink(this, SUB_NullThink); // for PushMove
-
-       this.reset = func_rotating_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/func/rotating.qh b/qcsrc/common/triggers/func/rotating.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/stardust.qc b/qcsrc/common/triggers/func/stardust.qc
deleted file mode 100644 (file)
index 9c2fba8..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "stardust.qh"
-#ifdef SVQC
-spawnfunc(func_stardust)
-{
-       this.effects = EF_STARDUST;
-
-       CSQCMODEL_AUTOINIT(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/func/stardust.qh b/qcsrc/common/triggers/func/stardust.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/func/train.qc b/qcsrc/common/triggers/func/train.qc
deleted file mode 100644 (file)
index ead0867..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-#include "train.qh"
-.float train_wait_turning;
-.entity future_target;
-void train_next(entity this);
-#ifdef SVQC
-void train_use(entity this, entity actor, entity trigger);
-#endif
-void train_wait(entity this)
-{
-       SUB_UseTargets(this.enemy, NULL, NULL);
-       this.enemy = NULL;
-
-       // if turning is enabled, the train will turn toward the next point while waiting
-       if(this.platmovetype_turn && !this.train_wait_turning)
-       {
-               entity targ, cp;
-               vector ang;
-               targ = this.future_target;
-               if((this.spawnflags & 1) && targ.curvetarget)
-                       cp = find(NULL, targetname, targ.curvetarget);
-               else
-                       cp = NULL;
-
-               if(cp) // bezier curves movement
-                       ang = cp.origin - (this.origin - this.view_ofs); // use the origin of the control point of the next path_corner
-               else // linear movement
-                       ang = targ.origin - (this.origin - this.view_ofs); // use the origin of the next path_corner
-               ang = vectoangles(ang);
-               ang_x = -ang_x; // flip up / down orientation
-
-               if(this.wait > 0) // slow turning
-                       SUB_CalcAngleMove(this, ang, TSPEED_TIME, this.ltime - time + this.wait, train_wait);
-               else // instant turning
-                       SUB_CalcAngleMove(this, ang, TSPEED_TIME, 0.0000001, train_wait);
-               this.train_wait_turning = true;
-               return;
-       }
-
-#ifdef SVQC
-       if(this.noise != "")
-               stopsoundto(MSG_BROADCAST, this, CH_TRIGGER_SINGLE); // send this as unreliable only, as the train will resume operation shortly anyway
-#endif
-
-#ifdef SVQC
-       entity tg = this.future_target;
-       if(tg.spawnflags & 4)
-       {
-               this.use = train_use;
-               setthink(this, func_null);
-               this.nextthink = 0;
-       }
-       else
-#endif
-            if(this.wait < 0 || this.train_wait_turning) // no waiting or we already waited while turning
-       {
-               this.train_wait_turning = false;
-               train_next(this);
-       }
-       else
-       {
-               setthink(this, train_next);
-               this.nextthink = this.ltime + this.wait;
-       }
-}
-
-entity train_next_find(entity this)
-{
-       if(this.target_random)
-       {
-               RandomSelection_Init();
-               for(entity t = NULL; (t = find(t, targetname, this.target));)
-               {
-                       RandomSelection_AddEnt(t, 1, 0);
-               }
-               return RandomSelection_chosen_ent;
-       }
-       else
-       {
-               return find(NULL, targetname, this.target);
-       }
-}
-
-void train_next(entity this)
-{
-       entity targ = NULL, cp = NULL;
-       vector cp_org = '0 0 0';
-
-       targ = this.future_target;
-
-       this.target = targ.target;
-       this.target_random = targ.target_random;
-       this.future_target = train_next_find(targ);
-
-       if (this.spawnflags & 1)
-       {
-               if(targ.curvetarget)
-               {
-                       cp = find(NULL, targetname, targ.curvetarget); // get its second target (the control point)
-                       cp_org = cp.origin - this.view_ofs; // no control point found, assume a straight line to the destination
-               }
-       }
-       if (this.target == "")
-               objerror(this, "train_next: no next target");
-       this.wait = targ.wait;
-       if (!this.wait)
-               this.wait = 0.1;
-
-       if(targ.platmovetype)
-       {
-               // this path_corner contains a movetype overrider, apply it
-               this.platmovetype_start = targ.platmovetype_start;
-               this.platmovetype_end = targ.platmovetype_end;
-       }
-       else
-       {
-               // this path_corner doesn't contain a movetype overrider, use the train's defaults
-               this.platmovetype_start = this.platmovetype_start_default;
-               this.platmovetype_end = this.platmovetype_end_default;
-       }
-
-       if (targ.speed)
-       {
-               if (cp)
-                       SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
-               else
-                       SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, targ.speed, train_wait);
-       }
-       else
-       {
-               if (cp)
-                       SUB_CalcMove_Bezier(this, cp_org, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
-               else
-                       SUB_CalcMove(this, targ.origin - this.view_ofs, TSPEED_LINEAR, this.speed, train_wait);
-       }
-
-       if(this.noise != "")
-               _sound(this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_TRAIN)
-
-#ifdef SVQC
-float train_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRAIN);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               WriteString(MSG_ENTITY, this.platmovetype);
-               WriteByte(MSG_ENTITY, this.platmovetype_turn);
-               WriteByte(MSG_ENTITY, this.spawnflags);
-
-               WriteString(MSG_ENTITY, this.model);
-
-               trigger_common_write(this, true);
-
-               WriteString(MSG_ENTITY, this.curvetarget);
-
-               WriteVector(MSG_ENTITY, this.pos1);
-               WriteVector(MSG_ENTITY, this.pos2);
-
-               WriteVector(MSG_ENTITY, this.size);
-
-               WriteVector(MSG_ENTITY, this.view_ofs);
-
-               WriteAngle(MSG_ENTITY, this.mangle_x);
-               WriteAngle(MSG_ENTITY, this.mangle_y);
-               WriteAngle(MSG_ENTITY, this.mangle_z);
-
-               WriteShort(MSG_ENTITY, this.speed);
-               WriteShort(MSG_ENTITY, this.height);
-               WriteByte(MSG_ENTITY, this.lip);
-               WriteByte(MSG_ENTITY, this.state);
-               WriteByte(MSG_ENTITY, this.wait);
-
-               WriteShort(MSG_ENTITY, this.dmg);
-               WriteByte(MSG_ENTITY, this.dmgtime);
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               // used on client
-       }
-
-       return true;
-}
-
-void train_link(entity this)
-{
-       //Net_LinkEntity(this, 0, false, train_send);
-}
-
-void train_use(entity this, entity actor, entity trigger)
-{
-       this.nextthink = this.ltime + 1;
-       setthink(this, train_next);
-       this.use = func_null; // not again
-       if(trigger.target2 && trigger.target2 != "")
-               this.future_target = find(NULL, targetname, trigger.target2);
-}
-
-void func_train_find(entity this)
-{
-       entity targ = train_next_find(this);
-       this.target = targ.target;
-       this.target_random = targ.target_random;
-       // save the future target for later
-       this.future_target = train_next_find(targ);
-       if (this.target == "")
-               objerror(this, "func_train_find: no next target");
-       setorigin(this, targ.origin - this.view_ofs);
-
-       if(!(this.spawnflags & 4))
-       {
-               this.nextthink = this.ltime + 1;
-               setthink(this, train_next);
-       }
-
-       train_link(this);
-}
-
-#endif
-
-/*QUAKED spawnfunc_func_train (0 .5 .8) ?
-Ridable platform, targets spawnfunc_path_corner path to follow.
-speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
-target : targetname of first spawnfunc_path_corner (starts here)
-*/
-#ifdef SVQC
-spawnfunc(func_train)
-{
-       if (this.noise != "")
-               precache_sound(this.noise);
-
-       if (this.target == "")
-               objerror(this, "func_train without a target");
-       if (!this.speed)
-               this.speed = 100;
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-       this.effects |= EF_LOWPRECISION;
-
-       if(this.spawnflags & 4)
-               this.use = train_use;
-
-       if (this.spawnflags & 2)
-       {
-               this.platmovetype_turn = true;
-               this.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
-       }
-       else
-               this.view_ofs = this.mins;
-
-       // wait for targets to spawn
-       InitializeEntity(this, func_train_find, INITPRIO_FINDTARGET);
-
-       setblocked(this, generic_plat_blocked);
-       if(this.dmg && (this.message == ""))
-               this.message = " was squished";
-    if(this.dmg && (this.message2 == ""))
-               this.message2 = "was squished by";
-       if(this.dmg && (!this.dmgtime))
-               this.dmgtime = 0.25;
-       this.dmgtime2 = time;
-
-       if(!set_platmovetype(this, this.platmovetype))
-               return;
-       this.platmovetype_start_default = this.platmovetype_start;
-       this.platmovetype_end_default = this.platmovetype_end;
-
-       // TODO make a reset function for this one
-}
-#elif defined(CSQC)
-void train_draw(entity this)
-{
-       //Movetype_Physics_NoMatchServer();
-       Movetype_Physics_MatchServer(this, autocvar_cl_projectiles_sloppy);
-}
-
-NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
-{
-       float sf = ReadByte();
-
-       if(sf & SF_TRIGGER_INIT)
-       {
-               this.platmovetype = strzone(ReadString());
-               this.platmovetype_turn = ReadByte();
-               this.spawnflags = ReadByte();
-
-               this.model = strzone(ReadString());
-               _setmodel(this, this.model);
-
-               trigger_common_read(this, true);
-
-               this.curvetarget = strzone(ReadString());
-
-               this.pos1 = ReadVector();
-               this.pos2 = ReadVector();
-
-               this.size = ReadVector();
-
-               this.view_ofs = ReadVector();
-
-               this.mangle_x = ReadAngle();
-               this.mangle_y = ReadAngle();
-               this.mangle_z = ReadAngle();
-
-               this.speed = ReadShort();
-               this.height = ReadShort();
-               this.lip = ReadByte();
-               this.state = ReadByte();
-               this.wait = ReadByte();
-
-               this.dmg = ReadShort();
-               this.dmgtime = ReadByte();
-
-               this.classname = "func_train";
-               this.solid = SOLID_BSP;
-               set_movetype(this, MOVETYPE_PUSH);
-               this.drawmask = MASK_NORMAL;
-               this.draw = train_draw;
-               if (isnew) IL_PUSH(g_drawables, this);
-               this.entremove = trigger_remove_generic;
-
-               if(set_platmovetype(this, this.platmovetype))
-               {
-                       this.platmovetype_start_default = this.platmovetype_start;
-                       this.platmovetype_end_default = this.platmovetype_end;
-               }
-
-               // everything is set up by the time the train is linked, we shouldn't need this
-               //func_train_find();
-
-               // but we will need these
-               train_next(this);
-
-               set_movetype(this, MOVETYPE_PUSH);
-               this.move_time = time;
-       }
-
-       if(sf & SF_TRIGGER_RESET)
-       {
-               // TODO: make a reset function for trains
-       }
-
-       return true;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/func/train.qh b/qcsrc/common/triggers/func/train.qh
deleted file mode 100644 (file)
index 8b6f7c0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#ifdef CSQC
-.float dmgtime;
-#endif
diff --git a/qcsrc/common/triggers/func/vectormamamam.qc b/qcsrc/common/triggers/func/vectormamamam.qc
deleted file mode 100644 (file)
index 951a740..0000000
+++ /dev/null
@@ -1,159 +0,0 @@
-#include "vectormamamam.qh"
-#ifdef SVQC
-// reusing some fields havocbots declared
-.entity wp00, wp01, wp02, wp03;
-
-.float targetfactor, target2factor, target3factor, target4factor;
-.vector targetnormal, target2normal, target3normal, target4normal;
-
-vector func_vectormamamam_origin(entity o, float t)
-{
-       vector v, p;
-       float f;
-       entity e;
-
-       f = o.spawnflags;
-       v = '0 0 0';
-
-       e = o.wp00;
-       if(e)
-       {
-               p = e.origin + t * e.velocity;
-               if(f & 1)
-                       v = v + (p * o.targetnormal) * o.targetnormal * o.targetfactor;
-               else
-                       v = v + (p - (p * o.targetnormal) * o.targetnormal) * o.targetfactor;
-       }
-
-       e = o.wp01;
-       if(e)
-       {
-               p = e.origin + t * e.velocity;
-               if(f & 2)
-                       v = v + (p * o.target2normal) * o.target2normal * o.target2factor;
-               else
-                       v = v + (p - (p * o.target2normal) * o.target2normal) * o.target2factor;
-       }
-
-       e = o.wp02;
-       if(e)
-       {
-               p = e.origin + t * e.velocity;
-               if(f & 4)
-                       v = v + (p * o.target3normal) * o.target3normal * o.target3factor;
-               else
-                       v = v + (p - (p * o.target3normal) * o.target3normal) * o.target3factor;
-       }
-
-       e = o.wp03;
-       if(e)
-       {
-               p = e.origin + t * e.velocity;
-               if(f & 8)
-                       v = v + (p * o.target4normal) * o.target4normal * o.target4factor;
-               else
-                       v = v + (p - (p * o.target4normal) * o.target4normal) * o.target4factor;
-       }
-
-       return v;
-}
-
-void func_vectormamamam_controller_think(entity this)
-{
-       this.nextthink = time + 0.1;
-
-       if(this.owner.active != ACTIVE_ACTIVE)
-       {
-               this.owner.velocity = '0 0 0';
-               return;
-       }
-
-       if(this.owner.classname == "func_vectormamamam") // don't brake stuff if the func_vectormamamam was killtarget'ed
-               this.owner.velocity = (this.owner.destvec + func_vectormamamam_origin(this.owner, 0.1) - this.owner.origin) * 10;
-}
-
-void func_vectormamamam_findtarget(entity this)
-{
-       if(this.target != "")
-               this.wp00 = find(NULL, targetname, this.target);
-
-       if(this.target2 != "")
-               this.wp01 = find(NULL, targetname, this.target2);
-
-       if(this.target3 != "")
-               this.wp02 = find(NULL, targetname, this.target3);
-
-       if(this.target4 != "")
-               this.wp03 = find(NULL, targetname, this.target4);
-
-       if(!this.wp00 && !this.wp01 && !this.wp02 && !this.wp03)
-               objerror(this, "No reference entity found, so there is nothing to move. Aborting.");
-
-       this.destvec = this.origin - func_vectormamamam_origin(this, 0);
-
-       entity controller;
-       controller = new(func_vectormamamam_controller);
-       controller.owner = this;
-       controller.nextthink = time + 1;
-       setthink(controller, func_vectormamamam_controller_think);
-}
-
-spawnfunc(func_vectormamamam)
-{
-       if (this.noise != "")
-       {
-               precache_sound(this.noise);
-               soundto(MSG_INIT, this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_IDLE);
-       }
-
-       if(!this.targetfactor)
-               this.targetfactor = 1;
-
-       if(!this.target2factor)
-               this.target2factor = 1;
-
-       if(!this.target3factor)
-               this.target3factor = 1;
-
-       if(!this.target4factor)
-               this.target4factor = 1;
-
-       if(this.targetnormal)
-               this.targetnormal = normalize(this.targetnormal);
-
-       if(this.target2normal)
-               this.target2normal = normalize(this.target2normal);
-
-       if(this.target3normal)
-               this.target3normal = normalize(this.target3normal);
-
-       if(this.target4normal)
-               this.target4normal = normalize(this.target4normal);
-
-       setblocked(this, generic_plat_blocked);
-       if(this.dmg && (this.message == ""))
-               this.message = " was squished";
-    if(this.dmg && (this.message == ""))
-               this.message2 = "was squished by";
-       if(this.dmg && (!this.dmgtime))
-               this.dmgtime = 0.25;
-       this.dmgtime2 = time;
-
-       if(this.netname == "")
-               this.netname = "1 0 0 0 1";
-
-       if (!InitMovingBrushTrigger(this))
-               return;
-
-       // wait for targets to spawn
-       this.nextthink = this.ltime + 999999999;
-       setthink(this, SUB_NullThink); // for PushMove
-
-       // Savage: Reduce bandwith, critical on e.g. nexdm02
-       this.effects |= EF_LOWPRECISION;
-
-       this.active = ACTIVE_ACTIVE;
-
-       InitializeEntity(this, func_vectormamamam_findtarget, INITPRIO_FINDTARGET);
-}
-#endif
diff --git a/qcsrc/common/triggers/func/vectormamamam.qh b/qcsrc/common/triggers/func/vectormamamam.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/include.qc b/qcsrc/common/triggers/include.qc
deleted file mode 100644 (file)
index 59da1f2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "include.qh"
-
-// some required common stuff
-#include "subs.qc"
-#include "triggers.qc"
-#include "platforms.qc"
-#include "teleporters.qc"
-
-// func
-#include "func/include.qc"
-
-// misc
-#include "misc/include.qc"
-
-// target
-#include "target/include.qc"
-
-// trigger
-#include "trigger/include.qc"
-
diff --git a/qcsrc/common/triggers/include.qh b/qcsrc/common/triggers/include.qh
deleted file mode 100644 (file)
index 87c07c1..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-
-// some required common stuff
-#ifdef SVQC
-       #include <server/item_key.qh>
-#endif
-#include "triggers.qh"
-#include "subs.qh"
-#include "platforms.qh"
-#include "teleporters.qh"
-
-// func
-#include "func/include.qh"
-
-// target
-#include "target/include.qh"
-
-// trigger
-#include "trigger/include.qh"
diff --git a/qcsrc/common/triggers/misc/_mod.inc b/qcsrc/common/triggers/misc/_mod.inc
deleted file mode 100644 (file)
index 4a8ec06..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/misc/corner.qc>
-#include <common/triggers/misc/follow.qc>
-#include <common/triggers/misc/include.qc>
-#include <common/triggers/misc/laser.qc>
-#include <common/triggers/misc/teleport_dest.qc>
diff --git a/qcsrc/common/triggers/misc/_mod.qh b/qcsrc/common/triggers/misc/_mod.qh
deleted file mode 100644 (file)
index 98615cc..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/misc/corner.qh>
-#include <common/triggers/misc/follow.qh>
-#include <common/triggers/misc/include.qh>
-#include <common/triggers/misc/laser.qh>
-#include <common/triggers/misc/teleport_dest.qh>
diff --git a/qcsrc/common/triggers/misc/corner.qc b/qcsrc/common/triggers/misc/corner.qc
deleted file mode 100644 (file)
index 6c90933..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-#include "corner.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_CORNER)
-
-#ifdef SVQC
-bool corner_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_CORNER);
-
-       WriteString(MSG_ENTITY, this.platmovetype);
-
-       WriteVector(MSG_ENTITY, this.origin);
-
-       WriteString(MSG_ENTITY, this.target);
-       WriteString(MSG_ENTITY, this.target2);
-       WriteString(MSG_ENTITY, this.target3);
-       WriteString(MSG_ENTITY, this.target4);
-       WriteString(MSG_ENTITY, this.targetname);
-       WriteByte(MSG_ENTITY, this.target_random);
-
-       WriteByte(MSG_ENTITY, this.wait);
-
-       return true;
-}
-
-void corner_link(entity this)
-{
-       //Net_LinkEntity(this, false, 0, corner_send);
-}
-
-spawnfunc(path_corner)
-{
-       // setup values for overriding train movement
-       // if a second value does not exist, both start and end speeds are the single value specified
-       set_platmovetype(this, this.platmovetype);
-
-       corner_link(this);
-}
-#elif defined(CSQC)
-
-void corner_remove(entity this)
-{
-       if(this.target) { strunzone(this.target); }
-       this.target = string_null;
-
-       if(this.target2) { strunzone(this.target2); }
-       this.target2 = string_null;
-
-       if(this.target3) { strunzone(this.target3); }
-       this.target3 = string_null;
-
-       if(this.target4) { strunzone(this.target4); }
-       this.target4 = string_null;
-
-       if(this.targetname) { strunzone(this.targetname); }
-       this.targetname = string_null;
-
-       if(this.platmovetype) { strunzone(this.platmovetype); }
-       this.platmovetype = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_CORNER, bool isnew)
-{
-       this.platmovetype = strzone(ReadString());
-
-       this.origin = ReadVector();
-       setorigin(this, this.origin);
-
-       this.target = strzone(ReadString());
-       this.target2 = strzone(ReadString());
-       this.target3 = strzone(ReadString());
-       this.target4 = strzone(ReadString());
-       this.targetname = strzone(ReadString());
-       this.target_random = ReadByte();
-
-       this.wait = ReadByte();
-
-       return = true;
-
-       this.classname = "path_corner";
-       this.drawmask = MASK_NORMAL;
-       this.entremove = corner_remove;
-
-       set_platmovetype(this, this.platmovetype);
-}
-
-#endif
diff --git a/qcsrc/common/triggers/misc/corner.qh b/qcsrc/common/triggers/misc/corner.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/misc/follow.qc b/qcsrc/common/triggers/misc/follow.qc
deleted file mode 100644 (file)
index 63db2c1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#include "follow.qh"
-// the way this entity works makes it no use to CSQC, as it removes itself instantly
-
-#ifdef SVQC
-void follow_init(entity this)
-{
-       entity src, dst;
-       src = NULL;
-       dst = NULL;
-       if(this.killtarget != "")
-               src = find(NULL, targetname, this.killtarget);
-       if(this.target != "")
-               dst = find(NULL, targetname, this.target);
-
-       if(!src && !dst)
-       {
-               objerror(this, "follow: could not find target/killtarget");
-               return;
-       }
-
-       if(this.jointtype)
-       {
-               // already done :P entity must stay
-               this.aiment = src;
-               this.enemy = dst;
-       }
-       else if(!src || !dst)
-       {
-               objerror(this, "follow: could not find target/killtarget");
-               return;
-       }
-       else if(this.spawnflags & 1)
-       {
-               // attach
-               if(this.spawnflags & 2)
-               {
-                       setattachment(dst, src, this.message);
-               }
-               else
-               {
-                       attach_sameorigin(dst, src, this.message);
-               }
-
-               dst.solid = SOLID_NOT; // solid doesn't work with attachment
-               delete(this);
-       }
-       else
-       {
-               if(this.spawnflags & 2)
-               {
-                       set_movetype(dst, MOVETYPE_FOLLOW);
-                       dst.aiment = src;
-                       // dst.punchangle = '0 0 0'; // keep unchanged
-                       dst.view_ofs = dst.origin;
-                       dst.v_angle = dst.angles;
-               }
-               else
-               {
-                       follow_sameorigin(dst, src);
-               }
-
-               delete(this);
-       }
-}
-
-spawnfunc(misc_follow)
-{
-       InitializeEntity(this, follow_init, INITPRIO_FINDTARGET);
-}
-#endif
diff --git a/qcsrc/common/triggers/misc/follow.qh b/qcsrc/common/triggers/misc/follow.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/misc/include.qc b/qcsrc/common/triggers/misc/include.qc
deleted file mode 100644 (file)
index bbe5ce0..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "include.qh"
-#include "corner.qc"
-#include "follow.qc"
-#include "laser.qc"
-#include "teleport_dest.qc"
diff --git a/qcsrc/common/triggers/misc/include.qh b/qcsrc/common/triggers/misc/include.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/misc/laser.qc b/qcsrc/common/triggers/misc/laser.qc
deleted file mode 100644 (file)
index 3d5ef42..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-#include "laser.qh"
-#if defined(CSQC)
-       #include <lib/csqcmodel/interpolate.qh>
-       #include <client/main.qh>
-       #include <lib/csqcmodel/cl_model.qh>
-#elif defined(MENUQC)
-#elif defined(SVQC)
-#endif
-
-REGISTER_NET_LINKED(ENT_CLIENT_LASER)
-
-#ifdef SVQC
-.float modelscale;
-void misc_laser_aim(entity this)
-{
-       vector a;
-       if(this.enemy)
-       {
-               if(this.spawnflags & 2)
-               {
-                       if(this.enemy.origin != this.mangle)
-                       {
-                               this.mangle = this.enemy.origin;
-                               this.SendFlags |= 2;
-                       }
-               }
-               else
-               {
-                       a = vectoangles(this.enemy.origin - this.origin);
-                       a_x = -a_x;
-                       if(a != this.mangle)
-                       {
-                               this.mangle = a;
-                               this.SendFlags |= 2;
-                       }
-               }
-       }
-       else
-       {
-               if(this.angles != this.mangle)
-               {
-                       this.mangle = this.angles;
-                       this.SendFlags |= 2;
-               }
-       }
-       if(this.origin != this.oldorigin)
-       {
-               this.SendFlags |= 1;
-               this.oldorigin = this.origin;
-       }
-}
-
-void misc_laser_init(entity this)
-{
-       if(this.target != "")
-               this.enemy = find(NULL, targetname, this.target);
-}
-
-.entity pusher;
-void misc_laser_think(entity this)
-{
-       vector o;
-       entity hitent;
-       vector hitloc;
-
-       this.nextthink = time;
-
-       if(!this.state)
-               return;
-
-       misc_laser_aim(this);
-
-       if(this.enemy)
-       {
-               o = this.enemy.origin;
-               if (!(this.spawnflags & 2))
-                       o = this.origin + normalize(o - this.origin) * 32768;
-       }
-       else
-       {
-               makevectors(this.mangle);
-               o = this.origin + v_forward * 32768;
-       }
-
-       if(this.dmg || this.enemy.target != "")
-       {
-               traceline(this.origin, o, MOVE_NORMAL, this);
-       }
-       hitent = trace_ent;
-       hitloc = trace_endpos;
-
-       if(this.enemy.target != "") // DETECTOR laser
-       {
-               if(trace_ent.iscreature)
-               {
-                       this.pusher = hitent;
-                       if(!this.count)
-                       {
-                               this.count = 1;
-
-                               SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
-                       }
-               }
-               else
-               {
-                       if(this.count)
-                       {
-                               this.count = 0;
-
-                               SUB_UseTargets(this.enemy, this.enemy.pusher, NULL);
-                       }
-               }
-       }
-
-       if(this.dmg)
-       {
-               if(this.team)
-                       if(((this.spawnflags & 8) == 0) == (this.team != hitent.team))
-                               return;
-               if(hitent.takedamage)
-                       Damage(hitent, this, this, ((this.dmg < 0) ? 100000 : (this.dmg * frametime)), DEATH_HURTTRIGGER.m_id, DMG_NOWEP, hitloc, '0 0 0');
-       }
-}
-
-bool laser_SendEntity(entity this, entity to, float fl)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
-       fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
-       if(this.spawnflags & 2)
-               fl |= 0x80;
-       if(this.alpha)
-               fl |= 0x40;
-       if(this.scale != 1 || this.modelscale != 1)
-               fl |= 0x20;
-       if(this.spawnflags & 4)
-               fl |= 0x10;
-       WriteByte(MSG_ENTITY, fl);
-       if(fl & 1)
-       {
-               WriteVector(MSG_ENTITY, this.origin);
-       }
-       if(fl & 8)
-       {
-               WriteByte(MSG_ENTITY, this.colormod_x * 255.0);
-               WriteByte(MSG_ENTITY, this.colormod_y * 255.0);
-               WriteByte(MSG_ENTITY, this.colormod_z * 255.0);
-               if(fl & 0x40)
-                       WriteByte(MSG_ENTITY, this.alpha * 255.0);
-               if(fl & 0x20)
-               {
-                       WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
-                       WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
-               }
-               if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
-                       WriteShort(MSG_ENTITY, this.cnt + 1);
-       }
-       if(fl & 2)
-       {
-               if(fl & 0x80)
-               {
-                       WriteVector(MSG_ENTITY, this.enemy.origin);
-               }
-               else
-               {
-                       WriteAngle(MSG_ENTITY, this.mangle_x);
-                       WriteAngle(MSG_ENTITY, this.mangle_y);
-               }
-       }
-       if(fl & 4)
-               WriteByte(MSG_ENTITY, this.state);
-       return 1;
-}
-
-/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
-Any object touching the beam will be hurt
-Keys:
-"target"
- spawnfunc_target_position where the laser ends
-"mdl"
- name of beam end effect to use
-"colormod"
- color of the beam (default: red)
-"dmg"
- damage per second (-1 for a laser that kills immediately)
-*/
-void laser_use(entity this, entity actor, entity trigger)
-{
-       this.state = !this.state;
-       this.SendFlags |= 4;
-       misc_laser_aim(this);
-}
-
-void laser_reset(entity this)
-{
-       if(this.spawnflags & 1)
-               this.state = 1;
-       else
-               this.state = 0;
-}
-
-spawnfunc(misc_laser)
-{
-       if(this.mdl)
-       {
-               if(this.mdl == "none")
-                       this.cnt = -1;
-               else
-               {
-                       this.cnt = _particleeffectnum(this.mdl);
-                       if(this.cnt < 0 && this.dmg)
-                this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
-               }
-       }
-       else if(!this.cnt)
-       {
-               if(this.dmg)
-                       this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
-               else
-                       this.cnt = -1;
-       }
-       if(this.cnt < 0)
-               this.cnt = -1;
-
-       if(this.colormod == '0 0 0')
-               if(!this.alpha)
-                       this.colormod = '1 0 0';
-       if(this.message == "") this.message = "saw the light";
-       if (this.message2 == "") this.message2 = "was pushed into a laser by";
-       if(!this.scale) this.scale = 1;
-       if(!this.modelscale) this.modelscale = 1;
-       else if(this.modelscale < 0) this.modelscale = 0;
-       setthink(this, misc_laser_think);
-       this.nextthink = time;
-       InitializeEntity(this, misc_laser_init, INITPRIO_FINDTARGET);
-
-       this.mangle = this.angles;
-
-       Net_LinkEntity(this, false, 0, laser_SendEntity);
-
-       IFTARGETED
-       {
-               this.reset = laser_reset;
-               this.reset(this);
-               this.use = laser_use;
-       }
-       else
-               this.state = 1;
-}
-#elif defined(CSQC)
-
-// a laser goes from origin in direction angles
-// it has color 'colormod'
-// and stops when something is in the way
-entityclass(Laser);
-class(Laser) .int cnt; // end effect
-class(Laser) .vector colormod;
-class(Laser) .int state; // on-off
-class(Laser) .int count; // flags for the laser
-class(Laser) .vector velocity;
-class(Laser) .float alpha;
-class(Laser) .float scale; // scaling factor of the thickness
-class(Laser) .float modelscale; // scaling factor of the dlight
-
-void Draw_Laser(entity this)
-{
-       if(!this.state)
-               return;
-       InterpolateOrigin_Do(this);
-       if(this.count & 0x80)
-       {
-               if(this.count & 0x10)
-               {
-                       trace_endpos = this.velocity;
-                       trace_dphitq3surfaceflags = 0;
-               }
-               else
-                       traceline(this.origin, this.velocity, 0, this);
-       }
-       else
-       {
-               if(this.count & 0x10)
-               {
-                       makevectors(this.angles);
-                       trace_endpos = this.origin + v_forward * 1048576;
-                       trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
-               }
-               else
-               {
-                       makevectors(this.angles);
-                       traceline(this.origin, this.origin + v_forward * 32768, 0, this);
-                       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
-                               trace_endpos = this.origin + v_forward * 1048576;
-               }
-       }
-       if(this.scale != 0)
-       {
-               if(this.alpha)
-               {
-                       Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, this.alpha, DRAWFLAG_NORMAL, view_origin);
-               }
-               else
-               {
-                       Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
-               }
-       }
-       if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
-       {
-               if(this.cnt >= 0)
-                       __pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
-               if(this.colormod != '0 0 0' && this.modelscale != 0)
-                       adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.colormod * 5);
-       }
-}
-
-NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
-{
-       InterpolateOrigin_Undo(this);
-
-       // 30 bytes, or 13 bytes for just moving
-       int f = ReadByte();
-       this.count = (f & 0xF0);
-
-       if(this.count & 0x80)
-               this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
-       else
-               this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
-
-       if(f & 1)
-       {
-               this.origin = ReadVector();
-               setorigin(this, this.origin);
-       }
-       if(f & 8)
-       {
-               this.colormod_x = ReadByte() / 255.0;
-               this.colormod_y = ReadByte() / 255.0;
-               this.colormod_z = ReadByte() / 255.0;
-               if(f & 0x40)
-                       this.alpha = ReadByte() / 255.0;
-               else
-                       this.alpha = 0;
-               this.scale = 2;
-               this.modelscale = 50;
-               if(f & 0x20)
-               {
-                       this.scale *= ReadByte() / 16.0; // beam radius
-                       this.modelscale *= ReadByte() / 16.0; // dlight radius
-               }
-               if((f & 0x80) || !(f & 0x10))
-                       this.cnt = ReadShort() - 1; // effect number
-               else
-                       this.cnt = 0;
-       }
-       if(f & 2)
-       {
-               if(f & 0x80)
-               {
-                       this.velocity = ReadVector();
-               }
-               else
-               {
-                       this.angles_x = ReadAngle();
-                       this.angles_y = ReadAngle();
-               }
-       }
-       if(f & 4)
-               this.state = ReadByte();
-
-       return = true;
-
-       InterpolateOrigin_Note(this);
-       this.draw = Draw_Laser;
-       if (isnew) IL_PUSH(g_drawables, this);
-}
-#endif
diff --git a/qcsrc/common/triggers/misc/laser.qh b/qcsrc/common/triggers/misc/laser.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/misc/teleport_dest.qc b/qcsrc/common/triggers/misc/teleport_dest.qc
deleted file mode 100644 (file)
index 40c7d46..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-#include "teleport_dest.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_TELEPORT_DEST)
-
-#ifdef SVQC
-
-bool teleport_dest_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TELEPORT_DEST);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & 1)
-       {
-               WriteByte(MSG_ENTITY, this.cnt);
-               WriteCoord(MSG_ENTITY, this.speed);
-               WriteString(MSG_ENTITY, this.targetname);
-               WriteVector(MSG_ENTITY, this.origin);
-
-               WriteAngle(MSG_ENTITY, this.mangle_x);
-               WriteAngle(MSG_ENTITY, this.mangle_y);
-               WriteAngle(MSG_ENTITY, this.mangle_z);
-       }
-
-       return true;
-}
-
-void teleport_dest_link(entity this)
-{
-       Net_LinkEntity(this, false, 0, teleport_dest_send);
-       this.SendFlags |= 1; // update
-}
-
-spawnfunc(info_teleport_destination)
-{
-       this.classname = "info_teleport_destination";
-
-       this.mangle = this.angles;
-       this.angles = '0 0 0';
-
-       //setorigin(this, this.origin + '0 0 27');      // To fix a mappers' habit as old as Quake
-       setorigin(this, this.origin);
-
-       IFTARGETED
-       {
-       }
-       else
-               objerror (this, "^3Teleport destination without a targetname");
-
-       teleport_dest_link(this);
-}
-
-spawnfunc(misc_teleporter_dest)
-{
-       spawnfunc_info_teleport_destination(this);
-}
-
-#elif defined(CSQC)
-
-void teleport_dest_remove(entity this)
-{
-       //if(this.classname)
-               //strunzone(this.classname);
-       //this.classname = string_null;
-
-       if(this.targetname)
-               strunzone(this.targetname);
-       this.targetname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TELEPORT_DEST, bool isnew)
-{
-       int sf = ReadByte();
-
-       if(sf & 1)
-       {
-               this.classname = "info_teleport_destination";
-               this.cnt = ReadByte();
-               this.speed = ReadCoord();
-               this.targetname = strzone(ReadString());
-               this.origin = ReadVector();
-
-               this.mangle_x = ReadAngle();
-               this.mangle_y = ReadAngle();
-               this.mangle_z = ReadAngle();
-
-               setorigin(this, this.origin);
-
-               this.drawmask = MASK_NORMAL;
-               this.entremove = teleport_dest_remove;
-       }
-
-       return = true;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/misc/teleport_dest.qh b/qcsrc/common/triggers/misc/teleport_dest.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/platforms.qc b/qcsrc/common/triggers/platforms.qc
deleted file mode 100644 (file)
index 8ea4827..0000000
+++ /dev/null
@@ -1,225 +0,0 @@
-#include "platforms.qh"
-void generic_plat_blocked(entity this, entity blocker)
-{
-#ifdef SVQC
-       if(this.dmg && blocker.takedamage != DAMAGE_NO)
-       {
-               if(this.dmgtime2 < time)
-               {
-                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-                       this.dmgtime2 = time + this.dmgtime;
-               }
-
-               // Gib dead/dying stuff
-               if(IS_DEAD(blocker))
-                       Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-       }
-#endif
-}
-
-void plat_spawn_inside_trigger(entity this)
-{
-       entity trigger;
-       vector tmin, tmax;
-
-       trigger = spawn();
-       settouch(trigger, plat_center_touch);
-       set_movetype(trigger, MOVETYPE_NONE);
-       trigger.solid = SOLID_TRIGGER;
-       trigger.enemy = this;
-
-       tmin = this.absmin + '25 25 0';
-       tmax = this.absmax - '25 25 -8';
-       tmin_z = tmax_z - (this.pos1_z - this.pos2_z + 8);
-       if (this.spawnflags & PLAT_LOW_TRIGGER)
-               tmax_z = tmin_z + 8;
-
-       if (this.size_x <= 50)
-       {
-               tmin_x = (this.mins_x + this.maxs_x) / 2;
-               tmax_x = tmin_x + 1;
-       }
-       if (this.size_y <= 50)
-       {
-               tmin_y = (this.mins_y + this.maxs_y) / 2;
-               tmax_y = tmin_y + 1;
-       }
-
-       if(tmin_x < tmax_x)
-               if(tmin_y < tmax_y)
-                       if(tmin_z < tmax_z)
-                       {
-                               setsize (trigger, tmin, tmax);
-                               return;
-                       }
-
-       // otherwise, something is fishy...
-       delete(trigger);
-       objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
-}
-
-void plat_hit_top(entity this)
-{
-       _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.state = 1;
-
-       setthink(this, plat_go_down);
-       this.nextthink = this.ltime + 3;
-}
-
-void plat_hit_bottom(entity this)
-{
-       _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-       this.state = 2;
-}
-
-void plat_go_down(entity this)
-{
-       _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
-       this.state = 3;
-       SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, plat_hit_bottom);
-}
-
-void plat_go_up(entity this)
-{
-       _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
-       this.state = 4;
-       SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, plat_hit_top);
-}
-
-void plat_center_touch(entity this, entity toucher)
-{
-#ifdef SVQC
-       if (!toucher.iscreature)
-               return;
-
-       if (toucher.health <= 0)
-               return;
-#elif defined(CSQC)
-       if (!IS_PLAYER(toucher))
-               return;
-       if(IS_DEAD(toucher))
-               return;
-#endif
-
-       if (this.enemy.state == 2) {
-               plat_go_up(this.enemy);
-       } else if (this.enemy.state == 1)
-               this.enemy.nextthink = this.enemy.ltime + 1;
-}
-
-void plat_outside_touch(entity this, entity toucher)
-{
-#ifdef SVQC
-       if (!toucher.iscreature)
-               return;
-
-       if (toucher.health <= 0)
-               return;
-#elif defined(CSQC)
-       if (!IS_PLAYER(toucher))
-               return;
-#endif
-
-       if (this.enemy.state == 1) {
-           entity e = this.enemy;
-               plat_go_down(e);
-    }
-}
-
-void plat_trigger_use(entity this, entity actor, entity trigger)
-{
-       if (getthink(this))
-               return;         // already activated
-       plat_go_down(this);
-}
-
-
-void plat_crush(entity this, entity blocker)
-{
-       if((this.spawnflags & 4) && (blocker.takedamage != DAMAGE_NO))
-       { // KIll Kill Kill!!
-#ifdef SVQC
-               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-       }
-       else
-       {
-#ifdef SVQC
-               if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
-               {   // Shall we bite?
-                       Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-                       // Gib dead/dying stuff
-                       if(IS_DEAD(blocker))
-                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-               }
-#endif
-
-               if (this.state == 4)
-                       plat_go_down (this);
-               else if (this.state == 3)
-                       plat_go_up (this);
-       // when in other states, then the plat_crush event came delayed after
-       // plat state already had changed
-       // this isn't a bug per se!
-       }
-}
-
-void plat_use(entity this, entity actor, entity trigger)
-{
-       this.use = func_null;
-       if (this.state != 4)
-               objerror (this, "plat_use: not in up state");
-       plat_go_down(this);
-}
-
-.string sound1, sound2;
-
-void plat_reset(entity this)
-{
-       IFTARGETED
-       {
-               setorigin(this, this.pos1);
-               this.state = 4;
-               this.use = plat_use;
-       }
-       else
-       {
-               setorigin(this, this.pos2);
-               this.state = 2;
-               this.use = plat_trigger_use;
-       }
-
-#ifdef SVQC
-       this.SendFlags |= SF_TRIGGER_RESET;
-#endif
-}
-
-.float platmovetype_start_default, platmovetype_end_default;
-bool set_platmovetype(entity e, string s)
-{
-       // sets platmovetype_start and platmovetype_end based on a string consisting of two values
-
-       int n = tokenize_console(s);
-       if(n > 0)
-               e.platmovetype_start = stof(argv(0));
-       else
-               e.platmovetype_start = 0;
-
-       if(n > 1)
-               e.platmovetype_end = stof(argv(1));
-       else
-               e.platmovetype_end = e.platmovetype_start;
-
-       if(n > 2)
-               if(argv(2) == "force")
-                       return true; // no checking, return immediately
-
-       if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
-       {
-               objerror(e, "Invalid platform move type; platform would go in reverse, which is not allowed.");
-               return false;
-       }
-
-       return true;
-}
diff --git a/qcsrc/common/triggers/platforms.qh b/qcsrc/common/triggers/platforms.qh
deleted file mode 100644 (file)
index c404674..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-.float dmgtime2;
-
-void plat_center_touch(entity this, entity toucher);
-void plat_outside_touch(entity this, entity toucher);
-void plat_trigger_use(entity this, entity actor, entity trigger);
-void plat_go_up(entity this);
-void plat_go_down(entity this);
-void plat_crush(entity this, entity blocker);
-const float PLAT_LOW_TRIGGER = 1;
-
-.float dmg;
diff --git a/qcsrc/common/triggers/subs.qc b/qcsrc/common/triggers/subs.qc
deleted file mode 100644 (file)
index 5b6182e..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-#include "subs.qh"
-void SUB_NullThink(entity this) { }
-
-void SUB_CalcMoveDone(entity this);
-void SUB_CalcAngleMoveDone(entity this);
-
-/*
-==================
-SUB_Friction
-
-Applies some friction to this
-==================
-*/
-.float friction;
-void SUB_Friction (entity this)
-{
-       this.nextthink = time;
-       if(IS_ONGROUND(this))
-               this.velocity = this.velocity * (1 - frametime * this.friction);
-}
-
-/*
-==================
-SUB_VanishOrRemove
-
-Makes client invisible or removes non-client
-==================
-*/
-void SUB_VanishOrRemove (entity ent)
-{
-       if (IS_CLIENT(ent))
-       {
-               // vanish
-               ent.alpha = -1;
-               ent.effects = 0;
-#ifdef SVQC
-               ent.glow_size = 0;
-               ent.pflags = 0;
-#endif
-       }
-       else
-       {
-               // remove
-               delete(ent);
-       }
-}
-
-void SUB_SetFade_Think (entity this)
-{
-       if(this.alpha == 0)
-               this.alpha = 1;
-       setthink(this, SUB_SetFade_Think);
-       this.nextthink = time;
-       this.alpha -= frametime * this.fade_rate;
-       if (this.alpha < 0.01)
-               SUB_VanishOrRemove(this);
-       else
-               this.nextthink = time;
-}
-
-/*
-==================
-SUB_SetFade
-
-Fade 'ent' out when time >= 'when'
-==================
-*/
-void SUB_SetFade (entity ent, float when, float fading_time)
-{
-       ent.fade_rate = 1/fading_time;
-       setthink(ent, SUB_SetFade_Think);
-       ent.nextthink = when;
-}
-
-/*
-=============
-SUB_CalcMove
-
-calculate this.velocity and this.nextthink to reach dest from
-this.origin traveling at speed
-===============
-*/
-void SUB_CalcMoveDone(entity this)
-{
-       // After moving, set origin to exact final destination
-
-       setorigin (this, this.finaldest);
-       this.velocity = '0 0 0';
-       this.nextthink = -1;
-       if (this.think1 && this.think1 != SUB_CalcMoveDone)
-               this.think1 (this);
-}
-
-.float platmovetype_turn;
-void SUB_CalcMove_controller_think (entity this)
-{
-       float traveltime;
-       float phasepos;
-       float nexttick;
-       vector delta;
-       vector delta2;
-       vector veloc;
-       vector angloc;
-       vector nextpos;
-       delta = this.destvec;
-       delta2 = this.destvec2;
-       if(time < this.animstate_endtime)
-       {
-               nexttick = time + PHYS_INPUT_FRAMETIME;
-
-               traveltime = this.animstate_endtime - this.animstate_starttime;
-               phasepos = (nexttick - this.animstate_starttime) / traveltime; // range: [0, 1]
-               phasepos = cubic_speedfunc(this.platmovetype_start, this.platmovetype_end, phasepos);
-               nextpos = this.origin + (delta * phasepos) + (delta2 * phasepos * phasepos);
-               // derivative: delta + 2 * delta2 * phasepos (e.g. for angle positioning)
-
-               if(this.owner.platmovetype_turn)
-               {
-                       vector destangle;
-                       destangle = delta + 2 * delta2 * phasepos;
-                       destangle = vectoangles(destangle);
-                       destangle_x = -destangle_x; // flip up / down orientation
-
-                       // take the shortest distance for the angles
-                       vector v = this.owner.angles;
-                       v.x -= 360 * floor((v.x - destangle_x) / 360 + 0.5);
-                       v.y -= 360 * floor((v.y - destangle_y) / 360 + 0.5);
-                       v.z -= 360 * floor((v.z - destangle_z) / 360 + 0.5);
-                       this.owner.angles = v;
-                       angloc = destangle - this.owner.angles;
-                       angloc = angloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
-                       this.owner.avelocity = angloc;
-               }
-               if(nexttick < this.animstate_endtime)
-                       veloc = nextpos - this.owner.origin;
-               else
-                       veloc = this.finaldest - this.owner.origin;
-               veloc = veloc * (1 / PHYS_INPUT_FRAMETIME); // so it arrives for the next frame
-
-               this.owner.velocity = veloc;
-               this.nextthink = nexttick;
-       }
-       else
-       {
-               // derivative: delta + 2 * delta2 (e.g. for angle positioning)
-               entity own = this.owner;
-               setthink(own, this.think1);
-               delete(this);
-               getthink(own)(own);
-       }
-}
-
-void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector destin)
-{
-       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
-       // 2 * control * t - 2 * control * t * t + destin * t * t
-       // 2 * control * t + (destin - 2 * control) * t * t
-
-       setorigin(controller, org);
-       control -= org;
-       destin -= org;
-
-       controller.destvec = 2 * control; // control point
-       controller.destvec2 = destin - 2 * control; // quadratic part required to reach end point
-       // also: initial d/dphasepos origin = 2 * control, final speed = 2 * (destin - control)
-}
-
-void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector destin)
-{
-       // 0 * (1-t) * (1-t) + 2 * control * t * (1-t) + destin * t * t
-       // 2 * control * t - 2 * control * t * t + destin * t * t
-       // 2 * control * t + (destin - 2 * control) * t * t
-
-       setorigin(controller, org);
-       destin -= org;
-
-       controller.destvec = destin; // end point
-       controller.destvec2 = '0 0 0';
-}
-
-float TSPEED_TIME = -1;
-float TSPEED_LINEAR = 0;
-float TSPEED_START = 1;
-float TSPEED_END = 2;
-// TODO average too?
-
-void SUB_CalcMove_Bezier (entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
-{
-       float   traveltime;
-       entity controller;
-
-       if (!tspeed)
-               objerror (this, "No speed is defined!");
-
-       this.think1 = func;
-       this.finaldest = tdest;
-       setthink(this, SUB_CalcMoveDone);
-
-       switch(tspeedtype)
-       {
-               default:
-               case TSPEED_START:
-                       traveltime = 2 * vlen(tcontrol - this.origin) / tspeed;
-                       break;
-               case TSPEED_END:
-                       traveltime = 2 * vlen(tcontrol - tdest)       / tspeed;
-                       break;
-               case TSPEED_LINEAR:
-                       traveltime = vlen(tdest - this.origin)        / tspeed;
-                       break;
-               case TSPEED_TIME:
-                       traveltime = tspeed;
-                       break;
-       }
-
-       if (traveltime < 0.1) // useless anim
-       {
-               this.velocity = '0 0 0';
-               this.nextthink = this.ltime + 0.1;
-               return;
-       }
-
-       controller = new(SUB_CalcMove_controller);
-       controller.owner = this;
-       controller.platmovetype = this.platmovetype;
-       controller.platmovetype_start = this.platmovetype_start;
-       controller.platmovetype_end = this.platmovetype_end;
-       SUB_CalcMove_controller_setbezier(controller, this.origin, tcontrol, tdest);
-       controller.finaldest = (tdest + '0 0 0.125'); // where do we want to end? Offset to overshoot a bit.
-       controller.animstate_starttime = time;
-       controller.animstate_endtime = time + traveltime;
-       setthink(controller, SUB_CalcMove_controller_think);
-       controller.think1 = getthink(this);
-
-       // the thinking is now done by the controller
-       setthink(this, SUB_NullThink); // for PushMove
-       this.nextthink = this.ltime + traveltime;
-
-       // invoke controller
-       getthink(controller)(controller);
-}
-
-void SUB_CalcMove (entity this, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
-{
-       vector  delta;
-       float   traveltime;
-
-       if (!tspeed)
-               objerror (this, "No speed is defined!");
-
-       this.think1 = func;
-       this.finaldest = tdest;
-       setthink(this, SUB_CalcMoveDone);
-
-       if (tdest == this.origin)
-       {
-               this.velocity = '0 0 0';
-               this.nextthink = this.ltime + 0.1;
-               return;
-       }
-
-       delta = tdest - this.origin;
-
-       switch(tspeedtype)
-       {
-               default:
-               case TSPEED_START:
-               case TSPEED_END:
-               case TSPEED_LINEAR:
-                       traveltime = vlen (delta) / tspeed;
-                       break;
-               case TSPEED_TIME:
-                       traveltime = tspeed;
-                       break;
-       }
-
-       // Very short animations don't really show off the effect
-       // of controlled animation, so let's just use linear movement.
-       // Alternatively entities can choose to specify non-controlled movement.
-        // The only currently implemented alternative movement is linear (value 1)
-       if (traveltime < 0.15 || (this.platmovetype_start == 1 && this.platmovetype_end == 1)) // is this correct?
-       {
-               this.velocity = delta * (1/traveltime); // QuakeC doesn't allow vector/float division
-               this.nextthink = this.ltime + traveltime;
-               return;
-       }
-
-       // now just run like a bezier curve...
-       SUB_CalcMove_Bezier(this, (this.origin + tdest) * 0.5, tdest, tspeedtype, tspeed, func);
-}
-
-void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void(entity this) func)
-{
-       SUB_CalcMove(ent, tdest, tspeedtype, tspeed, func);
-}
-
-/*
-=============
-SUB_CalcAngleMove
-
-calculate this.avelocity and this.nextthink to reach destangle from
-this.angles rotating
-
-The calling function should make sure this.setthink is valid
-===============
-*/
-void SUB_CalcAngleMoveDone(entity this)
-{
-       // After rotating, set angle to exact final angle
-       this.angles = this.finalangle;
-       this.avelocity = '0 0 0';
-       this.nextthink = -1;
-       if (this.think1 && this.think1 != SUB_CalcAngleMoveDone) // avoid endless loops
-               this.think1 (this);
-}
-
-// FIXME: I fixed this function only for rotation around the main axes
-void SUB_CalcAngleMove (entity this, vector destangle, float tspeedtype, float tspeed, void(entity this) func)
-{
-       if (!tspeed)
-               objerror (this, "No speed is defined!");
-
-       // take the shortest distance for the angles
-       this.angles_x -= 360 * floor((this.angles_x - destangle_x) / 360 + 0.5);
-       this.angles_y -= 360 * floor((this.angles_y - destangle_y) / 360 + 0.5);
-       this.angles_z -= 360 * floor((this.angles_z - destangle_z) / 360 + 0.5);
-       vector delta = destangle - this.angles;
-       float traveltime;
-
-       switch(tspeedtype)
-       {
-               default:
-               case TSPEED_START:
-               case TSPEED_END:
-               case TSPEED_LINEAR:
-                       traveltime = vlen (delta) / tspeed;
-                       break;
-               case TSPEED_TIME:
-                       traveltime = tspeed;
-                       break;
-       }
-
-       this.think1 = func;
-       this.finalangle = destangle;
-       setthink(this, SUB_CalcAngleMoveDone);
-
-       if (traveltime < 0.1)
-       {
-               this.avelocity = '0 0 0';
-               this.nextthink = this.ltime + 0.1;
-               return;
-       }
-
-       this.avelocity = delta * (1 / traveltime);
-       this.nextthink = this.ltime + traveltime;
-}
-
-void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void(entity this) func)
-{
-       SUB_CalcAngleMove (ent, destangle, tspeedtype, tspeed, func);
-}
diff --git a/qcsrc/common/triggers/subs.qh b/qcsrc/common/triggers/subs.qh
deleted file mode 100644 (file)
index 1b3bc5e..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-void SUB_SetFade (entity ent, float when, float fading_time);
-void SUB_VanishOrRemove (entity ent);
-
-.vector                finaldest, finalangle;          //plat.qc stuff
-.void(entity this) think1;
-.float state;
-.float         t_length, t_width;
-
-.vector destvec;
-.vector destvec2;
-
-.float delay;
-.float wait;
-.float lip;
-.float speed;
-.float sounds;
-.string  platmovetype;
-.float platmovetype_start, platmovetype_end;
-
-//entity activator;
-
-.string killtarget;
-
-.vector        pos1, pos2;
-.vector        mangle;
-
-.string target2;
-.string target3;
-.string target4;
-.string curvetarget;
-.float target_random;
-.float trigger_reverse;
-
-// Keys player is holding
-.float itemkeys;
-// message delay for func_door locked by keys and key locks
-// this field is used on player entities
-.float key_door_messagetime;
-
-.vector dest1, dest2;
-
-#ifdef CSQC
-// this stuff is defined in the server side engine VM, so we must define it separately here
-.float takedamage;
-const float DAMAGE_NO  = 0;
-const float DAMAGE_YES = 1;
-const float DAMAGE_AIM = 2;
-
-float  STATE_TOP               = 0;
-float  STATE_BOTTOM    = 1;
-float  STATE_UP                = 2;
-float  STATE_DOWN              = 3;
-
-.string                noise, noise1, noise2, noise3;  // contains names of wavs to play
-
-.float         max_health;             // players maximum health is stored here
-#endif
diff --git a/qcsrc/common/triggers/target/_mod.inc b/qcsrc/common/triggers/target/_mod.inc
deleted file mode 100644 (file)
index afd1050..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/target/changelevel.qc>
-#include <common/triggers/target/include.qc>
-#include <common/triggers/target/kill.qc>
-#include <common/triggers/target/levelwarp.qc>
-#include <common/triggers/target/location.qc>
-#include <common/triggers/target/music.qc>
-#include <common/triggers/target/spawn.qc>
-#include <common/triggers/target/spawnpoint.qc>
-#include <common/triggers/target/speaker.qc>
-#include <common/triggers/target/voicescript.qc>
diff --git a/qcsrc/common/triggers/target/_mod.qh b/qcsrc/common/triggers/target/_mod.qh
deleted file mode 100644 (file)
index 7c9fbee..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/target/changelevel.qh>
-#include <common/triggers/target/include.qh>
-#include <common/triggers/target/kill.qh>
-#include <common/triggers/target/levelwarp.qh>
-#include <common/triggers/target/location.qh>
-#include <common/triggers/target/music.qh>
-#include <common/triggers/target/spawn.qh>
-#include <common/triggers/target/spawnpoint.qh>
-#include <common/triggers/target/speaker.qh>
-#include <common/triggers/target/voicescript.qh>
diff --git a/qcsrc/common/triggers/target/changelevel.qc b/qcsrc/common/triggers/target/changelevel.qc
deleted file mode 100644 (file)
index 6c006d4..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-#include "changelevel.qh"
-#ifdef SVQC
-.string chmap, gametype;
-.entity chlevel_targ;
-
-void target_changelevel_use(entity this, entity actor, entity trigger)
-{
-       if(this.spawnflags & 2)
-       {
-               // simply don't react if a non-player triggers it
-               if(!IS_PLAYER(actor)) { return; }
-
-               actor.chlevel_targ = this;
-
-               int plnum = 0;
-               int realplnum = 0;
-               // let's not count bots
-               FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-                       ++realplnum;
-                       if(it.chlevel_targ == this)
-                               ++plnum;
-               });
-               if(plnum < ceil(realplnum * min(1, this.count))) // 70% of players
-                       return;
-       }
-
-       if(this.gametype != "")
-               MapInfo_SwitchGameType(MapInfo_Type_FromString(this.gametype));
-
-       if (this.chmap == "")
-               localcmd("endmatch\n");
-       else
-               localcmd(strcat("changelevel ", this.chmap, "\n"));
-}
-
-spawnfunc(target_changelevel)
-{
-       this.use = target_changelevel_use;
-
-       if(!this.count) { this.count = 0.7; }
-}
-#endif
diff --git a/qcsrc/common/triggers/target/changelevel.qh b/qcsrc/common/triggers/target/changelevel.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/include.qc b/qcsrc/common/triggers/target/include.qc
deleted file mode 100644 (file)
index a45c65e..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-#include "include.qh"
-
-#include "changelevel.qc"
-#include "kill.qc"
-#include "levelwarp.qc"
-#include "location.qc"
-#include "music.qc"
-#include "spawn.qc"
-#include "spawnpoint.qc"
-#include "speaker.qc"
-#include "voicescript.qc"
diff --git a/qcsrc/common/triggers/target/include.qh b/qcsrc/common/triggers/target/include.qh
deleted file mode 100644 (file)
index c0f7cad..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-#include "music.qh"
diff --git a/qcsrc/common/triggers/target/kill.qc b/qcsrc/common/triggers/target/kill.qc
deleted file mode 100644 (file)
index 2751c60..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#include "kill.qh"
-#include "location.qh"
-#ifdef SVQC
-
-void target_kill_use(entity this, entity actor, entity trigger)
-{
-       if(actor.takedamage == DAMAGE_NO)
-               return;
-
-       if(!actor.iscreature && !actor.damagedbytriggers)
-               return;
-
-       Damage(actor, this, trigger, 1000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, actor.origin, '0 0 0');
-}
-
-spawnfunc(target_kill)
-{
-    this.classname = "target_kill";
-
-    if (this.message == "")
-               this.message = "was in the wrong place";
-
-    this.use = target_kill_use;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/target/kill.qh b/qcsrc/common/triggers/target/kill.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/levelwarp.qc b/qcsrc/common/triggers/target/levelwarp.qc
deleted file mode 100644 (file)
index 6cef53d..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#include "levelwarp.qh"
-
-#ifdef SVQC
-void target_levelwarp_use(entity this, entity actor, entity trigger)
-{
-       if(!autocvar_g_campaign)
-               return; // only in campaign
-
-       if(this.cnt)
-               CampaignLevelWarp(this.cnt - 1); // specific level
-       else
-               CampaignLevelWarp(-1); // next level
-}
-
-spawnfunc(target_levelwarp)
-{
-       this.use = target_levelwarp_use;
-}
-#endif
diff --git a/qcsrc/common/triggers/target/levelwarp.qh b/qcsrc/common/triggers/target/levelwarp.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/location.qc b/qcsrc/common/triggers/target/location.qc
deleted file mode 100644 (file)
index 5774f45..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "location.qh"
-#ifdef SVQC
-void target_push_init(entity this);
-
-spawnfunc(target_location)
-{
-    this.classname = "target_location";
-    // location name in netname
-    // eventually support: count, teamgame selectors, line of sight?
-
-    target_push_init(this);
-
-    IL_PUSH(g_locations, this);
-}
-
-spawnfunc(info_location)
-{
-    this.classname = "target_location";
-    this.message = this.netname;
-
-    target_push_init(this);
-
-    IL_PUSH(g_locations, this);
-}
-#endif
diff --git a/qcsrc/common/triggers/target/location.qh b/qcsrc/common/triggers/target/location.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/music.qc b/qcsrc/common/triggers/target/music.qc
deleted file mode 100644 (file)
index 7ec3351..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-#include "music.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <common/constants.qh>
-    #include <common/net_linked.qh>
-    #include <server/constants.qh>
-    #include <server/defs.qh>
-#endif
-
-REGISTER_NET_TEMP(TE_CSQC_TARGET_MUSIC)
-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
-//   targetname
-//   lifetime
-//   fade_time
-//   fade_rate
-// when triggered, the music is overridden for activator until lifetime (or forever, if lifetime is 0)
-// when targetname is not set, THIS ONE is default
-void target_music_sendto(entity this, int to, bool is)
-{
-       WriteHeader(to, TE_CSQC_TARGET_MUSIC);
-       WriteShort(to, etof(this));
-       WriteByte(to, this.volume * 255.0 * is);
-       WriteByte(to, this.fade_time * 16.0);
-       WriteByte(to, this.fade_rate * 16.0);
-       WriteByte(to, this.lifetime);
-       WriteString(to, this.noise);
-}
-void target_music_reset(entity this)
-{
-       if (this.targetname == "") target_music_sendto(this, MSG_ALL, 1);
-}
-void target_music_kill()
-{
-       IL_EACH(g_targetmusic_list, true,
-       {
-               it.volume = 0;
-        if (it.targetname == "")
-            target_music_sendto(it, MSG_ALL, 1);
-        else
-            target_music_sendto(it, MSG_ALL, 0);
-       });
-}
-void target_music_use(entity this, entity actor, entity trigger)
-{
-       if(!actor)
-               return;
-       if(IS_REAL_CLIENT(actor))
-       {
-               msg_entity = actor;
-               target_music_sendto(this, MSG_ONE, 1);
-       }
-       FOREACH_CLIENT(IS_SPEC(it) && it.enemy == actor, {
-               msg_entity = it;
-               target_music_sendto(this, MSG_ONE, 1);
-       });
-}
-spawnfunc(target_music)
-{
-       this.use = target_music_use;
-       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
-               target_music_sendto(this, MSG_INIT, 0);
-}
-void TargetMusic_RestoreGame()
-{
-       IL_EACH(g_targetmusic_list, true,
-       {
-               if(it.targetname == "")
-                       target_music_sendto(it, MSG_INIT, 1);
-               else
-                       target_music_sendto(it, MSG_INIT, 0);
-       });
-}
-// values:
-//   volume
-//   noise
-//   targetname
-//   fade_time
-// spawnflags:
-//   1 = START_OFF
-// when triggered, it is disabled/enabled for everyone
-bool trigger_music_SendEntity(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_MUSIC);
-       sf &= ~0x80;
-       if(this.cnt)
-               sf |= 0x80;
-       WriteByte(MSG_ENTITY, sf);
-       if(sf & 4)
-       {
-               WriteVector(MSG_ENTITY, this.origin);
-       }
-       if(sf & 1)
-       {
-               if(this.model != "null")
-               {
-                       WriteShort(MSG_ENTITY, this.modelindex);
-                       WriteVector(MSG_ENTITY, this.mins);
-                       WriteVector(MSG_ENTITY, this.maxs);
-               }
-               else
-               {
-                       WriteShort(MSG_ENTITY, 0);
-                       WriteVector(MSG_ENTITY, this.maxs);
-               }
-               WriteByte(MSG_ENTITY, this.volume * 255.0);
-               WriteByte(MSG_ENTITY, this.fade_time * 16.0);
-               WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
-               WriteString(MSG_ENTITY, this.noise);
-       }
-       return 1;
-}
-void trigger_music_reset(entity this)
-{
-       this.cnt = !(this.spawnflags & 1);
-       this.SendFlags |= 0x80;
-}
-void trigger_music_use(entity this, entity actor, entity trigger)
-{
-       this.cnt = !this.cnt;
-       this.SendFlags |= 0x80;
-}
-spawnfunc(trigger_music)
-{
-       if(this.model != "") _setmodel(this, this.model);
-       if(!this.volume) this.volume = 1;
-       if(!this.modelindex)
-       {
-               setorigin(this, this.origin + this.mins);
-               setsize(this, '0 0 0', this.maxs - this.mins);
-       }
-       trigger_music_reset(this);
-
-       this.use = trigger_music_use;
-       this.reset = trigger_music_reset;
-
-       Net_LinkEntity(this, false, 0, trigger_music_SendEntity);
-}
-#elif defined(CSQC)
-
-entity TargetMusic_list;
-STATIC_INIT(TargetMusic_list)
-{
-       TargetMusic_list = LL_NEW();
-}
-
-void TargetMusic_Advance()
-{
-       // run AFTER all the thinks!
-       entity best = music_default;
-       if (music_target && time < music_target.lifetime) best = music_target;
-       if (music_trigger) best = music_trigger;
-       LL_EACH(TargetMusic_list, it.noise, {
-               const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
-               if (it == best)
-               {
-                       // increase volume
-                       it.state = (it.fade_time > 0) ? bound(0, it.state + frametime / it.fade_time, 1) : 1;
-               }
-               else
-               {
-                       // decrease volume
-                       it.state = (it.fade_rate > 0) ? bound(0, it.state - frametime / it.fade_rate, 1) : 0;
-               }
-               const float vol = it.state * it.volume * autocvar_bgmvolume;
-               if (vol != vol0)
-               {
-                       if(vol0 < 0)
-                               _sound(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE); // restart
-                       else
-                               _sound(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
-                       it.lastvol = vol;
-               }
-       });
-       music_trigger = NULL;
-       bgmtime = (best) ? getsoundtime(best, CH_BGM_SINGLE) : gettime(GETTIME_CDTRACK);
-}
-
-NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
-{
-       Net_TargetMusic();
-       return true;
-}
-
-void Net_TargetMusic()
-{
-       const int id = ReadShort();
-       const float vol = ReadByte() / 255.0;
-       const float fai = ReadByte() / 16.0;
-       const float fao = ReadByte() / 16.0;
-       const float tim = ReadByte();
-       const string noi = ReadString();
-
-       entity e = NULL;
-       LL_EACH(TargetMusic_list, it.count == id, { e = it; break; });
-       if (!e)
-       {
-               LL_PUSH(TargetMusic_list, e = new_pure(TargetMusic));
-               e.count = id;
-       }
-       if(e.noise != noi)
-       {
-               if(e.noise)
-                       strunzone(e.noise);
-               e.noise = strzone(noi);
-               precache_sound(e.noise);
-               _sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
-               if(getsoundtime(e, CH_BGM_SINGLE) < 0)
-               {
-                       LOG_TRACEF("Cannot initialize sound %s", e.noise);
-                       strunzone(e.noise);
-                       e.noise = string_null;
-               }
-       }
-       e.volume = vol;
-       e.fade_time = fai;
-       e.fade_rate = fao;
-       if(vol > 0)
-       {
-               if(tim == 0)
-               {
-                       music_default = e;
-                       if(!music_disabled)
-                       {
-                               e.state = 2;
-                               cvar_settemp("music_playlist_index", "-1"); // don't use playlists
-                               localcmd("cd stop\n"); // just in case
-                               music_disabled = 1;
-                       }
-               }
-               else
-               {
-                       music_target = e;
-                       e.lifetime = time + tim;
-               }
-       }
-}
-
-void Ent_TriggerMusic_Think(entity this)
-{
-       if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, this, NULL))
-       {
-               music_trigger = this;
-       }
-       this.nextthink = time;
-}
-
-void Ent_TriggerMusic_Remove(entity this)
-{
-       if(this.noise)
-               strunzone(this.noise);
-       this.noise = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
-{
-       int f = ReadByte();
-       if(f & 4)
-       {
-               this.origin = ReadVector();
-       }
-       if(f & 1)
-       {
-               this.modelindex = ReadShort();
-               if(this.modelindex)
-               {
-                       this.mins = ReadVector();
-                       this.maxs = ReadVector();
-               }
-               else
-               {
-                       this.mins    = '0 0 0';
-                       this.maxs = ReadVector();
-               }
-
-               this.volume = ReadByte() / 255.0;
-               this.fade_time = ReadByte() / 16.0;
-               this.fade_rate = ReadByte() / 16.0;
-               string s = this.noise;
-               if(this.noise)
-                       strunzone(this.noise);
-               this.noise = strzone(ReadString());
-               if(this.noise != s)
-               {
-                       precache_sound(this.noise);
-                       _sound(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE);
-                       if(getsoundtime(this, CH_BGM_SINGLE) < 0)
-                       {
-                               LOG_TRACEF("Cannot initialize sound %s", this.noise);
-                               strunzone(this.noise);
-                               this.noise = string_null;
-                       }
-               }
-       }
-
-       setorigin(this, this.origin);
-       setsize(this, this.mins, this.maxs);
-       this.cnt = 1;
-       setthink(this, Ent_TriggerMusic_Think);
-       this.nextthink = time;
-       return true;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/target/music.qh b/qcsrc/common/triggers/target/music.qh
deleted file mode 100644 (file)
index 80b3684..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#pragma once
-
-.float lifetime;
-
-#ifdef CSQC
-float music_disabled;
-entity music_default;
-entity music_target;
-entity music_trigger;
-// FIXME also control bgmvolume here, to not require a target_music for the default track.
-
-entityclass(TargetMusic);
-class(TargetMusic) .int state;
-class(TargetMusic) .float lastvol;
-
-void TargetMusic_Advance();
-
-void Net_TargetMusic();
-
-void Ent_TriggerMusic_Think(entity this);
-
-void Ent_TriggerMusic_Remove(entity this);
-
-#elif defined(SVQC)
-void target_music_kill();
-#endif
diff --git a/qcsrc/common/triggers/target/spawn.qc b/qcsrc/common/triggers/target/spawn.qc
deleted file mode 100644 (file)
index 1464da9..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-#include "spawn.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <common/util.qh>
-    #include <server/defs.qh>
-#endif
-
-#ifdef SVQC
-
-// spawner entity
-// "classname" "target_spawn"
-// "message" "fieldname value fieldname value ..."
-// "spawnflags"
-//   1 = call the spawn function
-//   2 = trigger on map load
-
-float target_spawn_initialized;
-.void(entity this) target_spawn_spawnfunc;
-float target_spawn_spawnfunc_field;
-.entity target_spawn_activator;
-.float target_spawn_id;
-float target_spawn_count;
-
-void target_spawn_helper_setmodel(entity this)
-{
-       _setmodel(this, this.model);
-}
-
-void target_spawn_helper_setsize(entity this)
-{
-       setsize(this, this.mins, this.maxs);
-}
-
-void target_spawn_edit_entity(entity this, entity e, string msg, entity kt, entity t2, entity t3, entity t4, entity act, entity trigger)
-{
-       float i, n, valuefieldpos;
-       string key, value, valuefield, valueoffset, valueoffsetrandom;
-       entity valueent;
-       vector data, data2;
-
-       n = tokenize_console(msg);
-
-       for(i = 0; i < n-1; i += 2)
-       {
-               key = argv(i);
-               value = argv(i+1);
-               if(key == "$")
-               {
-                       data.x = -1;
-                       data.y = FIELD_STRING;
-               }
-               else
-               {
-                       data = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", key)));
-                       if(data.y == 0) // undefined field, i.e., invalid type
-                       {
-                               LOG_INFO("target_spawn: invalid/unknown entity key ", key, " specified, ignored!");
-                               continue;
-                       }
-               }
-               if(substring(value, 0, 1) == "$")
-               {
-                       value = substring(value, 1, strlen(value) - 1);
-                       if(substring(value, 0, 1) == "$")
-                       {
-                               // deferred replacement
-                               // do nothing
-                               // useful for creating target_spawns with this!
-                       }
-                       else
-                       {
-                               // replace me!
-                               valuefieldpos = strstrofs(value, "+", 0);
-                               valueoffset = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valueoffset = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
-                                       value = substring(value, 0, valuefieldpos);
-                               }
-
-                               valuefieldpos = strstrofs(valueoffset, "+", 0);
-                               valueoffsetrandom = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valueoffsetrandom = substring(valueoffset, valuefieldpos + 1, strlen(valueoffset) - valuefieldpos - 1);
-                                       valueoffset = substring(valueoffset, 0, valuefieldpos);
-                               }
-
-                               valuefieldpos = strstrofs(value, ".", 0);
-                               valuefield = "";
-                               if(valuefieldpos != -1)
-                               {
-                                       valuefield = substring(value, valuefieldpos + 1, strlen(value) - valuefieldpos - 1);
-                                       value = substring(value, 0, valuefieldpos);
-                               }
-
-                               if(value == "self")
-                               {
-                                       valueent = this;
-                                       value = "";
-                               }
-                               else if(value == "activator")
-                               {
-                                       valueent = act;
-                                       value = "";
-                               }
-                               else if(value == "other")
-                               {
-                                       valueent = trigger;
-                                       value = "";
-                               }
-                               else if(value == "pusher")
-                               {
-                                       if(time < act.pushltime)
-                                               valueent = act.pusher;
-                                       else
-                                               valueent = NULL;
-                                       value = "";
-                               }
-                               else if(value == "target")
-                               {
-                                       valueent = e;
-                                       value = "";
-                               }
-                               else if(value == "killtarget")
-                               {
-                                       valueent = kt;
-                                       value = "";
-                               }
-                               else if(value == "target2")
-                               {
-                                       valueent = t2;
-                                       value = "";
-                               }
-                               else if(value == "target3")
-                               {
-                                       valueent = t3;
-                                       value = "";
-                               }
-                               else if(value == "target4")
-                               {
-                                       valueent = t4;
-                                       value = "";
-                               }
-                               else if(value == "time")
-                               {
-                                       valueent = NULL;
-                                       value = ftos(time);
-                               }
-                               else
-                               {
-                                       LOG_INFO("target_spawn: invalid/unknown variable replacement ", value, " specified, ignored!");
-                                       continue;
-                               }
-
-                               if(valuefield == "")
-                               {
-                                       if(value == "")
-                                               value = ftos(etof(valueent));
-                               }
-                               else
-                               {
-                                       if(value != "")
-                                       {
-                                               LOG_INFO("target_spawn: try to get a field of a non-entity, ignored!");
-                                               continue;
-                                       }
-                                       data2 = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", valuefield)));
-                                       if(data2_y == 0) // undefined field, i.e., invalid type
-                                       {
-                                               LOG_INFO("target_spawn: invalid/unknown entity key replacement ", valuefield, " specified, ignored!");
-                                               continue;
-                                       }
-                                       value = getentityfieldstring(data2_x, valueent);
-                               }
-
-                               if(valueoffset != "")
-                               {
-                                       switch(data.y)
-                                       {
-                                               case FIELD_STRING:
-                                                       value = strcat(value, valueoffset);
-                                                       break;
-                                               case FIELD_FLOAT:
-                                                       value = ftos(stof(value) + stof(valueoffset));
-                                                       break;
-                                               case FIELD_VECTOR:
-                                                       value = vtos(stov(value) + stov(valueoffset));
-                                                       break;
-                                               default:
-                                                       LOG_INFO("target_spawn: only string, float and vector fields can do calculations, calculation ignored!");
-                                                       break;
-                                       }
-                               }
-
-                               if(valueoffsetrandom != "")
-                               {
-                                       switch(data.y)
-                                       {
-                                               case FIELD_FLOAT:
-                                                       value = ftos(stof(value) + random() * stof(valueoffsetrandom));
-                                                       break;
-                                               case FIELD_VECTOR:
-                                                       data2 = stov(valueoffsetrandom);
-                                                       value = vtos(stov(value) + random() * data2_x * '1 0 0' + random() * data2_y * '0 1 0' + random() * data2_z * '0 0 1');
-                                                       break;
-                                               default:
-                                                       LOG_INFO("target_spawn: only float and vector fields can do random calculations, calculation ignored!");
-                                                       break;
-                                       }
-                               }
-                       }
-               }
-               if(key == "$")
-               {
-                       if(substring(value, 0, 1) == "_")
-                               value = strcat("target_spawn_helper", value);
-                       putentityfieldstring(target_spawn_spawnfunc_field, e, value);
-
-                       e.target_spawn_spawnfunc(e);
-
-                       // We called an external function, so we have to re-tokenize msg.
-                       n = tokenize_console(msg);
-               }
-               else
-               {
-                       if(data.y == FIELD_VECTOR)
-                               value = strreplace("'", "", value); // why?!?
-                       putentityfieldstring(data.x, e, value);
-               }
-       }
-}
-
-void target_spawn_useon(entity e, entity this, entity actor, entity trigger)
-{
-       this.target_spawn_activator = actor;
-       target_spawn_edit_entity(
-               this,
-               e,
-               this.message,
-               find(NULL, targetname, this.killtarget),
-               find(NULL, targetname, this.target2),
-               find(NULL, targetname, this.target3),
-               find(NULL, targetname, this.target4),
-               actor,
-               trigger
-       );
-}
-
-bool target_spawn_cancreate(entity this)
-{
-       float c;
-       entity e;
-
-       c = this.count;
-       if(c == 0) // no limit?
-               return true;
-
-       ++c; // increase count to not include MYSELF
-       for(e = NULL; (e = findfloat(e, target_spawn_id, this.target_spawn_id)); --c)
-               ;
-
-       // if c now is 0, we have AT LEAST the given count (maybe more), so don't spawn any more
-       if(c == 0)
-               return false;
-       return true;
-}
-
-void target_spawn_use(entity this, entity actor, entity trigger)
-{
-       if(this.target == "")
-       {
-               // spawn new entity
-               if(!target_spawn_cancreate(this))
-                       return;
-               entity e = spawn();
-               e.spawnfunc_checked = true;
-               target_spawn_useon(e, this, actor, trigger);
-               e.target_spawn_id = this.target_spawn_id;
-       }
-       else if(this.target == "*activator")
-       {
-               // edit entity
-               if(actor)
-                       target_spawn_useon(actor, this, actor, trigger);
-       }
-       else
-       {
-               // edit entity
-               FOREACH_ENTITY_STRING(targetname, this.target,
-               {
-                       target_spawn_useon(it, this, actor, trigger);
-               });
-       }
-}
-
-void target_spawn_spawnfirst(entity this)
-{
-       entity act = this.target_spawn_activator;
-       if(this.spawnflags & 2)
-               target_spawn_use(this, act, NULL);
-}
-
-void initialize_field_db()
-{
-       if(!target_spawn_initialized)
-       {
-               float n, i;
-               string fn;
-               vector prev, next;
-               float ft;
-
-               n = numentityfields();
-               for(i = 0; i < n; ++i)
-               {
-                       fn = entityfieldname(i);
-                       ft = entityfieldtype(i);
-                       next = i * '1 0 0' + ft * '0 1 0' + '0 0 1';
-                       prev = stov(db_get(TemporaryDB, strcat("/target_spawn/field/", fn)));
-                       if(prev.y == 0)
-                       {
-                               db_put(TemporaryDB, strcat("/target_spawn/field/", fn), vtos(next));
-                               if(fn == "target_spawn_spawnfunc")
-                                       target_spawn_spawnfunc_field = i;
-                       }
-               }
-
-               target_spawn_initialized = 1;
-       }
-}
-
-spawnfunc(target_spawn)
-{
-       initialize_field_db();
-       this.use = target_spawn_use;
-       this.message = strzone(strreplace("'", "\"", this.message));
-       this.target_spawn_id = ++target_spawn_count;
-       InitializeEntity(this, target_spawn_spawnfirst, INITPRIO_LAST);
-}
-#endif
diff --git a/qcsrc/common/triggers/target/spawn.qh b/qcsrc/common/triggers/target/spawn.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/spawnpoint.qc b/qcsrc/common/triggers/target/spawnpoint.qc
deleted file mode 100644 (file)
index fe15385..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "spawnpoint.qh"
-
-#ifdef SVQC
-void target_spawnpoint_use(entity this, entity actor, entity trigger)
-{
-       if(this.active != ACTIVE_ACTIVE)
-               return;
-
-       actor.spawnpoint_targ = this;
-}
-
-void target_spawnpoint_reset(entity this)
-{
-       this.active = ACTIVE_ACTIVE;
-}
-
-// TODO: persistent spawnflag?
-spawnfunc(target_spawnpoint)
-{
-       this.active = ACTIVE_ACTIVE;
-       this.use = target_spawnpoint_use;
-       this.reset = target_spawnpoint_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/target/spawnpoint.qh b/qcsrc/common/triggers/target/spawnpoint.qh
deleted file mode 100644 (file)
index 2eeb8da..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-#ifdef SVQC
-.entity spawnpoint_targ;
-#endif
diff --git a/qcsrc/common/triggers/target/speaker.qc b/qcsrc/common/triggers/target/speaker.qc
deleted file mode 100644 (file)
index af327b4..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-#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);
-void target_speaker_use_activator(entity this, entity actor, entity trigger)
-{
-       if (!IS_REAL_CLIENT(actor))
-               return;
-       string snd;
-       if(substring(this.noise, 0, 1) == "*")
-       {
-               var .string sample = GetVoiceMessageSampleField(substring(this.noise, 1, -1));
-               if(GetPlayerSoundSampleField_notFound)
-                       snd = SND(Null);
-               else if(actor.(sample) == "")
-                       snd = SND(Null);
-               else
-               {
-                       tokenize_console(actor.(sample));
-                       float n;
-                       n = stof(argv(1));
-                       if(n > 0)
-                               snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
-                       else
-                               snd = strcat(argv(0), ".wav"); // randomization
-               }
-       }
-       else
-               snd = this.noise;
-       msg_entity = actor;
-       soundto(MSG_ONE, this, CH_TRIGGER, snd, VOL_BASE * this.volume, this.atten);
-}
-void target_speaker_use_on(entity this, entity actor, entity trigger)
-{
-       string snd;
-       if(substring(this.noise, 0, 1) == "*")
-       {
-               var .string sample = GetVoiceMessageSampleField(substring(this.noise, 1, -1));
-               if(GetPlayerSoundSampleField_notFound)
-                       snd = SND(Null);
-               else if(actor.(sample) == "")
-                       snd = SND(Null);
-               else
-               {
-                       tokenize_console(actor.(sample));
-                       float n;
-                       n = stof(argv(1));
-                       if(n > 0)
-                               snd = strcat(argv(0), ftos(floor(random() * n + 1)), ".wav"); // randomization
-                       else
-                               snd = strcat(argv(0), ".wav"); // randomization
-               }
-       }
-       else
-               snd = this.noise;
-       _sound(this, CH_TRIGGER_SINGLE, snd, VOL_BASE * this.volume, this.atten);
-       if(this.spawnflags & 3)
-               this.use = target_speaker_use_off;
-}
-void target_speaker_use_off(entity this, entity actor, entity trigger)
-{
-       sound(this, CH_TRIGGER_SINGLE, SND_Null, VOL_BASE * this.volume, this.atten);
-       this.use = target_speaker_use_on;
-}
-void target_speaker_reset(entity this)
-{
-       if(this.spawnflags & 1) // LOOPED_ON
-       {
-               if(this.use == target_speaker_use_on)
-                       target_speaker_use_on(this, NULL, NULL);
-       }
-       else if(this.spawnflags & 2)
-       {
-               if(this.use == target_speaker_use_off)
-                       target_speaker_use_off(this, NULL, NULL);
-       }
-}
-
-spawnfunc(target_speaker)
-{
-       // TODO: "*" prefix to sound file name
-       // TODO: wait and random (just, HOW? random is not a field)
-       if(this.noise)
-               precache_sound (this.noise);
-
-       if(!this.atten && !(this.spawnflags & 4))
-       {
-               IFTARGETED
-                       this.atten = ATTEN_NORM;
-               else
-                       this.atten = ATTEN_STATIC;
-       }
-       else if(this.atten < 0)
-               this.atten = 0;
-
-       if(!this.volume)
-               this.volume = 1;
-
-       IFTARGETED
-       {
-               if(this.spawnflags & 8) // ACTIVATOR
-                       this.use = target_speaker_use_activator;
-               else if(this.spawnflags & 1) // LOOPED_ON
-               {
-                       target_speaker_use_on(this, NULL, NULL);
-                       this.reset = target_speaker_reset;
-               }
-               else if(this.spawnflags & 2) // LOOPED_OFF
-               {
-                       this.use = target_speaker_use_on;
-                       this.reset = target_speaker_reset;
-               }
-               else
-                       this.use = target_speaker_use_on;
-       }
-       else if(this.spawnflags & 1) // LOOPED_ON
-       {
-               ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
-               delete(this);
-       }
-       else if(this.spawnflags & 2) // LOOPED_OFF
-       {
-               objerror(this, "This sound entity can never be activated");
-       }
-       else
-       {
-               // Quake/Nexuiz fallback
-               ambientsound (this.origin, this.noise, VOL_BASE * this.volume, this.atten);
-               delete(this);
-       }
-}
-#endif
diff --git a/qcsrc/common/triggers/target/speaker.qh b/qcsrc/common/triggers/target/speaker.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/target/voicescript.qc b/qcsrc/common/triggers/target/voicescript.qc
deleted file mode 100644 (file)
index 6dfb568..0000000
+++ /dev/null
@@ -1,102 +0,0 @@
-#include "voicescript.qh"
-#ifdef SVQC
-.entity voicescript; // attached voice script
-.float voicescript_index; // index of next voice, or -1 to use the randomized ones
-.float voicescript_nextthink; // time to play next voice
-.float voicescript_voiceend; // time when this voice ends
-
-void target_voicescript_clear(entity pl)
-{
-       pl.voicescript = NULL;
-}
-
-void target_voicescript_use(entity this, entity actor, entity trigger)
-{
-       if(actor.voicescript != this)
-       {
-               actor.voicescript = this;
-               actor.voicescript_index = 0;
-               actor.voicescript_nextthink = time + this.delay;
-       }
-}
-
-void target_voicescript_next(entity pl)
-{
-       entity vs;
-       float i, n, dt;
-
-       vs = pl.voicescript;
-       if(!vs)
-               return;
-       if(vs.message == "")
-               return;
-       if (!IS_PLAYER(pl))
-               return;
-       if(game_stopped)
-               return;
-
-       if(time >= pl.voicescript_voiceend)
-       {
-               if(time >= pl.voicescript_nextthink)
-               {
-                       // get the next voice...
-                       n = tokenize_console(vs.message);
-
-                       if(pl.voicescript_index < vs.cnt)
-                               i = pl.voicescript_index * 2;
-                       else if(n > vs.cnt * 2)
-                               i = ((pl.voicescript_index - vs.cnt) % ((n - vs.cnt * 2 - 1) / 2)) * 2 + vs.cnt * 2 + 1;
-                       else
-                               i = -1;
-
-                       if(i >= 0)
-                       {
-                               play2(pl, strcat(vs.netname, "/", argv(i), ".wav"));
-                               dt = stof(argv(i + 1));
-                               if(dt >= 0)
-                               {
-                                       pl.voicescript_voiceend = time + dt;
-                                       pl.voicescript_nextthink = pl.voicescript_voiceend + vs.wait * (0.5 + random());
-                               }
-                               else
-                               {
-                                       pl.voicescript_voiceend = time - dt;
-                                       pl.voicescript_nextthink = pl.voicescript_voiceend;
-                               }
-
-                               pl.voicescript_index += 1;
-                       }
-                       else
-                       {
-                               pl.voicescript = NULL; // stop trying then
-                       }
-               }
-       }
-}
-
-spawnfunc(target_voicescript)
-{
-       // netname: directory of the sound files
-       // message: list of "sound file" duration "sound file" duration, a *, and again a list
-       //          foo1 4.1 foo2 4.0 foo3 -3.1 * fool1 1.1 fool2 7.1 fool3 9.1 fool4 3.7
-       //          Here, a - in front of the duration means that no delay is to be
-       //          added after this message
-       // wait: average time between messages
-       // delay: initial delay before the first message
-
-       float i, n;
-       this.use = target_voicescript_use;
-
-       n = tokenize_console(this.message);
-       this.cnt = n / 2;
-       for(i = 0; i+1 < n; i += 2)
-       {
-               if(argv(i) == "*")
-               {
-                       this.cnt = i / 2;
-                       ++i;
-               }
-               precache_sound(strcat(this.netname, "/", argv(i), ".wav"));
-       }
-}
-#endif
diff --git a/qcsrc/common/triggers/target/voicescript.qh b/qcsrc/common/triggers/target/voicescript.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/teleporters.qc b/qcsrc/common/triggers/teleporters.qc
deleted file mode 100644 (file)
index 25626e0..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-#include "teleporters.qh"
-
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <lib/warpzone/common.qh>
-    #include <lib/warpzone/util_server.qh>
-    #include <lib/warpzone/server.qh>
-    #include "../constants.qh"
-       #include "../triggers/subs.qh"
-    #include "../util.qh"
-    #include <server/weapons/csqcprojectile.qh>
-    #include <server/autocvars.qh>
-    #include <server/constants.qh>
-    #include <server/defs.qh>
-    #include "../deathtypes/all.qh"
-    #include "../turrets/sv_turrets.qh"
-    #include "../vehicles/all.qh"
-    #include "../mapinfo.qh"
-    #include <server/anticheat.qh>
-#endif
-
-#ifdef SVQC
-float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax)
-{
-       if (IS_PLAYER(player) && !IS_DEAD(player))
-       {
-               TDEATHLOOP(org)
-               {
-               #ifdef SVQC
-                       if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
-               #endif
-                               if(IS_PLAYER(head))
-                                       if(!IS_DEAD(head))
-                                               return 1;
-               }
-       }
-       return 0;
-}
-
-void trigger_teleport_link(entity this);
-
-void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax)
-{
-       TDEATHLOOP(player.origin)
-       {
-               if (IS_PLAYER(player) && player.health >= 1)
-               {
-                       if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
-                       {
-                               if(IS_PLAYER(head))
-                                       if(head.health >= 1)
-                                               ++tdeath_hit;
-                               Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, head.origin, '0 0 0');
-                       }
-               }
-               else // dead bodies and monsters gib themselves instead of telefragging
-                       Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, telefragger.origin, '0 0 0');
-       }
-}
-
-void spawn_tdeath(vector v0, entity e, vector v)
-{
-       tdeath(e, e, e, '0 0 0', '0 0 0');
-}
-#endif
-
-void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
-{
-       entity telefragger;
-       vector from;
-
-       if(teleporter.owner)
-               telefragger = teleporter.owner;
-       else
-               telefragger = player;
-
-       makevectors (to_angles);
-
-#ifdef SVQC
-       if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
-       {
-               if(teleporter.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
-               {
-                       if(tflags & TELEPORT_FLAG_SOUND)
-                       {
-                               string thesound = SND(TELEPORT);
-                               if(teleporter.noise != "")
-                               {
-                                       RandomSelection_Init();
-                                       FOREACH_WORD(teleporter.noise, true,
-                                       {
-                                               RandomSelection_AddString(it, 1, 1);
-                                       });
-                                       thesound = RandomSelection_chosen_string;
-                               }
-                               _sound (player, CH_TRIGGER, thesound, VOL_BASE, ATTEN_NORM);
-                       }
-                       if(tflags & TELEPORT_FLAG_PARTICLES)
-                       {
-                               Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
-                               Send_Effect(EFFECT_TELEPORT, to + v_forward * 32, '0 0 0', 1);
-                       }
-                       teleporter.pushltime = time + 0.2;
-               }
-       }
-#endif
-
-       // Relocate the player
-       // assuming to allows PL_MIN to PL_MAX box and some more
-#ifdef SVQC
-       from = player.origin;
-       setorigin(player, to);
-       player.oldorigin = to; // don't undo the teleport by unsticking
-       player.angles = to_angles;
-       player.fixangle = true;
-       player.velocity = to_velocity;
-       BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
-
-       makevectors(player.angles);
-       Reset_ArcBeam(player, v_forward);
-       UpdateCSQCProjectileAfterTeleport(player);
-       UpdateItemAfterTeleport(player);
-#elif defined(CSQC)
-       from = player.origin;
-       setorigin(player, to);
-       player.angles = to_angles;
-       player.velocity = to_velocity;
-       UNSET_ONGROUND(player);
-       player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
-       player.csqcmodel_teleported = 1;
-       player.v_angle = to_angles;
-
-       if(player == csqcplayer) // not for anything but the main player
-       {
-               setproperty(VF_ANGLES, player.angles);
-               setproperty(VF_CL_VIEWANGLES, player.angles);
-       }
-#endif
-
-#ifdef SVQC
-       if(IS_PLAYER(player))
-       {
-               if(tflags & TELEPORT_FLAG_TDEATH)
-                       if(player.takedamage && !IS_DEAD(player) && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
-                               tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
-
-               // player no longer is on ground
-               UNSET_ONGROUND(player);
-
-               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
-               player.oldvelocity = player.velocity;
-
-               // reset tracking of who pushed you into a hazard (for kill credit)
-               if(teleporter.owner)
-               {
-                       player.pusher = teleporter.owner;
-                       player.pushltime = time + autocvar_g_maxpushtime;
-                       player.istypefrag = PHYS_INPUT_BUTTON_CHAT(player);
-               }
-               else
-               {
-                       player.pushltime = 0;
-                       player.istypefrag = 0;
-               }
-
-               player.lastteleporttime = time;
-               player.lastteleport_origin = from;
-       }
-#endif
-}
-
-entity Simple_TeleportPlayer(entity teleporter, entity player)
-{
-       vector locout;
-       entity e = NULL;
-
-       // Find the output teleporter
-       if(teleporter.enemy)
-       {
-               e = teleporter.enemy;
-       }
-       else
-       {
-               // sorry CSQC, random stuff ain't gonna happen
-#ifdef SVQC
-               RandomSelection_Init();
-               FOREACH_ENTITY_STRING(targetname, teleporter.target,
-               {
-                       bool p = true;
-                       if(STAT(TELEPORT_TELEFRAG_AVOID, player))
-                       {
-                       #ifdef SVQC
-                               locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
-                       #elif defined(CSQC)
-                               locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
-                       #endif
-                               if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
-                                       p = false;
-                       }
-                       RandomSelection_AddEnt(it, (it.cnt ? it.cnt : 1), p);
-               });
-               e = RandomSelection_chosen_ent;
-#endif
-       }
-
-#ifdef SVQC
-       if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
-#elif defined(CSQC)
-       if(!e) { LOG_INFO("Teleport destination could not be found from CSQC."); }
-#endif
-
-       makevectors(e.mangle);
-
-       if(e.speed)
-               if(vdist(player.velocity, >, e.speed))
-                       player.velocity = normalize(player.velocity) * max(0, e.speed);
-
-       if(STAT(TELEPORT_MAXSPEED, player))
-               if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
-                       player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
-
-       locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
-
-       TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
-
-       return e;
-}
-
-void teleport_findtarget(entity this)
-{
-       bool istrigger = (this.solid == SOLID_TRIGGER);
-
-       int n = 0;
-       for(entity e = NULL; (e = find(e, targetname, this.target)); )
-       {
-               ++n;
-#ifdef SVQC
-               if(e.move_movetype == MOVETYPE_NONE)
-               {
-                       entity tracetest_ent = spawn();
-                       setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
-                       tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-                       waypoint_spawnforteleporter(this, e.origin, 0, tracetest_ent);
-                       delete(tracetest_ent);
-               }
-               if(e.classname != "info_teleport_destination")
-                       LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.");
-#endif
-       }
-
-       if(n == 0)
-       {
-               // no dest!
-               objerror (this, "Teleporter with nonexistant target");
-               return;
-       }
-       else if(n == 1)
-       {
-               // exactly one dest - bots love that
-               this.enemy = find(NULL, targetname, this.target);
-       }
-       else
-       {
-               // have to use random selection every single time
-               this.enemy = NULL;
-       }
-
-       // now enable touch
-       if(istrigger)
-               settouch(this, Teleport_Touch);
-#ifdef SVQC
-       if(istrigger)
-               trigger_teleport_link(this);
-#endif
-}
-
-entity Teleport_Find(vector mi, vector ma)
-{
-       IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
-       {
-               return it;
-       });
-       return NULL;
-}
-
-void WarpZone_PostTeleportPlayer_Callback(entity pl)
-{
-#ifdef SVQC
-       makevectors(pl.angles);
-       Reset_ArcBeam(pl, v_forward);
-       UpdateCSQCProjectileAfterTeleport(pl);
-       UpdateItemAfterTeleport(pl);
-    if (IS_PLAYER(pl)) anticheat_fixangle(pl);
-#endif
-       // "disown" projectiles after teleport
-       if(pl.owner)
-       if(pl.owner == pl.realowner)
-       {
-       #ifdef SVQC
-               if(!(pl.flags & FL_PROJECTILE))
-       #elif defined(CSQC)
-               if(!(pl.flags & BIT(15))) // FL_PROJECTILE
-       #endif
-                       LOG_INFO("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".");
-               pl.owner = NULL;
-       }
-       if(IS_PLAYER(pl))
-       {
-               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
-       #ifdef SVQC
-               pl.oldvelocity = pl.velocity;
-       #endif
-       }
-}
diff --git a/qcsrc/common/triggers/teleporters.qh b/qcsrc/common/triggers/teleporters.qh
deleted file mode 100644 (file)
index 6f5b2b5..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#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;
-const float TELEPORT_FLAG_TDEATH = 4;
-const float TELEPORT_FLAG_FORCE_TDEATH = 8;
-
-#define TELEPORT_FLAGS_WARPZONE   0
-#define TELEPORT_FLAGS_PORTAL     (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH | TELEPORT_FLAG_FORCE_TDEATH)
-#define TELEPORT_FLAGS_TELEPORTER (TELEPORT_FLAG_SOUND | TELEPORT_FLAG_PARTICLES | TELEPORT_FLAG_TDEATH)
-
-// types for .teleportable entity setting
-const float TELEPORT_NORMAL = 1; // play sounds/effects etc
-const float TELEPORT_SIMPLE = 2; // only do teleport, nothing special
-
-entity Simple_TeleportPlayer(entity teleporter, entity player);
-
-void Teleport_Touch(entity this, entity toucher);
-
-void teleport_findtarget(entity this);
-
-entity Teleport_Find(vector mi, vector ma);
-
-void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags);
-
-#ifdef SVQC
-
-void trigger_teleport_use(entity this, entity actor, entity trigger);
-
-#define TDEATHLOOP(o) \
-       entity head; \
-       vector deathmin; \
-       vector deathmax; \
-       float deathradius; \
-       deathmin = (o) + player.mins; \
-       deathmax = (o) + player.maxs; \
-       if(telefragmin != telefragmax) \
-       { \
-               if(deathmin.x > telefragmin.x) deathmin.x = telefragmin.x; \
-               if(deathmin.y > telefragmin.y) deathmin.y = telefragmin.y; \
-               if(deathmin.z > telefragmin.z) deathmin.z = telefragmin.z; \
-               if(deathmax.x < telefragmax.x) deathmax.x = telefragmax.x; \
-               if(deathmax.y < telefragmax.y) deathmax.y = telefragmax.y; \
-               if(deathmax.z < telefragmax.z) deathmax.z = telefragmax.z; \
-       } \
-       deathradius = max(vlen(deathmin), vlen(deathmax)); \
-       for(head = findradius(o, deathradius); head; head = head.chain) \
-               if(head != player) \
-                       if(head.takedamage) \
-                               if(boxesoverlap(deathmin, deathmax, head.absmin, head.absmax))
-
-float check_tdeath(entity player, vector org, vector telefragmin, vector telefragmax);
-float tdeath_hit;
-void tdeath(entity player, entity teleporter, entity telefragger, vector telefragmin, vector telefragmax);
-
-void spawn_tdeath(vector v0, entity e, vector v);
-
-void Reset_ArcBeam(entity player, vector forward);
-
-#endif
-
-void WarpZone_PostTeleportPlayer_Callback(entity pl);
-
-#ifdef CSQC
-.entity realowner;
-#endif
diff --git a/qcsrc/common/triggers/trigger/_mod.inc b/qcsrc/common/triggers/trigger/_mod.inc
deleted file mode 100644 (file)
index 05a496e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/trigger/counter.qc>
-#include <common/triggers/trigger/delay.qc>
-#include <common/triggers/trigger/disablerelay.qc>
-#include <common/triggers/trigger/flipflop.qc>
-#include <common/triggers/trigger/gamestart.qc>
-#include <common/triggers/trigger/gravity.qc>
-#include <common/triggers/trigger/heal.qc>
-#include <common/triggers/trigger/hurt.qc>
-#include <common/triggers/trigger/impulse.qc>
-#include <common/triggers/trigger/include.qc>
-#include <common/triggers/trigger/jumppads.qc>
-#include <common/triggers/trigger/keylock.qc>
-#include <common/triggers/trigger/magicear.qc>
-#include <common/triggers/trigger/monoflop.qc>
-#include <common/triggers/trigger/multi.qc>
-#include <common/triggers/trigger/multivibrator.qc>
-#include <common/triggers/trigger/relay.qc>
-#include <common/triggers/trigger/relay_activators.qc>
-#include <common/triggers/trigger/relay_if.qc>
-#include <common/triggers/trigger/relay_teamcheck.qc>
-#include <common/triggers/trigger/secret.qc>
-#include <common/triggers/trigger/swamp.qc>
-#include <common/triggers/trigger/teleport.qc>
-#include <common/triggers/trigger/viewloc.qc>
diff --git a/qcsrc/common/triggers/trigger/_mod.qh b/qcsrc/common/triggers/trigger/_mod.qh
deleted file mode 100644 (file)
index 2c7477b..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// generated file; do not modify
-#include <common/triggers/trigger/counter.qh>
-#include <common/triggers/trigger/delay.qh>
-#include <common/triggers/trigger/disablerelay.qh>
-#include <common/triggers/trigger/flipflop.qh>
-#include <common/triggers/trigger/gamestart.qh>
-#include <common/triggers/trigger/gravity.qh>
-#include <common/triggers/trigger/heal.qh>
-#include <common/triggers/trigger/hurt.qh>
-#include <common/triggers/trigger/impulse.qh>
-#include <common/triggers/trigger/include.qh>
-#include <common/triggers/trigger/jumppads.qh>
-#include <common/triggers/trigger/keylock.qh>
-#include <common/triggers/trigger/magicear.qh>
-#include <common/triggers/trigger/monoflop.qh>
-#include <common/triggers/trigger/multi.qh>
-#include <common/triggers/trigger/multivibrator.qh>
-#include <common/triggers/trigger/relay.qh>
-#include <common/triggers/trigger/relay_activators.qh>
-#include <common/triggers/trigger/relay_if.qh>
-#include <common/triggers/trigger/relay_teamcheck.qh>
-#include <common/triggers/trigger/secret.qh>
-#include <common/triggers/trigger/swamp.qh>
-#include <common/triggers/trigger/teleport.qh>
-#include <common/triggers/trigger/viewloc.qh>
diff --git a/qcsrc/common/triggers/trigger/counter.qc b/qcsrc/common/triggers/trigger/counter.qc
deleted file mode 100644 (file)
index 87c046b..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#include "counter.qh"
-#ifdef SVQC
-void counter_reset(entity this);
-
-void counter_use(entity this, entity actor, entity trigger)
-{
-       this.count -= 1;
-       if (this.count < 0)
-               return;
-
-       bool doactivate = (this.spawnflags & 4);
-
-       if (this.count == 0)
-       {
-               if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE))
-                       Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COMPLETED);
-
-               doactivate = true;
-
-               if(this.respawntime)
-               {
-                       setthink(this, counter_reset);
-                       this.nextthink = time + this.respawntime;
-               }
-       }
-       else
-       {
-               if(IS_PLAYER(actor) && !(this.spawnflags & SPAWNFLAG_NOMESSAGE))
-               {
-                       if(this.count >= 4)
-                               Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER);
-                       else
-                               Send_Notification(NOTIF_ONE, actor, MSG_CENTER, CENTER_SEQUENCE_COUNTER_FEWMORE, this.count);
-               }
-       }
-
-       if(doactivate)
-               SUB_UseTargets(this, actor, trigger);
-}
-
-void counter_reset(entity this)
-{
-       setthink(this, func_null);
-       this.nextthink = 0;
-       this.count = this.cnt;
-}
-
-/*QUAKED spawnfunc_trigger_counter (.5 .5 .5) ? nomessage
-Acts as an intermediary for an action that takes multiple inputs.
-
-If nomessage is not set, it will print "1 more.. " etc when triggered and "sequence complete" when finished.
-
-If respawntime is set, it will re-enable itself after the time once the sequence has been completed
-
-After the counter has been triggered "count" times (default 2), it will fire all of it's targets and remove itself.
-*/
-spawnfunc(trigger_counter)
-{
-       if (!this.count)
-               this.count = 2;
-       this.cnt = this.count;
-
-       this.use = counter_use;
-       this.reset = counter_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/counter.qh b/qcsrc/common/triggers/trigger/counter.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/delay.qc b/qcsrc/common/triggers/trigger/delay.qc
deleted file mode 100644 (file)
index 2cd4cfd..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "delay.qh"
-#ifdef SVQC
-void delay_delayeduse(entity this)
-{
-       SUB_UseTargets(this, this.enemy, this.goalentity);
-       this.enemy = this.goalentity = NULL;
-}
-
-void delay_use(entity this, entity actor, entity trigger)
-{
-       this.enemy = actor;
-       this.goalentity = trigger;
-       setthink(this, delay_delayeduse);
-       this.nextthink = time + this.wait;
-}
-
-void delay_reset(entity this)
-{
-       this.enemy = this.goalentity = NULL;
-       setthink(this, func_null);
-       this.nextthink = 0;
-}
-
-spawnfunc(trigger_delay)
-{
-    if(!this.wait)
-        this.wait = 1;
-
-    this.use = delay_use;
-    this.reset = delay_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/delay.qh b/qcsrc/common/triggers/trigger/delay.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/disablerelay.qc b/qcsrc/common/triggers/trigger/disablerelay.qc
deleted file mode 100644 (file)
index eee61c9..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#include "disablerelay.qh"
-#ifdef SVQC
-void trigger_disablerelay_use(entity this, entity actor, entity trigger)
-{
-       int a = 0, b = 0;
-
-       for(entity e = NULL; (e = find(e, targetname, this.target)); )
-       {
-               if(e.use == SUB_UseTargets)
-               {
-                       e.use = SUB_DontUseTargets;
-                       ++a;
-               }
-               else if(e.use == SUB_DontUseTargets)
-               {
-                       e.use = SUB_UseTargets;
-                       ++b;
-               }
-       }
-
-       if((!a) == (!b))
-               LOG_INFO("Invalid use of trigger_disablerelay: ", ftos(a), " relays were on, ", ftos(b), " relays were off!");
-}
-
-spawnfunc(trigger_disablerelay)
-{
-       this.use = trigger_disablerelay_use;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/disablerelay.qh b/qcsrc/common/triggers/trigger/disablerelay.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/flipflop.qc b/qcsrc/common/triggers/trigger/flipflop.qc
deleted file mode 100644 (file)
index af212ff..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-#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
-*/
-void flipflop_use(entity this, entity actor, entity trigger)
-{
-    this.state = !this.state;
-    if(this.state)
-        SUB_UseTargets(this, actor, trigger);
-}
-
-spawnfunc(trigger_flipflop)
-{
-    if(this.spawnflags & 1)
-        this.state = 1;
-    this.use = flipflop_use;
-    this.reset = spawnfunc_trigger_flipflop; // perfect resetter
-}
-
-#endif
diff --git a/qcsrc/common/triggers/trigger/flipflop.qh b/qcsrc/common/triggers/trigger/flipflop.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/gamestart.qc b/qcsrc/common/triggers/trigger/gamestart.qc
deleted file mode 100644 (file)
index 72d76d1..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-#include "gamestart.qh"
-#ifdef SVQC
-void gamestart_use(entity this, entity actor, entity trigger)
-{
-       SUB_UseTargets(this, this, trigger);
-       delete(this);
-}
-
-void gamestart_use_this(entity this)
-{
-       gamestart_use(this, NULL, NULL);
-}
-
-spawnfunc(trigger_gamestart)
-{
-       this.use = gamestart_use;
-       this.reset2 = spawnfunc_trigger_gamestart;
-
-       if(this.wait)
-       {
-               setthink(this, adaptor_think2use);
-               this.nextthink = game_starttime + this.wait;
-       }
-       else
-               InitializeEntity(this, gamestart_use_this, INITPRIO_FINDTARGET);
-}
-
-#endif
diff --git a/qcsrc/common/triggers/trigger/gamestart.qh b/qcsrc/common/triggers/trigger/gamestart.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/gravity.qc b/qcsrc/common/triggers/trigger/gravity.qc
deleted file mode 100644 (file)
index 3ea1562..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-#include "gravity.qh"
-#ifdef SVQC
-.entity trigger_gravity_check;
-void trigger_gravity_remove(entity own)
-{
-       if(own.trigger_gravity_check.owner == own)
-       {
-               UpdateCSQCProjectile(own);
-               own.gravity = own.trigger_gravity_check.gravity;
-               delete(own.trigger_gravity_check);
-       }
-       else
-               backtrace("Removing a trigger_gravity_check with no valid owner");
-       own.trigger_gravity_check = NULL;
-}
-void trigger_gravity_check_think(entity this)
-{
-       // This spawns when a player enters the gravity zone and checks if he left.
-       // Each frame, this.count is set to 2 by trigger_gravity_touch() and decreased by 1 here.
-       // It the player has left the gravity trigger, this will be allowed to reach 0 and indicate that.
-       if(this.count <= 0)
-       {
-               if(this.owner.trigger_gravity_check == this)
-                       trigger_gravity_remove(this.owner);
-               else
-                       delete(this);
-               return;
-       }
-       else
-       {
-               this.count -= 1;
-               this.nextthink = time;
-       }
-}
-
-void trigger_gravity_use(entity this, entity actor, entity trigger)
-{
-       this.state = !this.state;
-}
-
-void trigger_gravity_touch(entity this, entity toucher)
-{
-       float g;
-
-       if(this.state != true)
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       g = this.gravity;
-
-       if (!(this.spawnflags & 1))
-       {
-               if(toucher.trigger_gravity_check)
-               {
-                       if(this == toucher.trigger_gravity_check.enemy)
-                       {
-                               // same?
-                               toucher.trigger_gravity_check.count = 2; // gravity one more frame...
-                               return;
-                       }
-
-                       // compare prio
-                       if(this.cnt > toucher.trigger_gravity_check.enemy.cnt)
-                               trigger_gravity_remove(toucher);
-                       else
-                               return;
-               }
-               toucher.trigger_gravity_check = spawn();
-               toucher.trigger_gravity_check.enemy = this;
-               toucher.trigger_gravity_check.owner = toucher;
-               toucher.trigger_gravity_check.gravity = toucher.gravity;
-               setthink(toucher.trigger_gravity_check, trigger_gravity_check_think);
-               toucher.trigger_gravity_check.nextthink = time;
-               toucher.trigger_gravity_check.count = 2;
-               if(toucher.gravity)
-                       g *= toucher.gravity;
-       }
-
-       if (toucher.gravity != g)
-       {
-               toucher.gravity = g;
-               if(this.noise != "")
-                       _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-               UpdateCSQCProjectile(this.owner);
-       }
-}
-
-spawnfunc(trigger_gravity)
-{
-       if(this.gravity == 1)
-               return;
-
-       EXACTTRIGGER_INIT;
-       settouch(this, trigger_gravity_touch);
-       if(this.noise != "")
-               precache_sound(this.noise);
-
-       this.state = true;
-       IFTARGETED
-       {
-               this.use = trigger_gravity_use;
-               if(this.spawnflags & 2)
-                       this.state = false;
-       }
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/gravity.qh b/qcsrc/common/triggers/trigger/gravity.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/heal.qc b/qcsrc/common/triggers/trigger/heal.qc
deleted file mode 100644 (file)
index f2345e8..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-#include "heal.qh"
-#ifdef SVQC
-.float triggerhealtime;
-void trigger_heal_touch(entity this, entity toucher)
-{
-       if (this.active != ACTIVE_ACTIVE)
-               return;
-
-       // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
-       if (toucher.iscreature)
-       {
-               if (toucher.takedamage)
-               if (!IS_DEAD(toucher))
-               if (toucher.triggerhealtime < time)
-               {
-                       bool is_trigger = !boolean(!this.nottargeted && this.targetname != "");
-                       if(is_trigger)
-                               EXACTTRIGGER_TOUCH(this, toucher);
-                       if(this.delay > 0)
-                               toucher.triggerhealtime = time + this.delay;
-
-                       bool playthesound = (this.spawnflags & 4);
-                       if (toucher.health < this.max_health)
-                       {
-                               playthesound = true;
-                               toucher.health = min(toucher.health + this.health, this.max_health);
-                               toucher.pauserothealth_finished = max(toucher.pauserothealth_finished, time + autocvar_g_balance_pause_health_rot);
-                       }
-
-                       if(playthesound)
-                               _sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-               }
-       }
-}
-
-void trigger_heal_use(entity this, entity actor, entity trigger)
-{
-       trigger_heal_touch(this, actor);
-}
-
-void trigger_heal_init(entity this)
-{
-       this.active = ACTIVE_ACTIVE;
-       if(!this.delay)
-               this.delay = 1;
-       if(!this.health)
-               this.health = 10;
-       if(!this.max_health)
-               this.max_health = 200; // max health topoff for field
-       if(this.noise == "")
-               this.noise = "misc/mediumhealth.wav";
-       precache_sound(this.noise);
-}
-
-spawnfunc(trigger_heal)
-{
-       EXACTTRIGGER_INIT;
-       settouch(this, trigger_heal_touch);
-       trigger_heal_init(this);
-}
-
-spawnfunc(target_heal)
-{
-       this.use = trigger_heal_use;
-       trigger_heal_init(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/heal.qh b/qcsrc/common/triggers/trigger/heal.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/hurt.qc b/qcsrc/common/triggers/trigger/hurt.qc
deleted file mode 100644 (file)
index 9c09f92..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-#include "hurt.qh"
-#ifdef SVQC
-void trigger_hurt_use(entity this, entity actor, entity trigger)
-{
-       if(IS_PLAYER(actor))
-               this.enemy = actor;
-       else
-               this.enemy = NULL; // let's just destroy it, if taking over is too much work
-}
-
-.float triggerhurttime;
-void trigger_hurt_touch(entity this, entity toucher)
-{
-       if (this.active != ACTIVE_ACTIVE)
-               return;
-
-       if(this.team)
-               if(((this.spawnflags & 4) == 0) == (this.team != toucher.team))
-                       return;
-
-       // only do the EXACTTRIGGER_TOUCH checks when really needed (saves some cpu)
-       if (toucher.iscreature)
-       {
-               if (toucher.takedamage)
-               if (toucher.triggerhurttime < time)
-               {
-                       EXACTTRIGGER_TOUCH(this, toucher);
-                       toucher.triggerhurttime = time + 1;
-
-                       entity own;
-                       own = this.enemy;
-                       if (!IS_PLAYER(own))
-                       {
-                               own = this;
-                               this.enemy = NULL; // I still hate you all
-                       }
-
-                       Damage (toucher, this, own, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, toucher.origin, '0 0 0');
-               }
-       }
-       else if(toucher.damagedbytriggers)
-       {
-               if(toucher.takedamage)
-               {
-                       EXACTTRIGGER_TOUCH(this, toucher);
-                       Damage(toucher, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, toucher.origin, '0 0 0');
-               }
-       }
-
-       return;
-}
-
-/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
-Any object touching this will be hurt
-set dmg to damage amount
-defalt dmg = 5
-*/
-.entity trigger_hurt_next;
-entity trigger_hurt_last;
-entity trigger_hurt_first;
-spawnfunc(trigger_hurt)
-{
-       EXACTTRIGGER_INIT;
-       this.active = ACTIVE_ACTIVE;
-       settouch(this, trigger_hurt_touch);
-       this.use = trigger_hurt_use;
-       this.enemy = world; // I hate you all
-       if (!this.dmg)
-               this.dmg = 1000;
-       if (this.message == "")
-               this.message = "was in the wrong place";
-       if (this.message2 == "")
-               this.message2 = "was thrown into a world of hurt by";
-       // this.message = "someone like %s always gets wrongplaced";
-
-       if(!trigger_hurt_first)
-               trigger_hurt_first = this;
-       if(trigger_hurt_last)
-               trigger_hurt_last.trigger_hurt_next = this;
-       trigger_hurt_last = this;
-}
-
-float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
-{
-       entity th;
-
-       for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
-               if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
-                       return true;
-
-       return false;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/hurt.qh b/qcsrc/common/triggers/trigger/hurt.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/impulse.qc b/qcsrc/common/triggers/trigger/impulse.qc
deleted file mode 100644 (file)
index 4be6e86..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-#include "impulse.qh"
-// targeted (directional) mode
-void trigger_impulse_touch1(entity this, entity toucher)
-{
-       entity targ;
-       float pushdeltatime;
-       float str;
-
-       if (this.active != ACTIVE_ACTIVE)
-               return;
-
-       if (!isPushable(toucher))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       targ = find(NULL, targetname, this.target);
-       if(!targ)
-       {
-               objerror(this, "trigger_force without a (valid) .target!\n");
-               delete(this);
-               return;
-       }
-
-       str = min(this.radius, vlen(this.origin - toucher.origin));
-
-       if(this.falloff == 1)
-               str = (str / this.radius) * this.strength;
-       else if(this.falloff == 2)
-               str = (1 - (str / this.radius)) * this.strength;
-       else
-               str = this.strength;
-
-       pushdeltatime = time - toucher.lastpushtime;
-       if (pushdeltatime > 0.15) pushdeltatime = 0;
-       toucher.lastpushtime = time;
-       if(!pushdeltatime) return;
-
-       if(this.spawnflags & 64)
-       {
-               float addspeed = str - toucher.velocity * normalize(targ.origin - this.origin);
-               if (addspeed > 0)
-               {
-                       float accelspeed = min(8 * pushdeltatime * str, addspeed);
-                       toucher.velocity += accelspeed * normalize(targ.origin - this.origin);
-               }
-       }
-       else
-               toucher.velocity = toucher.velocity + normalize(targ.origin - this.origin) * str * pushdeltatime;
-
-       UNSET_ONGROUND(toucher);
-
-#ifdef SVQC
-       UpdateCSQCProjectile(toucher);
-#endif
-}
-
-// Directionless (accelerator/decelerator) mode
-void trigger_impulse_touch2(entity this, entity toucher)
-{
-       float pushdeltatime;
-
-       if (this.active != ACTIVE_ACTIVE)
-               return;
-
-       if (!isPushable(toucher))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       pushdeltatime = time - toucher.lastpushtime;
-       if (pushdeltatime > 0.15) pushdeltatime = 0;
-       toucher.lastpushtime = time;
-       if(!pushdeltatime) return;
-
-       // div0: ticrate independent, 1 = identity (not 20)
-       toucher.velocity = toucher.velocity * (this.strength ** pushdeltatime);
-
-#ifdef SVQC
-       UpdateCSQCProjectile(toucher);
-#endif
-}
-
-// Spherical (gravity/repulsor) mode
-void trigger_impulse_touch3(entity this, entity toucher)
-{
-       float pushdeltatime;
-       float str;
-
-       if (this.active != ACTIVE_ACTIVE)
-               return;
-
-       if (!isPushable(toucher))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       pushdeltatime = time - toucher.lastpushtime;
-       if (pushdeltatime > 0.15) pushdeltatime = 0;
-       toucher.lastpushtime = time;
-       if(!pushdeltatime) return;
-
-       setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
-
-       str = min(this.radius, vlen(this.origin - toucher.origin));
-
-       if(this.falloff == 1)
-               str = (1 - str / this.radius) * this.strength; // 1 in the inside
-       else if(this.falloff == 2)
-               str = (str / this.radius) * this.strength; // 0 in the inside
-       else
-               str = this.strength;
-
-       toucher.velocity = toucher.velocity + normalize(toucher.origin - this.origin) * str * pushdeltatime;
-
-#ifdef SVQC
-       UpdateCSQCProjectile(toucher);
-#endif
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_IMPULSE)
-
-/*QUAKED spawnfunc_trigger_impulse (.5 .5 .5) ?
--------- KEYS --------
-target : If this is set, this points to the spawnfunc_target_position to which the player will get pushed.
-                If not, this trigger acts like a damper/accelerator field.
-
-strength : This is how mutch force to add in the direction of .target each second
-                  when .target is set. If not, this is hoe mutch to slow down/accelerate
-                  someting cought inside this trigger. (1=no change, 0,5 half speed rougthly each tic, 2 = doubble)
-
-radius   : If set, act as a spherical device rather then a liniar one.
-
-falloff : 0 = none, 1 = liniar, 2 = inverted liniar
-
--------- NOTES --------
-Use a brush textured with common/origin in the trigger entity to determine the origin of the force
-in directional and sperical mode. For damper/accelerator mode this is not nessesary (and has no effect).
-*/
-#ifdef SVQC
-bool trigger_impulse_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_IMPULSE);
-
-       WriteInt24_t(MSG_ENTITY, this.spawnflags);
-       WriteCoord(MSG_ENTITY, this.radius);
-       WriteCoord(MSG_ENTITY, this.strength);
-       WriteByte(MSG_ENTITY, this.falloff);
-       WriteByte(MSG_ENTITY, this.active);
-
-       trigger_common_write(this, true);
-
-       return true;
-}
-
-void trigger_impulse_link(entity this)
-{
-       trigger_link(this, trigger_impulse_send);
-}
-
-spawnfunc(trigger_impulse)
-{
-       this.active = ACTIVE_ACTIVE;
-
-       trigger_init(this);
-
-       if(this.radius)
-       {
-               if(!this.strength) this.strength = 2000 * autocvar_g_triggerimpulse_radial_multiplier;
-               setorigin(this, this.origin);
-               setsize(this, '-1 -1 -1' * this.radius,'1 1 1' * this.radius);
-               settouch(this, trigger_impulse_touch3);
-       }
-       else
-       {
-               if(this.target)
-               {
-                       if(!this.strength) this.strength = 950 * autocvar_g_triggerimpulse_directional_multiplier;
-                       settouch(this, trigger_impulse_touch1);
-               }
-               else
-               {
-                       if(!this.strength) this.strength = 0.9;
-                       this.strength = (this.strength ** autocvar_g_triggerimpulse_accel_power) * autocvar_g_triggerimpulse_accel_multiplier;
-                       settouch(this, trigger_impulse_touch2);
-               }
-       }
-
-       trigger_impulse_link(this);
-}
-#elif defined(CSQC)
-NET_HANDLE(ENT_CLIENT_TRIGGER_IMPULSE, bool isnew)
-{
-       this.spawnflags = ReadInt24_t();
-       this.radius = ReadCoord();
-       this.strength = ReadCoord();
-       this.falloff = ReadByte();
-       this.active = ReadByte();
-
-       trigger_common_read(this, true);
-       return = true;
-
-       this.classname = "trigger_impulse";
-       this.solid = SOLID_TRIGGER;
-       this.entremove = trigger_remove_generic;
-       this.move_time = time;
-
-       if (this.radius) { settouch(this, trigger_impulse_touch3); }
-       else if (this.target) { settouch(this, trigger_impulse_touch1); }
-       else { settouch(this, trigger_impulse_touch2); }
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/impulse.qh b/qcsrc/common/triggers/trigger/impulse.qh
deleted file mode 100644 (file)
index a6961f5..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#pragma once
-
-// tZorks trigger impulse / gravity
-.float radius;
-.float falloff;
-.float strength;
-.float lastpushtime;
diff --git a/qcsrc/common/triggers/trigger/include.qc b/qcsrc/common/triggers/trigger/include.qc
deleted file mode 100644 (file)
index 1c762fc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "include.qh"
-
-#include "counter.qc"
-#include "delay.qc"
-#include "disablerelay.qc"
-#include "flipflop.qc"
-#include "gamestart.qc"
-#include "gravity.qc"
-#include "heal.qc"
-#include "hurt.qc"
-#include "impulse.qc"
-#include "jumppads.qc"
-#include "keylock.qc"
-#include "magicear.qc"
-#include "monoflop.qc"
-#include "multi.qc"
-#include "multivibrator.qc"
-#include "relay.qc"
-#include "relay_activators.qc"
-#include "relay_if.qc"
-#include "relay_teamcheck.qc"
-#include "secret.qc"
-#include "swamp.qc"
-#include "teleport.qc"
-#include "viewloc.qc"
diff --git a/qcsrc/common/triggers/trigger/include.qh b/qcsrc/common/triggers/trigger/include.qh
deleted file mode 100644 (file)
index 8aa6b2b..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "multi.qh"
-#include "jumppads.qh"
-#include "secret.qh"
-#include "swamp.qh"
-#include "keylock.qh"
-#include "impulse.qh"
-#include "viewloc.qh"
diff --git a/qcsrc/common/triggers/trigger/jumppads.qc b/qcsrc/common/triggers/trigger/jumppads.qc
deleted file mode 100644 (file)
index fde6e1f..0000000
+++ /dev/null
@@ -1,636 +0,0 @@
-#include "jumppads.qh"
-// TODO: split target_push and put it in the target folder
-#ifdef SVQC
-#include "jumppads.qh"
-#include <common/physics/movetypes/movetypes.qh>
-
-void trigger_push_use(entity this, entity actor, entity trigger)
-{
-       if(teamplay)
-       {
-               this.team = actor.team;
-               this.SendFlags |= 2;
-       }
-}
-#endif
-
-REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_PUSH)
-REGISTER_NET_LINKED(ENT_CLIENT_TARGET_PUSH)
-
-/*
-       trigger_push_calculatevelocity
-
-       Arguments:
-         org - origin of the object which is to be pushed
-         tgt - target entity (can be either a point or a model entity; if it is
-               the latter, its midpoint is used)
-         ht  - jump height, measured from the higher one of org and tgt's midpoint
-         pushed_entity - object that is to be pushed
-
-       Returns: velocity for the jump
- */
-vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity)
-{
-       float grav, sdist, zdist, vs, vz, jumpheight;
-       vector sdir, torg;
-
-       torg = tgt.origin + (tgt.mins + tgt.maxs) * 0.5;
-
-       grav = PHYS_GRAVITY(NULL);
-       if(pushed_entity && PHYS_ENTGRAVITY(pushed_entity))
-               grav *= PHYS_ENTGRAVITY(pushed_entity);
-
-       zdist = torg.z - org.z;
-       sdist = vlen(torg - org - zdist * '0 0 1');
-       sdir = normalize(torg - org - zdist * '0 0 1');
-
-       // how high do we need to push the player?
-       jumpheight = fabs(ht);
-       if(zdist > 0)
-               jumpheight = jumpheight + zdist;
-
-       /*
-               STOP.
-
-               You will not understand the following equations anyway...
-               But here is what I did to get them.
-
-               I used the functions
-
-                 s(t) = t * vs
-                 z(t) = t * vz - 1/2 grav t^2
-
-               and solved for:
-
-                 s(ti) = sdist
-                 z(ti) = zdist
-                 max(z, ti) = jumpheight
-
-               From these three equations, you will find the three parameters vs, vz
-               and ti.
-        */
-
-       // push him so high...
-       vz = sqrt(fabs(2 * grav * jumpheight)); // NOTE: sqrt(positive)!
-
-       // we start with downwards velocity only if it's a downjump and the jump apex should be outside the jump!
-       if(ht < 0)
-               if(zdist < 0)
-                       vz = -vz;
-
-       vector solution;
-       solution = solve_quadratic(0.5 * grav, -vz, zdist); // equation "z(ti) = zdist"
-       // ALWAYS solvable because jumpheight >= zdist
-       if(!solution.z)
-               solution_y = solution.x; // just in case it is not solvable due to roundoff errors, assume two equal solutions at their center (this is mainly for the usual case with ht == 0)
-       if(zdist == 0)
-               solution_x = solution.y; // solution_x is 0 in this case, so don't use it, but rather use solution_y (which will be sqrt(0.5 * jumpheight / grav), actually)
-
-       float flighttime;
-       if(zdist < 0)
-       {
-               // down-jump
-               if(ht < 0)
-               {
-                       // almost straight line type
-                       // jump apex is before the jump
-                       // we must take the larger one
-                       flighttime = solution.y;
-               }
-               else
-               {
-                       // regular jump
-                       // jump apex is during the jump
-                       // we must take the larger one too
-                       flighttime = solution.y;
-               }
-       }
-       else
-       {
-               // up-jump
-               if(ht < 0)
-               {
-                       // almost straight line type
-                       // jump apex is after the jump
-                       // we must take the smaller one
-                       flighttime = solution.x;
-               }
-               else
-               {
-                       // regular jump
-                       // jump apex is during the jump
-                       // we must take the larger one
-                       flighttime = solution.y;
-               }
-       }
-       vs = sdist / flighttime;
-
-       // finally calculate the velocity
-       return sdir * vs + '0 0 1' * vz;
-}
-
-bool jumppad_push(entity this, entity targ)
-{
-       if (!isPushable(targ))
-               return false;
-
-       if(this.enemy)
-       {
-               targ.velocity = trigger_push_calculatevelocity(targ.origin, this.enemy, this.height, targ);
-       }
-       else if(this.target && this.target != "")
-       {
-               entity e;
-               RandomSelection_Init();
-               for(e = NULL; (e = find(e, targetname, this.target)); )
-               {
-                       if(e.cnt)
-                               RandomSelection_AddEnt(e, e.cnt, 1);
-                       else
-                               RandomSelection_AddEnt(e, 1, 1);
-               }
-               targ.velocity = trigger_push_calculatevelocity(targ.origin, RandomSelection_chosen_ent, this.height, targ);
-       }
-       else
-       {
-               targ.velocity = this.movedir;
-       }
-
-       UNSET_ONGROUND(targ);
-
-#ifdef CSQC
-       if (targ.flags & FL_PROJECTILE)
-       {
-               targ.angles = vectoangles (targ.velocity);
-               switch(targ.move_movetype)
-               {
-                       case MOVETYPE_FLY:
-                               set_movetype(targ, MOVETYPE_TOSS);
-                               targ.gravity = 1;
-                               break;
-                       case MOVETYPE_BOUNCEMISSILE:
-                               set_movetype(targ, MOVETYPE_BOUNCE);
-                               targ.gravity = 1;
-                               break;
-               }
-       }
-#endif
-
-#ifdef SVQC
-       if (IS_PLAYER(targ))
-       {
-               // reset tracking of oldvelocity for impact damage (sudden velocity changes)
-               targ.oldvelocity = targ.velocity;
-
-               if(this.pushltime < time)  // prevent "snorring" sound when a player hits the jumppad more than once
-               {
-                       // flash when activated
-                       Send_Effect(EFFECT_JUMPPAD, targ.origin, targ.velocity, 1);
-                       _sound (targ, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-                       this.pushltime = time + 0.2;
-               }
-               if(IS_REAL_CLIENT(targ) || IS_BOT_CLIENT(targ))
-               {
-                       bool found = false;
-                       for(int i = 0; i < targ.jumppadcount && i < NUM_JUMPPADSUSED; ++i)
-                               if(targ.(jumppadsused[i]) == this)
-                                       found = true;
-                       if(!found)
-                       {
-                               targ.(jumppadsused[targ.jumppadcount % NUM_JUMPPADSUSED]) = this;
-                               targ.jumppadcount = targ.jumppadcount + 1;
-                       }
-
-                       if(IS_REAL_CLIENT(targ))
-                       {
-                               if(this.message)
-                                       centerprint(targ, this.message);
-                       }
-                       else
-                       {
-                               targ.lastteleporttime = time;
-                               targ.lastteleport_origin = targ.origin;
-                       }
-
-                       if (!IS_DEAD(targ))
-                               animdecide_setaction(targ, ANIMACTION_JUMP, true);
-               }
-               else
-                       targ.jumppadcount = 1;
-
-               // reset tracking of who pushed you into a hazard (for kill credit)
-               targ.pushltime = 0;
-               targ.istypefrag = 0;
-       }
-
-       if(this.enemy.target)
-               SUB_UseTargets(this.enemy, targ, this);
-
-       if (targ.flags & FL_PROJECTILE)
-       {
-               targ.angles = vectoangles (targ.velocity);
-               targ.com_phys_gravity_factor = 1;
-               switch(targ.move_movetype)
-               {
-                       case MOVETYPE_FLY:
-                               set_movetype(targ, MOVETYPE_TOSS);
-                               targ.gravity = 1;
-                               break;
-                       case MOVETYPE_BOUNCEMISSILE:
-                               set_movetype(targ, MOVETYPE_BOUNCE);
-                               targ.gravity = 1;
-                               break;
-               }
-               UpdateCSQCProjectile(targ);
-       }
-#endif
-
-       return true;
-}
-
-void trigger_push_touch(entity this, entity toucher)
-{
-       if (this.active == ACTIVE_NOT)
-               return;
-
-       if(this.team)
-               if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, toucher)))
-                       return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       noref bool success = jumppad_push(this, toucher);
-
-#ifdef SVQC
-       if (success && (this.spawnflags & PUSH_ONCE))
-       {
-               settouch(this, func_null);
-               setthink(this, SUB_Remove);
-               this.nextthink = time;
-       }
-#endif
-}
-
-#ifdef SVQC
-void trigger_push_link(entity this);
-void trigger_push_updatelink(entity this);
-bool trigger_push_testorigin(entity tracetest_ent, entity targ, entity jp, vector org)
-{
-       setorigin(tracetest_ent, org);
-       tracetoss(tracetest_ent, tracetest_ent);
-       if(trace_startsolid)
-               return false;
-
-       if (!jp.height)
-       {
-               // since tracetoss starting from jumppad's origin often fails when target
-               // is very close to real destination, start it directly from target's
-               // origin instead
-               vector ofs = '0 0 0';
-               if (vdist(vec2(tracetest_ent.velocity), <, autocvar_sv_maxspeed))
-                       ofs = stepheightvec;
-
-               tracetest_ent.velocity.z = 0;
-               setorigin(tracetest_ent, targ.origin + ofs);
-               tracetoss(tracetest_ent, tracetest_ent);
-               if (trace_startsolid && ofs.z)
-               {
-                       setorigin(tracetest_ent, targ.origin + ofs / 2);
-                       tracetoss(tracetest_ent, tracetest_ent);
-                       if (trace_startsolid && ofs.z)
-                       {
-                               setorigin(tracetest_ent, targ.origin);
-                               tracetoss(tracetest_ent, tracetest_ent);
-                               if (trace_startsolid)
-                                       return false;
-                       }
-               }
-       }
-       tracebox(trace_endpos, tracetest_ent.mins, tracetest_ent.maxs, trace_endpos - eZ * 1500, true, tracetest_ent);
-       return true;
-}
-#endif
-
-/// if (item != NULL) returns true if the item can be reached by using this jumppad, false otherwise
-/// if (item == NULL) tests jumppad's trajectory and eventually spawns waypoints for it (return value doesn't matter)
-bool trigger_push_test(entity this, entity item)
-{
-       // first calculate a typical start point for the jump
-       vector org = (this.absmin + this.absmax) * 0.5;
-       org.z = this.absmax.z - PL_MIN_CONST.z - 10;
-
-       if (this.target)
-       {
-               int n = 0;
-#ifdef SVQC
-               vector vel = '0 0 0';
-#endif
-               for(entity t = NULL; (t = find(t, targetname, this.target)); )
-               {
-                       ++n;
-#ifdef SVQC
-                       if(t.move_movetype != MOVETYPE_NONE)
-                               continue;
-
-                       entity e = spawn();
-                       setsize(e, PL_MIN_CONST, PL_MAX_CONST);
-                       e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-                       e.velocity = trigger_push_calculatevelocity(org, t, this.height, e);
-
-                       if(item)
-                       {
-                               setorigin(e, org);
-                               tracetoss(e, e);
-                               bool r = (trace_ent == item);
-                               delete(e);
-                               return r;
-                       }
-
-                       vel = e.velocity;
-                       vector best_target = '0 0 0';
-                       vector best_org = '0 0 0';
-                       vector best_vel = '0 0 0';
-                       bool valid_best_target = false;
-                       if (trigger_push_testorigin(e, t, this, org))
-                       {
-                               best_target = trace_endpos;
-                               best_org = org;
-                               best_vel = e.velocity;
-                               valid_best_target = true;
-                       }
-
-                       vector new_org;
-                       vector dist = t.origin - org;
-                       if (dist.x || dist.y) // if not perfectly vertical
-                       {
-                               // test trajectory with different starting points, sometimes the trajectory
-                               // starting from the jumppad origin can't reach the real destination
-                               // and destination waypoint ends up near the jumppad itself
-                               vector flatdir = normalize(dist - eZ * dist.z);
-                               vector ofs = flatdir * 0.5 * min(fabs(this.absmax.x - this.absmin.x), fabs(this.absmax.y - this.absmin.y));
-                               new_org = org + ofs;
-                               e.velocity = trigger_push_calculatevelocity(new_org, t, this.height, e);
-                               vel = e.velocity;
-                               if (vdist(vec2(e.velocity), <, autocvar_sv_maxspeed))
-                                       e.velocity = autocvar_sv_maxspeed * flatdir;
-                               if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50))
-                               {
-                                       best_target = trace_endpos;
-                                       best_org = new_org;
-                                       best_vel = vel;
-                                       valid_best_target = true;
-                               }
-                               new_org = org - ofs;
-                               e.velocity = trigger_push_calculatevelocity(new_org, t, this.height, e);
-                               vel = e.velocity;
-                               if (vdist(vec2(e.velocity), <, autocvar_sv_maxspeed))
-                                       e.velocity = autocvar_sv_maxspeed * flatdir;
-                               if (trigger_push_testorigin(e, t, this, new_org) && (!valid_best_target || trace_endpos.z > best_target.z + 50))
-                               {
-                                       best_target = trace_endpos;
-                                       best_org = new_org;
-                                       best_vel = vel;
-                                       valid_best_target = true;
-                               }
-                       }
-
-                       if (valid_best_target)
-                       {
-                               if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, best_target + PL_MIN_CONST, best_target + PL_MAX_CONST)))
-                               {
-                                       float velxy = vlen(vec2(best_vel));
-                                       float cost = vlen(vec2(t.origin - best_org)) / velxy;
-                                       if(velxy < autocvar_sv_maxspeed)
-                                               velxy = autocvar_sv_maxspeed;
-                                       cost += vlen(vec2(best_target - t.origin)) / velxy;
-                                       waypoint_spawnforteleporter(this, best_target, cost, e);
-                               }
-                       }
-                       delete(e);
-#endif
-               }
-
-               if(item)
-                       return false;
-
-               if(!n)
-               {
-                       // no dest!
-#ifdef SVQC
-                       objerror (this, "Jumppad with nonexistant target");
-#endif
-                       return false;
-               }
-               else if(n == 1)
-               {
-                       // exactly one dest - bots love that
-                       this.enemy = find(NULL, targetname, this.target);
-               }
-               else
-               {
-                       // have to use random selection every single time
-                       this.enemy = NULL;
-               }
-       }
-#ifdef SVQC
-       else
-       {
-               entity e = spawn();
-               setsize(e, PL_MIN_CONST, PL_MAX_CONST);
-               e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-               setorigin(e, org);
-               e.velocity = this.movedir;
-               tracetoss(e, e);
-               if(item)
-               {
-                       bool r = (trace_ent == item);
-                       delete(e);
-                       return r;
-               }
-               if (!(boxesoverlap(this.absmin, this.absmax + eZ * 50, trace_endpos + PL_MIN_CONST, trace_endpos + PL_MAX_CONST)))
-                       waypoint_spawnforteleporter(this, trace_endpos, vlen(trace_endpos - org) / vlen(e.velocity), e);
-               delete(e);
-       }
-
-       defer(this, 0.1, trigger_push_updatelink);
-#endif
-       return true;
-}
-
-void trigger_push_findtarget(entity this)
-{
-       trigger_push_test(this, NULL);
-}
-
-#ifdef SVQC
-float trigger_push_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_PUSH);
-
-       WriteByte(MSG_ENTITY, this.team);
-       WriteInt24_t(MSG_ENTITY, this.spawnflags);
-       WriteByte(MSG_ENTITY, this.active);
-       WriteCoord(MSG_ENTITY, this.height);
-
-       WriteVector(MSG_ENTITY, this.movedir);
-
-       trigger_common_write(this, true);
-
-       return true;
-}
-
-void trigger_push_updatelink(entity this)
-{
-       this.SendFlags |= 1;
-}
-
-void trigger_push_link(entity this)
-{
-       trigger_link(this, trigger_push_send);
-}
-
-/*
- * ENTITY PARAMETERS:
- *
- *   target:  target of jump
- *   height:  the absolute value is the height of the highest point of the jump
- *            trajectory above the higher one of the player and the target.
- *            the sign indicates whether the highest point is INSIDE (positive)
- *            or OUTSIDE (negative) of the jump trajectory. General rule: use
- *            positive values for targets mounted on the floor, and use negative
- *            values to target a point on the ceiling.
- *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
- */
-spawnfunc(trigger_push)
-{
-       SetMovedir(this);
-
-       trigger_init(this);
-
-       this.active = ACTIVE_ACTIVE;
-       this.use = trigger_push_use;
-       settouch(this, trigger_push_touch);
-
-       // normal push setup
-       if (!this.speed)
-               this.speed = 1000;
-       this.movedir = this.movedir * this.speed * 10;
-
-       if (!this.noise)
-               this.noise = "misc/jumppad.wav";
-       precache_sound (this.noise);
-
-       trigger_push_link(this); // link it now
-
-       IL_PUSH(g_jumppads, this);
-
-       // this must be called to spawn the teleport waypoints for bots
-       InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
-}
-
-
-bool target_push_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
-
-       WriteByte(MSG_ENTITY, this.cnt);
-       WriteString(MSG_ENTITY, this.targetname);
-       WriteVector(MSG_ENTITY, this.origin);
-
-       WriteAngle(MSG_ENTITY, this.angles_x);
-       WriteAngle(MSG_ENTITY, this.angles_y);
-       WriteAngle(MSG_ENTITY, this.angles_z);
-
-       return true;
-}
-
-void target_push_use(entity this, entity actor, entity trigger)
-{
-       if(trigger.classname == "trigger_push" || trigger == this)
-               return; // WTF, why is this a thing
-
-       jumppad_push(this, actor);
-}
-
-void target_push_link(entity this)
-{
-       BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
-       Net_LinkEntity(this, false, 0, target_push_send);
-       //this.SendFlags |= 1; // update
-}
-
-void target_push_init(entity this)
-{
-       this.mangle = this.angles;
-       setorigin(this, this.origin);
-       target_push_link(this);
-}
-
-void target_push_init2(entity this)
-{
-       if(this.target && this.target != "") // we have an old style pusher!
-       {
-               InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
-               this.use = target_push_use;
-       }
-
-       target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
-}
-
-spawnfunc(target_push) { target_push_init2(this); }
-spawnfunc(info_notnull) { target_push_init(this); }
-spawnfunc(target_position) { target_push_init(this); }
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
-{
-       this.classname = "jumppad";
-       int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; }
-       this.spawnflags = ReadInt24_t();
-       this.active = ReadByte();
-       this.height = ReadCoord();
-
-       this.movedir = ReadVector();
-
-       trigger_common_read(this, true);
-
-       this.entremove = trigger_remove_generic;
-       this.solid = SOLID_TRIGGER;
-       settouch(this, trigger_push_touch);
-       this.move_time = time;
-       defer(this, 0.25, trigger_push_findtarget);
-
-       return true;
-}
-
-void target_push_remove(entity this)
-{
-       //if(this.classname)
-               //strunzone(this.classname);
-       //this.classname = string_null;
-
-       if(this.targetname)
-               strunzone(this.targetname);
-       this.targetname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
-{
-       this.classname = "push_target";
-       this.cnt = ReadByte();
-       this.targetname = strzone(ReadString());
-       this.origin = ReadVector();
-
-       this.angles_x = ReadAngle();
-       this.angles_y = ReadAngle();
-       this.angles_z = ReadAngle();
-
-       return = true;
-
-       setorigin(this, this.origin);
-
-       this.drawmask = MASK_NORMAL;
-       this.entremove = target_push_remove;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/jumppads.qh b/qcsrc/common/triggers/trigger/jumppads.qh
deleted file mode 100644 (file)
index 50ed0a3..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#pragma once
-
-IntrusiveList g_jumppads;
-STATIC_INIT(g_jumppads) { g_jumppads = IL_NEW(); }
-
-const float PUSH_ONCE          = 1;
-const float PUSH_SILENT                = 2;
-
-.float pushltime;
-.float istypefrag;
-.float height;
-
-const int NUM_JUMPPADSUSED = 3;
-.float jumppadcount;
-.entity jumppadsused[NUM_JUMPPADSUSED];
-
-#ifdef SVQC
-void SUB_UseTargets(entity this, entity actor, entity trigger);
-void trigger_push_use(entity this, entity actor, entity trigger);
-bool trigger_push_testorigin(entity tracetest_ent, entity targ, entity jp, vector org);
-#endif
-
-/*
-       trigger_push_calculatevelocity
-
-       Arguments:
-         org - origin of the object which is to be pushed
-         tgt - target entity (can be either a point or a model entity; if it is
-               the latter, its midpoint is used)
-         ht  - jump height, measured from the higher one of org and tgt's midpoint
-         pushed_entity - object that is to be pushed
-
-       Returns: velocity for the jump
- */
-vector trigger_push_calculatevelocity(vector org, entity tgt, float ht, entity pushed_entity);
-
-void trigger_push_touch(entity this, entity toucher);
-
-.vector dest;
-bool trigger_push_test(entity this, entity item);
-void trigger_push_findtarget(entity this);
-
-/*
- * ENTITY PARAMETERS:
- *
- *   target:  target of jump
- *   height:  the absolute value is the height of the highest point of the jump
- *            trajectory above the higher one of the player and the target.
- *            the sign indicates whether the highest point is INSIDE (positive)
- *            or OUTSIDE (negative) of the jump trajectory. General rule: use
- *            positive values for targets mounted on the floor, and use negative
- *            values to target a point on the ceiling.
- *   movedir: if target is not set, this * speed * 10 is the velocity to be reached.
- */
-#ifdef SVQC
-spawnfunc(trigger_push);
-
-spawnfunc(target_push);
-spawnfunc(info_notnull);
-spawnfunc(target_position);
-#endif
diff --git a/qcsrc/common/triggers/trigger/keylock.qc b/qcsrc/common/triggers/trigger/keylock.qc
deleted file mode 100644 (file)
index bf20d1e..0000000
+++ /dev/null
@@ -1,198 +0,0 @@
-#include "keylock.qh"
-/**
- * trigger given targets
- */
-void trigger_keylock_trigger(entity this, entity actor, string s)
-{
-       for(entity t = NULL; (t = find(t, targetname, s)); )
-               if(t.use)
-                       t.use(t, actor, this);
-}
-
-/**
- * kill killtarget of trigger keylock.
- */
-void trigger_keylock_kill(string s)
-{
-       entity t;
-       for(t = NULL; (t = find(t, targetname, s)); )
-               delete(t);
-}
-
-void trigger_keylock_touch(entity this, entity toucher)
-{
-       bool key_used = false;
-       bool started_delay = false;
-
-       // only player may trigger the lock
-       if(!IS_PLAYER(toucher))
-               return;
-
-       // check silver key
-       if(this.itemkeys)
-               key_used = item_keys_usekey(this, toucher);
-
-       if(this.itemkeys)
-       {
-#ifdef SVQC
-               // at least one of the keys is missing
-               if(key_used)
-               {
-                       // one or more keys were given, but others are still missing!
-                       play2(toucher, this.noise1);
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(this.itemkeys));
-                       toucher.key_door_messagetime = time + 2;
-               }
-               else if(toucher.key_door_messagetime <= time)
-               {
-                       // no keys were given
-                       play2(toucher, this.noise2);
-                       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(this.itemkeys));
-                       toucher.key_door_messagetime = time + 2;
-               }
-#endif
-
-               // trigger target2
-               if(this.delay <= time || started_delay == true)
-               if(this.target2)
-               {
-                       trigger_keylock_trigger(this, toucher, this.target2);
-                       started_delay = true;
-                       this.delay = time + this.wait;
-               }
-       }
-       else
-       {
-#ifdef SVQC
-               // all keys were given!
-               play2(toucher, this.noise);
-               centerprint(toucher, this.message);
-#endif
-
-               if(this.target)
-                       trigger_keylock_trigger(this, toucher, this.target);
-
-               if(this.killtarget)
-                       trigger_keylock_kill(this.killtarget);
-
-               delete(this);
-       }
-
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_KEYLOCK)
-
-#ifdef SVQC
-bool trigger_keylock_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_KEYLOCK);
-
-       WriteInt24_t(MSG_ENTITY, this.itemkeys);
-       WriteByte(MSG_ENTITY, this.height);
-
-       trigger_common_write(this, true);
-
-       return true;
-}
-
-void trigger_keylock_link(entity this)
-{
-       // uncomment to network keylocks
-       //Net_LinkEntity(this, false, 0, trigger_keylock_send);
-}
-
-/*QUAKED trigger_keylock (.0 .5 .8) ?
-Keylock trigger.  Must target other entities.
-This trigger will trigger target entities when all required keys are provided.
--------- KEYS --------
-itemkeys: A bit field with key IDs that are needed to open this lock.
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (3 is default)
-target: trigger all entities with this targetname when triggered and all keys have been given to it, then remove this trigger
-target2: trigger all entities with this targetname when triggered without giving it all the required keys.
-killtarget: remove all entities with this targetname when triggered with all the needed keys.
-message: print this message to the player who activated the trigger when all needed keys have been given.
-message2: print this message to the player who activated the trigger when not all of the needed keys have been given.
-noise: sound to play when lock gets unlocked (default: see sounds)
-noise1: sound to play when only some of the needed key were used but not all (default: misc/decreasevalue.wav)
-noise2: sound to play when a key is missing (default: misc/talk.wav)
-wait: prevent triggering again for this amount of time (default: 5) - applies to target2, target3, target4.
----------NOTES----------
-If spawned without any key specified in itemkeys, this trigger will display an error and remove itself.
-message2 and noise2 will be resent to the player every 2 seconds while he is in the trigger zone.
-*/
-spawnfunc(trigger_keylock)
-{
-       if(!this.itemkeys) { delete(this); return; }
-
-       // set unlocked message
-       if(this.message == "")
-               this.message = "Unlocked!";
-
-       // set default unlock noise
-       if(this.noise == "")
-       {
-               if(this.sounds == 1)
-                       this.noise = "misc/secret.wav";
-               else if(this.sounds == 2)
-                       this.noise = strzone(SND(TALK));
-               else //if (this.sounds == 3) {
-                       this.noise = "misc/trigger1.wav";
-       }
-
-       // set default use key sound
-       if(this.noise1 == "")
-               this.noise1 = "misc/decreasevalue.wav";
-
-       // set closed sourd
-       if(this.noise2 == "")
-               this.noise2 = SND(TALK);
-
-       // delay between triggering message2 and trigger2
-       if(!this.wait) { this.wait = 5; }
-
-       // precache sounds
-       precache_sound(this.noise);
-       precache_sound(this.noise1);
-       precache_sound(this.noise2);
-
-       EXACTTRIGGER_INIT;
-
-       settouch(this, trigger_keylock_touch);
-
-       trigger_keylock_link(this);
-}
-#elif defined(CSQC)
-void keylock_remove(entity this)
-{
-       if(this.target) { strunzone(this.target); }
-       this.target = string_null;
-
-       if(this.target2) { strunzone(this.target2); }
-       this.target2 = string_null;
-
-       if(this.target3) { strunzone(this.target3); }
-       this.target3 = string_null;
-
-       if(this.target4) { strunzone(this.target4); }
-       this.target4 = string_null;
-
-       if(this.killtarget) { strunzone(this.killtarget); }
-       this.killtarget = string_null;
-
-       if(this.targetname) { strunzone(this.targetname); }
-       this.targetname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_KEYLOCK, bool isnew)
-{
-       this.itemkeys = ReadInt24_t();
-       this.height = ReadByte();
-
-       trigger_common_read(this, true);
-
-       return = true;
-
-       this.classname = "trigger_keylock";
-       this.entremove = keylock_remove;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/keylock.qh b/qcsrc/common/triggers/trigger/keylock.qh
deleted file mode 100644 (file)
index 904c3fa..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-#ifdef CSQC
-bool item_keys_usekey(entity l, entity p)
-{
-       int valid = (l.itemkeys & p.itemkeys); // TODO: itemkeys isn't networked or anything!
-       l.itemkeys &= ~valid; // only some of the needed keys were given
-       return valid != 0;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/magicear.qc b/qcsrc/common/triggers/trigger/magicear.qc
deleted file mode 100644 (file)
index 354ed1b..0000000
+++ /dev/null
@@ -1,200 +0,0 @@
-#include "magicear.qh"
-#ifdef SVQC
-float magicear_matched;
-float W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, float instrument, float ignorepitch, float mintempo, float maxtempo);
-string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
-{
-       float domatch, dotrigger, matchstart, l;
-       string s, msg;
-       string savemessage;
-
-       magicear_matched = false;
-
-       dotrigger = ((IS_PLAYER(source)) && (!IS_DEAD(source)) && ((ear.radius == 0) || (vdist(source.origin - ear.origin, <=, ear.radius))));
-       domatch = ((ear.spawnflags & 32) || dotrigger);
-
-       if (!domatch)
-               return msgin;
-
-       if (!msgin)
-       {
-               // we are in TUBA mode!
-               if (!(ear.spawnflags & 256))
-                       return msgin;
-
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity weaponentity = weaponentities[slot];
-                       if(!W_Tuba_HasPlayed(source, weaponentity, ear.message, ear.movedir_x, !(ear.spawnflags & 512), ear.movedir_y, ear.movedir_z))
-                               return msgin;
-               }
-
-               magicear_matched = true;
-
-               if(dotrigger)
-               {
-                       savemessage = ear.message;
-                       ear.message = string_null;
-                       SUB_UseTargets(ear, source, NULL);
-                       ear.message = savemessage;
-               }
-
-               if(ear.netname != "")
-                       return ear.netname;
-
-               return msgin;
-       }
-
-       if(ear.spawnflags & 256) // ENOTUBA
-               return msgin;
-
-       if(privatesay)
-       {
-               if(ear.spawnflags & 4)
-                       return msgin;
-       }
-       else
-       {
-               if(!teamsay)
-                       if(ear.spawnflags & 1)
-                               return msgin;
-               if(teamsay > 0)
-                       if(ear.spawnflags & 2)
-                               return msgin;
-               if(teamsay < 0)
-                       if(ear.spawnflags & 8)
-                               return msgin;
-       }
-
-       matchstart = -1;
-       l = strlen(ear.message);
-
-       if(ear.spawnflags & 128)
-               msg = msgin;
-       else
-               msg = strdecolorize(msgin);
-
-       if(substring(ear.message, 0, 1) == "*")
-       {
-               if(substring(ear.message, -1, 1) == "*")
-               {
-                       // two wildcards
-                       // as we need multi-replacement here...
-                       s = substring(ear.message, 1, -2);
-                       l -= 2;
-                       if(strstrofs(msg, s, 0) >= 0)
-                               matchstart = -2; // we use strreplace on s
-               }
-               else
-               {
-                       // match at start
-                       s = substring(ear.message, 1, -1);
-                       l -= 1;
-                       if(substring(msg, -l, l) == s)
-                               matchstart = strlen(msg) - l;
-               }
-       }
-       else
-       {
-               if(substring(ear.message, -1, 1) == "*")
-               {
-                       // match at end
-                       s = substring(ear.message, 0, -2);
-                       l -= 1;
-                       if(substring(msg, 0, l) == s)
-                               matchstart = 0;
-               }
-               else
-               {
-                       // full match
-                       s = ear.message;
-                       if(msg == ear.message)
-                               matchstart = 0;
-               }
-       }
-
-       if(matchstart == -1) // no match
-               return msgin;
-
-       magicear_matched = true;
-
-       if(dotrigger)
-       {
-               savemessage = ear.message;
-               ear.message = string_null;
-               SUB_UseTargets(ear, source, NULL);
-               ear.message = savemessage;
-       }
-
-       if(ear.spawnflags & 16)
-       {
-               return ear.netname;
-       }
-       else if(ear.netname != "")
-       {
-               if(matchstart < 0)
-                       return strreplace(s, ear.netname, msg);
-               else
-                       return strcat(
-                               substring(msg, 0, matchstart),
-                               ear.netname,
-                               substring(msg, matchstart + l, -1)
-                       );
-       }
-       else
-               return msgin;
-}
-
-entity magicears;
-string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin)
-{
-       entity ear;
-       string msgout;
-       for(ear = magicears; ear; ear = ear.enemy)
-       {
-               msgout = trigger_magicear_processmessage(ear, source, teamsay, privatesay, msgin);
-               if(!(ear.spawnflags & 64))
-               if(magicear_matched)
-                       return msgout;
-               msgin = msgout;
-       }
-       return msgin;
-}
-
-spawnfunc(trigger_magicear)
-{
-       this.enemy = magicears;
-       magicears = this;
-
-       // actually handled in "say" processing
-       // spawnflags:
-       //    1 = ignore say
-       //    2 = ignore teamsay
-       //    4 = ignore tell
-       //    8 = ignore tell to unknown player
-       //   16 = let netname replace the whole message (otherwise, netname is a word replacement if set)
-       //   32 = perform the replacement even if outside the radius or dead
-       //   64 = continue replacing/triggering even if this one matched
-       //  128 = don't decolorize message before matching
-       //  256 = message is a tuba note sequence (pitch.duration pitch.duration ...)
-       //  512 = tuba notes must be exact right pitch, no transposing
-       // message: either
-       //   *pattern*
-       // or
-       //   *pattern
-       // or
-       //   pattern*
-       // or
-       //   pattern
-       // netname:
-       //   if set, replacement for the matched text
-       // radius:
-       //   "hearing distance"
-       // target:
-       //   what to trigger
-       // movedir:
-       //   for spawnflags 256, defines 'instrument+1 mintempo maxtempo' (zero component doesn't matter)
-
-       this.movedir_x -= 1; // map to tuba instrument numbers
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/magicear.qh b/qcsrc/common/triggers/trigger/magicear.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/monoflop.qc b/qcsrc/common/triggers/trigger/monoflop.qc
deleted file mode 100644 (file)
index a67baca..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#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"
-*/
-void monoflop_use(entity this, entity actor, entity trigger)
-{
-       this.nextthink = time + this.wait;
-       this.enemy = actor;
-       if(this.state)
-               return;
-       this.state = 1;
-       SUB_UseTargets(this, actor, trigger);
-}
-void monoflop_fixed_use(entity this, entity actor, entity trigger)
-{
-       if(this.state)
-               return;
-       this.nextthink = time + this.wait;
-       this.state = 1;
-       this.enemy = actor;
-       SUB_UseTargets(this, actor, trigger);
-}
-
-void monoflop_think(entity this)
-{
-       this.state = 0;
-       SUB_UseTargets(this, this.enemy, NULL);
-}
-
-void monoflop_reset(entity this)
-{
-       this.state = 0;
-       this.nextthink = 0;
-}
-
-spawnfunc(trigger_monoflop)
-{
-       if(!this.wait)
-               this.wait = 1;
-       if(this.spawnflags & 1)
-               this.use = monoflop_fixed_use;
-       else
-               this.use = monoflop_use;
-       setthink(this, monoflop_think);
-       this.state = 0;
-       this.reset = monoflop_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/monoflop.qh b/qcsrc/common/triggers/trigger/monoflop.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/multi.qc b/qcsrc/common/triggers/trigger/multi.qc
deleted file mode 100644 (file)
index 24b7d5f..0000000
+++ /dev/null
@@ -1,211 +0,0 @@
-#include "multi.qh"
-// NOTE: also contains trigger_once at bottom
-
-#ifdef SVQC
-// the wait time has passed, so set back up for another activation
-void multi_wait(entity this)
-{
-       if (this.max_health)
-       {
-               this.health = this.max_health;
-               this.takedamage = DAMAGE_YES;
-               this.solid = SOLID_BBOX;
-       }
-}
-
-
-// the trigger was just touched/killed/used
-// this.enemy should be set to the activator so it can be held through a delay
-// so wait for the delay time before firing
-void multi_trigger(entity this)
-{
-       if (this.nextthink > time)
-       {
-               return;         // allready been triggered
-       }
-
-       if(this.spawnflags & 16384)
-       if(!IS_PLAYER(this.enemy))
-               return; // only players
-
-       if (this.classname == "trigger_secret")
-       {
-               if (!IS_PLAYER(this.enemy))
-                       return;
-               found_secrets = found_secrets + 1;
-               WriteByte (MSG_ALL, SVC_FOUNDSECRET);
-       }
-
-       if (this.noise)
-               _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-
-// don't trigger again until reset
-       this.takedamage = DAMAGE_NO;
-
-       SUB_UseTargets(this, this.enemy, this.goalentity);
-
-       if (this.wait > 0)
-       {
-               setthink(this, multi_wait);
-               this.nextthink = time + this.wait;
-       }
-       else if (this.wait == 0)
-       {
-               multi_wait(this); // waiting finished
-       }
-       else
-       {       // we can't just delete(this) here, because this is a touch function
-               // called while C code is looping through area links...
-               settouch(this, func_null);
-       }
-}
-
-void multi_use(entity this, entity actor, entity trigger)
-{
-       this.goalentity = trigger;
-       this.enemy = actor;
-       multi_trigger(this);
-}
-
-void multi_touch(entity this, entity toucher)
-{
-       if(!(this.spawnflags & 2))
-       if(!toucher.iscreature)
-                       return;
-
-       if(this.team)
-               if(((this.spawnflags & 4) == 0) == (this.team != toucher.team))
-                       return;
-
-// if the trigger has an angles field, check player's facing direction
-       if (this.movedir != '0 0 0')
-       {
-               makevectors (toucher.angles);
-               if (v_forward * this.movedir < 0)
-                       return;         // not facing the right way
-       }
-
-       // if the trigger has pressed keys, check that the player is pressing those keys
-       if(this.pressedkeys && IS_PLAYER(toucher)) // only for players
-       if(!(CS(toucher).pressedkeys & this.pressedkeys))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       this.enemy = toucher;
-       this.goalentity = toucher;
-       multi_trigger(this);
-}
-
-void multi_eventdamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(!this.takedamage)
-               return;
-       if(this.spawnflags & DOOR_NOSPLASH)
-               if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
-                       return;
-       if(this.team)
-               if(((this.spawnflags & 4) == 0) == (this.team != attacker.team))
-                       return;
-       this.health = this.health - damage;
-       if (this.health <= 0)
-       {
-               this.enemy = attacker;
-               this.goalentity = inflictor;
-               multi_trigger(this);
-       }
-}
-
-void multi_reset(entity this)
-{
-       if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
-               settouch(this, multi_touch);
-       if (this.max_health)
-       {
-               this.health = this.max_health;
-               this.takedamage = DAMAGE_YES;
-               this.solid = SOLID_BBOX;
-       }
-       setthink(this, func_null);
-       this.nextthink = 0;
-       this.team = this.team_saved;
-}
-
-/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
-Variable sized repeatable trigger.  Must be targeted at one or more entities.  If "health" is set, the trigger must be killed to activate each time.
-If "delay" is set, the trigger waits some time after activating before firing.
-"wait" : Seconds between triggerings. (.2 default)
-If notouch is set, the trigger is only fired by other entities, not by touching.
-NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
-sounds
-1)     secret
-2)     beep beep
-3)     large switch
-4)
-set "message" to text string
-*/
-spawnfunc(trigger_multiple)
-{
-       this.reset = multi_reset;
-       if (this.sounds == 1)
-               this.noise = "misc/secret.wav";
-       else if (this.sounds == 2)
-               this.noise = strzone(SND(TALK));
-       else if (this.sounds == 3)
-               this.noise = "misc/trigger1.wav";
-
-       if(this.noise)
-               precache_sound(this.noise);
-
-       if (!this.wait)
-               this.wait = 0.2;
-       else if(this.wait < -1)
-               this.wait = 0;
-       this.use = multi_use;
-
-       EXACTTRIGGER_INIT;
-
-       this.team_saved = this.team;
-       IL_PUSH(g_saved_team, this);
-
-       if (this.health)
-       {
-               if (this.spawnflags & SPAWNFLAG_NOTOUCH)
-                       objerror (this, "health and notouch don't make sense\n");
-               this.canteamdamage = true;
-               this.max_health = this.health;
-               this.event_damage = multi_eventdamage;
-               this.takedamage = DAMAGE_YES;
-               this.solid = SOLID_BBOX;
-               setorigin(this, this.origin);   // make sure it links into the world
-       }
-       else
-       {
-               if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
-               {
-                       settouch(this, multi_touch);
-                       setorigin(this, this.origin);   // make sure it links into the world
-               }
-       }
-}
-
-
-/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
-Variable sized trigger. Triggers once, then removes itself.  You must set the key "target" to the name of another object in the level that has a matching
-"targetname".  If "health" is set, the trigger must be killed to activate.
-If notouch is set, the trigger is only fired by other entities, not by touching.
-if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
-if "angle" is set, the trigger will only fire when someone is facing the direction of the angle.  Use "360" for an angle of 0.
-sounds
-1)     secret
-2)     beep beep
-3)     large switch
-4)
-set "message" to text string
-*/
-spawnfunc(trigger_once)
-{
-       this.wait = -1;
-       spawnfunc_trigger_multiple(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/multi.qh b/qcsrc/common/triggers/trigger/multi.qh
deleted file mode 100644 (file)
index 43358c2..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-
-#ifdef SVQC
-void multi_trigger(entity this);
-void multi_reset(entity this);
-
-spawnfunc(trigger_once);
-#endif
diff --git a/qcsrc/common/triggers/trigger/multivibrator.qc b/qcsrc/common/triggers/trigger/multivibrator.qc
deleted file mode 100644 (file)
index d946efe..0000000
+++ /dev/null
@@ -1,78 +0,0 @@
-#include "multivibrator.qh"
-#ifdef SVQC
-void multivibrator_send(entity this)
-{
-       float newstate;
-       float cyclestart;
-
-       cyclestart = floor((time + this.phase) / (this.wait + this.respawntime)) * (this.wait + this.respawntime) - this.phase;
-
-       newstate = (time < cyclestart + this.wait);
-
-       if(this.state != newstate)
-               SUB_UseTargets(this, this, NULL);
-       this.state = newstate;
-
-       if(this.state)
-               this.nextthink = cyclestart + this.wait + 0.01;
-       else
-               this.nextthink = cyclestart + this.wait + this.respawntime + 0.01;
-}
-
-void multivibrator_send_think(entity this)
-{
-       multivibrator_send(this);
-}
-
-void multivibrator_toggle(entity this, entity actor, entity trigger)
-{
-       if(this.nextthink == 0)
-       {
-               multivibrator_send(this);
-       }
-       else
-       {
-               if(this.state)
-               {
-                       SUB_UseTargets(this, actor, trigger);
-                       this.state = 0;
-               }
-               this.nextthink = 0;
-       }
-}
-
-void multivibrator_reset(entity this)
-{
-       if(!(this.spawnflags & 1))
-               this.nextthink = 0; // wait for a trigger event
-       else
-               this.nextthink = max(1, time);
-}
-
-/*QUAKED trigger_multivibrator (.5 .5 .5) (-8 -8 -8) (8 8 8) START_ON
-"Multivibrator" trigger gate... repeatedly sends trigger events. When triggered, turns on or off.
--------- KEYS --------
-target: trigger all entities with this targetname when it goes off
-targetname: name that identifies this entity so it can be triggered; when off, it always uses the OFF state
-phase: offset of the timing
-wait: "on" cycle time (default: 1)
-respawntime: "off" cycle time (default: same as wait)
--------- SPAWNFLAGS --------
-START_ON: assume it is already turned on (when targeted)
-*/
-spawnfunc(trigger_multivibrator)
-{
-       if(!this.wait)
-               this.wait = 1;
-       if(!this.respawntime)
-               this.respawntime = this.wait;
-
-       this.state = 0;
-       this.use = multivibrator_toggle;
-       setthink(this, multivibrator_send_think);
-       this.nextthink = max(1, time);
-
-       IFTARGETED
-               multivibrator_reset(this);
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/multivibrator.qh b/qcsrc/common/triggers/trigger/multivibrator.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/relay.qc b/qcsrc/common/triggers/trigger/relay.qc
deleted file mode 100644 (file)
index e5d0018..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#include "relay.qh"
-#ifdef SVQC
-
-void relay_use(entity this, entity actor, entity trigger)
-{
-       if(this.active != ACTIVE_ACTIVE)
-               return;
-
-       SUB_UseTargets(this, actor, trigger);
-}
-
-/*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.
-*/
-spawnfunc(trigger_relay)
-{
-       this.active = ACTIVE_ACTIVE;
-       this.use = relay_use;
-       this.reset = spawnfunc_trigger_relay; // this spawnfunc resets fully
-}
-
-spawnfunc(target_relay) { spawnfunc_trigger_relay(this); }
-#endif
diff --git a/qcsrc/common/triggers/trigger/relay.qh b/qcsrc/common/triggers/trigger/relay.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/relay_activators.qc b/qcsrc/common/triggers/trigger/relay_activators.qc
deleted file mode 100644 (file)
index d713a05..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "relay_activators.qh"
-#ifdef SVQC
-void relay_activators_use(entity this, entity actor, entity trigger)
-{
-       for(entity trg = NULL; (trg = find(trg, targetname, this.target)); )
-       {
-               if (trg.setactive)
-                       trg.setactive(trg, this.cnt);
-               else
-               {
-                       //bprint("Not using setactive\n");
-                       if(this.cnt == ACTIVE_TOGGLE)
-                               if(trg.active == ACTIVE_ACTIVE)
-                                       trg.active = ACTIVE_NOT;
-                               else
-                                       trg.active = ACTIVE_ACTIVE;
-                       else
-                               trg.active = this.cnt;
-               }
-       }
-}
-
-spawnfunc(relay_activate)
-{
-       this.cnt = ACTIVE_ACTIVE;
-       this.use = relay_activators_use;
-}
-
-spawnfunc(relay_deactivate)
-{
-       this.cnt = ACTIVE_NOT;
-       this.use = relay_activators_use;
-}
-
-spawnfunc(relay_activatetoggle)
-{
-       this.cnt = ACTIVE_TOGGLE;
-       this.use = relay_activators_use;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/relay_activators.qh b/qcsrc/common/triggers/trigger/relay_activators.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/relay_if.qc b/qcsrc/common/triggers/trigger/relay_if.qc
deleted file mode 100644 (file)
index 728252c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "relay_if.qh"
-#ifdef SVQC
-void trigger_relay_if_use(entity this, entity actor, entity trigger)
-{
-       int n = this.count;
-
-       // TODO make this generic AND faster than nextent()ing through all, if somehow possible
-       n = (cvar_string(this.netname) == cvar_string(this.message));
-       if(this.spawnflags & 1)
-               n = !n;
-
-       if(n)
-               SUB_UseTargets(this, actor, trigger);
-}
-
-spawnfunc(trigger_relay_if)
-{
-       this.use = trigger_relay_if_use;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/relay_if.qh b/qcsrc/common/triggers/trigger/relay_if.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/relay_teamcheck.qc b/qcsrc/common/triggers/trigger/relay_teamcheck.qc
deleted file mode 100644 (file)
index fee28df..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-#include "relay_teamcheck.qh"
-#ifdef SVQC
-void trigger_relay_teamcheck_use(entity this, entity actor, entity trigger)
-{
-       if(actor.team)
-       {
-               if(this.spawnflags & 2)
-               {
-                       if(DIFF_TEAM(actor, this))
-                               SUB_UseTargets(this, actor, trigger);
-               }
-               else
-               {
-                       if(SAME_TEAM(actor, this))
-                               SUB_UseTargets(this, actor, trigger);
-               }
-       }
-       else
-       {
-               if(this.spawnflags & 1)
-                       SUB_UseTargets(this, actor, trigger);
-       }
-}
-
-void trigger_relay_teamcheck_reset(entity this)
-{
-       this.team = this.team_saved;
-}
-
-spawnfunc(trigger_relay_teamcheck)
-{
-       this.team_saved = this.team;
-       IL_PUSH(g_saved_team, this);
-       this.use = trigger_relay_teamcheck_use;
-       this.reset = trigger_relay_teamcheck_reset;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/relay_teamcheck.qh b/qcsrc/common/triggers/trigger/relay_teamcheck.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/secret.qc b/qcsrc/common/triggers/trigger/secret.qc
deleted file mode 100644 (file)
index 9377332..0000000
+++ /dev/null
@@ -1,90 +0,0 @@
-#include "secret.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <common/util.qh>
-    #include <server/defs.qh>
-#endif
-
-#ifdef SVQC
-
-void secrets_setstatus(entity this)
-{
-       // TODO: use global stats!
-       STAT(SECRETS_TOTAL, this) = secrets_total;
-       STAT(SECRETS_FOUND, this) = secrets_found;
-}
-
-/**
- * A secret has been found (maybe :P)
- */
-void trigger_secret_touch(entity this, entity toucher)
-{
-       // only a player can trigger this
-       if (!IS_PLAYER(toucher))
-               return;
-
-       // update secrets found counter
-       secrets_found += 1;
-       //print("Secret found: ", ftos(secret_counter.cnt), "/");
-       //print(ftos(secret_counter.count), "\n");
-
-       // centerprint message (multi_touch() doesn't always call centerprint())
-       centerprint(toucher, this.message);
-       this.message = "";
-
-       // handle normal trigger features
-       multi_touch(this, toucher);
-       // we can't just delete(this) here, because this is a touch function
-       // called while C code is looping through area links...
-       //delete(this);
-}
-
-/*QUAKED trigger_secret (.5 .5 .5) ?
-Variable sized secret trigger. Can be targeted at one or more entities.
-Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
--------- KEYS --------
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
-noise: path to sound file, if you want to play something else
-target: trigger all entities with this targetname when triggered
-message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
-killtarget: remove all entities with this targetname when triggered
--------- NOTES --------
-You should create a common/trigger textured brush covering the entrance to a secret room/area.
-Trigger secret can only be trigger by a player's touch and can not be a target itself.
-*/
-spawnfunc(trigger_secret)
-{
-       // FIXME: should it be disabled in most modes?
-
-       // update secrets count
-       secrets_total += 1;
-
-       // add default message
-       if (this.message == "")
-               this.message = "You found a secret!";
-
-       // set default sound
-       if (this.noise == "")
-       if (!this.sounds)
-               this.sounds = 1; // misc/secret.wav
-
-       // this entity can't be a target itself!!!!
-       this.targetname = "";
-
-       // you can't just shoot a room to find it, can you?
-       this.health = 0;
-
-       // a secret can not be delayed
-       this.delay = 0;
-
-       // convert this trigger to trigger_once
-       //this.classname = "trigger_once";
-       spawnfunc_trigger_once(this);
-
-       // take over the touch() function, so we can mark secret as found
-       settouch(this, trigger_secret_touch);
-       // ignore triggering;
-       this.use = func_null;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/secret.qh b/qcsrc/common/triggers/trigger/secret.qh
deleted file mode 100644 (file)
index fcc55c3..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#pragma once
-#ifdef SVQC
-
-/**
- * Total number of secrets on the map.
- */
-float secrets_total;
-
-/**
- * Total numbe of secrets found on the map.
- */
-float secrets_found;
-
-
-/**
- * update secrets status.
- */
-void secrets_setstatus(entity this);
-#endif
diff --git a/qcsrc/common/triggers/trigger/swamp.qc b/qcsrc/common/triggers/trigger/swamp.qc
deleted file mode 100644 (file)
index 058e41c..0000000
+++ /dev/null
@@ -1,157 +0,0 @@
-#include "swamp.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <lib/warpzone/util_server.qh>
-    #include <common/weapons/_all.qh>
-    #include <server/defs.qh>
-    #include <common/deathtypes/all.qh>
-#endif
-
-/*
-*              t_swamp.c
-*              Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
-*              Author tZork (Jakob MG)
-*              jakob@games43.se
-*              2005 11 29
-*/
-
-.float swamp_interval; //Hurt players in swamp with this interval
-.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
-.entity swampslug;
-
-#ifdef SVQC
-spawnfunc(trigger_swamp);
-#endif
-void swamp_touch(entity this, entity toucher);
-void swampslug_think(entity this);
-
-
-/*
-* Uses a entity calld swampslug to handle players in the swamp
-* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
-* attaches a new "swampslug" to the player. As long as the plyer is inside
-* the swamp the swamp gives the slug new health. But the slug slowly kills itself
-* so when the player goes outside the swamp, it dies and releases the player from the
-* swamps curses (dmg/slowdown)
-*
-* I do it this way becuz there is no "untouch" event.
-*/
-void swampslug_think(entity this)
-{
-       //Slowly kill the slug
-       this.health = this.health - 1;
-
-       //Slug dead? then remove curses.
-       if(this.health <= 0)
-       {
-               this.owner.in_swamp = 0;
-               delete(this);
-               //centerprint(this.owner,"Killing slug...\n");
-               return;
-       }
-
-       // Slug still alive, so we are still in the swamp
-       // Or we have exited it very recently.
-       // Do the damage and renew the timer.
-#ifdef SVQC
-       Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, DMG_NOWEP, this.owner.origin, '0 0 0');
-#endif
-
-       this.nextthink = time + this.swamp_interval;
-}
-
-void swamp_touch(entity this, entity toucher)
-{
-       // If whatever thats touching the swamp is not a player
-       // or if its a dead player, just dont care abt it.
-       if(!IS_PLAYER(toucher) || IS_DEAD(toucher))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, toucher);
-
-       // Chech if player alredy got a swampslug.
-       if(toucher.in_swamp != 1)
-       {
-               // If not attach one.
-               //centerprint(toucher,"Entering swamp!\n");
-               toucher.swampslug = spawn();
-               toucher.swampslug.health = 2;
-               setthink(toucher.swampslug, swampslug_think);
-               toucher.swampslug.nextthink = time;
-               toucher.swampslug.owner = toucher;
-               toucher.swampslug.dmg = this.dmg;
-               toucher.swampslug.swamp_interval = this.swamp_interval;
-               toucher.swamp_slowdown = this.swamp_slowdown;
-               toucher.in_swamp = 1;
-               return;
-       }
-
-       //toucher.in_swamp = 1;
-
-       //Revitalize players swampslug
-       toucher.swampslug.health = 2;
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
-
-#ifdef SVQC
-float swamp_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
-
-       WriteByte(MSG_ENTITY, this.dmg); // can probably get away with using a single byte here
-       WriteByte(MSG_ENTITY, this.swamp_slowdown);
-       WriteByte(MSG_ENTITY, this.swamp_interval);
-
-       trigger_common_write(this, false);
-
-       return true;
-}
-
-void swamp_link(entity this)
-{
-       trigger_link(this, swamp_send);
-}
-
-/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
-Players gettin into the swamp will
-get slowd down and damaged
-*/
-spawnfunc(trigger_swamp)
-{
-       // Init stuff
-       trigger_init(this);
-       settouch(this, swamp_touch);
-
-       // Setup default keys, if missing
-       if(this.dmg <= 0)
-               this.dmg = 5;
-       if(this.swamp_interval <= 0)
-               this.swamp_interval = 1;
-       if(this.swamp_slowdown <= 0)
-               this.swamp_slowdown = 0.5;
-
-       swamp_link(this);
-}
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
-{
-       this.dmg = ReadByte();
-       this.swamp_slowdown = ReadByte();
-       this.swamp_interval = ReadByte();
-
-       trigger_common_read(this, false);
-
-       return = true;
-
-       this.classname = "trigger_swamp";
-       this.solid = SOLID_TRIGGER;
-       settouch(this, swamp_touch);
-       this.drawmask = MASK_NORMAL;
-       this.move_time = time;
-       this.entremove = trigger_remove_generic;
-}
-#endif
diff --git a/qcsrc/common/triggers/trigger/swamp.qh b/qcsrc/common/triggers/trigger/swamp.qh
deleted file mode 100644 (file)
index f4df983..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-
-.float swamp_interval; //Hurt players in swamp with this interval
-.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
-.entity swampslug;
-
-.float in_swamp;              // bool
-.entity swampslug;            // Uses this to release from swamp ("untouch" fix)
diff --git a/qcsrc/common/triggers/trigger/teleport.qc b/qcsrc/common/triggers/trigger/teleport.qc
deleted file mode 100644 (file)
index 0330ce8..0000000
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "teleport.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_TRIGGER_TELEPORT)
-
-#ifdef SVQC
-void trigger_teleport_use(entity this, entity actor, entity trigger)
-{
-       if(teamplay)
-               this.team = actor.team;
-#ifdef SVQC
-       this.SendFlags |= SF_TRIGGER_UPDATE;
-#endif
-}
-#endif
-
-bool Teleport_Active(entity this, entity player)
-{
-       if (this.active != ACTIVE_ACTIVE)
-               return false;
-
-#ifdef SVQC
-       if (!player.teleportable)
-               return false;
-
-       if(player.vehicle)
-       if(!player.vehicle.teleportable)
-               return false;
-
-       if(IS_TURRET(player))
-               return false;
-#elif defined(CSQC)
-       if(!IS_PLAYER(player))
-               return false;
-#endif
-
-       if(IS_DEAD(player))
-               return false;
-
-       if(this.team)
-               if(((this.spawnflags & 4) == 0) == (DIFF_TEAM(this, player)))
-                       return false;
-
-       return true;
-}
-
-void Teleport_Touch(entity this, entity toucher)
-{
-       entity player = toucher;
-
-       if(!Teleport_Active(this, player))
-               return;
-
-       EXACTTRIGGER_TOUCH(this, player);
-
-#ifdef SVQC
-       if(IS_PLAYER(player))
-               RemoveGrapplingHooks(player);
-#endif
-
-       entity e;
-       e = Simple_TeleportPlayer(this, player);
-
-#ifdef SVQC
-       string s = this.target; this.target = string_null;
-       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
-       if (!this.target) this.target = s;
-
-       SUB_UseTargets(e, player, player);
-#endif
-}
-
-#ifdef SVQC
-void target_teleport_use(entity this, entity actor, entity trigger)
-{
-       entity player = actor;
-
-       if(!Teleport_Active(this, player))
-               return;
-
-       if(IS_PLAYER(player))
-               RemoveGrapplingHooks(player);
-
-       entity e = Simple_TeleportPlayer(this, player);
-
-       string s = this.target; this.target = string_null;
-       SUB_UseTargets(this, player, player); // TODO: should we be using toucher for trigger too?
-       if (!this.target) this.target = s;
-
-       SUB_UseTargets(e, player, player);
-}
-#endif
-
-#ifdef SVQC
-float trigger_teleport_send(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_TRIGGER_TELEPORT);
-
-       WriteByte(MSG_ENTITY, this.team);
-       WriteInt24_t(MSG_ENTITY, this.spawnflags);
-       WriteByte(MSG_ENTITY, this.active);
-       WriteCoord(MSG_ENTITY, this.speed);
-
-       trigger_common_write(this, true);
-
-       return true;
-}
-
-void trigger_teleport_link(entity this)
-{
-       //trigger_link(this, trigger_teleport_send);
-}
-
-spawnfunc(trigger_teleport)
-{
-       this.angles = '0 0 0';
-
-       this.active = ACTIVE_ACTIVE;
-       //trigger_init(this); // only for predicted triggers?
-       EXACTTRIGGER_INIT;
-       this.use = trigger_teleport_use;
-
-       if(this.noise != "")
-               FOREACH_WORD(this.noise, true, precache_sound(it));
-
-       // this must be called to spawn the teleport waypoints for bots
-       InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
-
-       if (this.target == "")
-       {
-               objerror (this, "Teleporter with no target");
-               return;
-       }
-
-       IL_PUSH(g_teleporters, this);
-}
-
-spawnfunc(target_teleporter)
-{
-       if(this.target == "")
-       {
-               // actually a destination!
-               spawnfunc_info_teleport_destination(this);
-               return;
-       }
-
-       this.active = ACTIVE_ACTIVE;
-
-       this.use = target_teleport_use;
-
-       if(this.noise != "")
-               FOREACH_WORD(this.noise, true, precache_sound(it));
-
-       InitializeEntity(this, teleport_findtarget, INITPRIO_FINDTARGET);
-}
-#elif defined(CSQC)
-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();
-       this.speed = ReadCoord();
-
-       trigger_common_read(this, true);
-
-       this.entremove = trigger_remove_generic;
-       this.solid = SOLID_TRIGGER;
-       //settouch(this, trigger_push_touch);
-       this.move_time = time;
-       defer(this, 0.25, teleport_findtarget);
-
-       return true;
-}
-
-#endif
diff --git a/qcsrc/common/triggers/trigger/teleport.qh b/qcsrc/common/triggers/trigger/teleport.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/common/triggers/trigger/viewloc.qc b/qcsrc/common/triggers/trigger/viewloc.qc
deleted file mode 100644 (file)
index 8b98579..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-#include "viewloc.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include <lib/warpzone/util_server.qh>
-    #include <server/defs.qh>
-#endif
-
-REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC)
-REGISTER_NET_LINKED(ENT_CLIENT_VIEWLOC_TRIGGER)
-
-#ifdef SVQC
-
-void viewloc_think(entity this)
-{
-       // we abuse this method, rather than using normal .touch, because touch isn't reliable with multiple clients inside the same trigger, and can't "untouch" entities
-
-       // set myself as current viewloc where possible
-#if 1
-       FOREACH_CLIENT(IS_PLAYER(it) && it.viewloc == this,
-       {
-               it.viewloc = NULL;
-       });
-#else
-       entity e;
-       for(e = NULL; (e = findentity(e, viewloc, this)); )
-               e.viewloc = NULL;
-#endif
-
-#if 1
-       FOREACH_CLIENT(!it.viewloc && IS_PLAYER(it),
-       {
-               vector emin = it.absmin;
-               vector emax = it.absmax;
-               if(this.solid == SOLID_BSP)
-               {
-                       emin -= '1 1 1';
-                       emax += '1 1 1';
-               }
-               if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
-               {
-                       if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, it)) // accurate
-                               it.viewloc = this;
-               }
-       });
-#else
-
-               for(e = findradius((this.absmin + this.absmax) * 0.5, vlen(this.absmax - this.absmin) * 0.5 + 1); e; e = e.chain)
-                       if(!e.viewloc)
-                               if(IS_PLAYER(e)) // should we support non-player entities with this?
-                               //if(!IS_DEAD(e)) // death view is handled separately, we can't override this just yet
-                               {
-                                       vector emin = e.absmin;
-                                       vector emax = e.absmax;
-                                       if(this.solid == SOLID_BSP)
-                                       {
-                                               emin -= '1 1 1';
-                                               emax += '1 1 1';
-                                       }
-                                       if(boxesoverlap(emin, emax, this.absmin, this.absmax)) // quick
-                                               if(WarpZoneLib_BoxTouchesBrush(emin, emax, this, e)) // accurate
-                                                       e.viewloc = this;
-                               }
-#endif
-
-       this.nextthink = time;
-}
-
-bool trigger_viewloc_send(entity this, entity to, int sf)
-{
-       // CSQC doesn't need to know our origin (yet), as we're only available for referencing
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC_TRIGGER);
-
-       WriteByte(MSG_ENTITY, this.spawnflags);
-
-       WriteEntity(MSG_ENTITY, this.enemy);
-       WriteEntity(MSG_ENTITY, this.goalentity);
-
-       WriteVector(MSG_ENTITY, this.origin);
-
-       return true;
-}
-
-void viewloc_init(entity this)
-{
-       entity e;
-       for(e = NULL; (e = find(e, targetname, this.target)); )
-               if(e.classname == "target_viewlocation_start")
-               {
-                       this.enemy = e;
-                       break;
-               }
-       for(e = NULL; (e = find(e, targetname, this.target2)); )
-               if(e.classname == "target_viewlocation_end")
-               {
-                       this.goalentity = e;
-                       break;
-               }
-
-       if(!this.enemy) { LOG_INFO("^1FAIL!"); delete(this); return; }
-
-       if(!this.goalentity)
-               this.goalentity = this.enemy; // make them match so CSQC knows what to do
-
-       Net_LinkEntity(this, false, 0, trigger_viewloc_send);
-
-       setthink(this, viewloc_think);
-       this.nextthink = time;
-}
-
-spawnfunc(trigger_viewlocation)
-{
-       // we won't check target2 here yet, as it may not even need to exist
-       if(this.target == "") { LOG_INFO("^1FAIL!"); delete(this); return; }
-
-       EXACTTRIGGER_INIT;
-       InitializeEntity(this, viewloc_init, INITPRIO_FINDTARGET);
-}
-
-bool viewloc_send(entity this, entity to, int sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_VIEWLOC);
-
-       WriteByte(MSG_ENTITY, this.cnt);
-
-       WriteVector(MSG_ENTITY, this.origin);
-
-       WriteAngle(MSG_ENTITY, this.angles_x);
-       WriteAngle(MSG_ENTITY, this.angles_y);
-       WriteAngle(MSG_ENTITY, this.angles_z);
-
-       return true;
-}
-
-.float angle;
-void viewloc_link(entity this)
-{
-       if(this.angle)
-               this.angles_y = this.angle;
-       Net_LinkEntity(this, false, 0, viewloc_send);
-}
-
-spawnfunc(target_viewlocation_start)
-{
-       this.classname = "target_viewlocation_start";
-       this.cnt = 1;
-       viewloc_link(this);
-}
-spawnfunc(target_viewlocation_end)
-{
-       this.classname = "target_viewlocation_end";
-       this.cnt = 2;
-       viewloc_link(this);
-}
-
-// compatibility
-spawnfunc(target_viewlocation) { spawnfunc_target_viewlocation_start(this); }
-
-#elif defined(CSQC)
-
-void trigger_viewloc_updatelink(entity this)
-{
-       this.enemy = findfloat(NULL, entnum, this.cnt);
-       this.goalentity = findfloat(NULL, entnum, this.count);
-}
-
-NET_HANDLE(ENT_CLIENT_VIEWLOC_TRIGGER, bool isnew)
-{
-       this.spawnflags = ReadByte();
-
-       float point1 = ReadShort();
-       float point2 = ReadShort();
-
-       this.enemy = findfloat(NULL, entnum, point1);
-       this.goalentity = findfloat(NULL, entnum, point2);
-
-       this.origin = ReadVector();
-
-       return = true;
-
-       setorigin(this, this.origin);
-
-       this.cnt = point1;
-       this.count = point2;
-
-       setthink(this, trigger_viewloc_updatelink);
-       this.nextthink = time + 1; // we need to delay this or else
-
-       this.classname = "trigger_viewlocation";
-       this.drawmask = MASK_NORMAL; // not so concerned, but better keep it alive
-}
-
-NET_HANDLE(ENT_CLIENT_VIEWLOC, bool isnew)
-{
-       this.cnt = ReadByte();
-
-       this.origin = ReadVector();
-       setorigin(this, this.origin);
-
-       this.movedir_x = ReadAngle();
-       this.movedir_y = ReadAngle();
-       this.movedir_z = ReadAngle();
-
-       return = true;
-
-       this.classname = ((this.cnt == 2) ? "target_viewlocation_end" : "target_viewlocation_start");
-       this.drawmask = MASK_NORMAL; // don't cull it
-}
-
-#endif
diff --git a/qcsrc/common/triggers/trigger/viewloc.qh b/qcsrc/common/triggers/trigger/viewloc.qh
deleted file mode 100644 (file)
index 69c6c82..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-
-.entity viewloc;
-
-const int VIEWLOC_NOSIDESCROLL = BIT(0); // NOTE: currently unimplemented
-const int VIEWLOC_FREEAIM = BIT(1);
-const int VIEWLOC_FREEMOVE = BIT(2);
-
-#ifdef CSQC
-.entity goalentity;
-.entity enemy;
-.vector movedir;
-#endif
diff --git a/qcsrc/common/triggers/triggers.qc b/qcsrc/common/triggers/triggers.qc
deleted file mode 100644 (file)
index fbd20c8..0000000
+++ /dev/null
@@ -1,311 +0,0 @@
-#include "triggers.qh"
-void SUB_DontUseTargets(entity this, entity actor, entity trigger) { }
-
-void SUB_UseTargets(entity this, entity actor, entity trigger);
-
-void DelayThink(entity this)
-{
-       SUB_UseTargets (this, this.enemy, NULL);
-       delete(this);
-}
-
-void FixSize(entity e)
-{
-       e.mins_x = rint(e.mins_x);
-       e.mins_y = rint(e.mins_y);
-       e.mins_z = rint(e.mins_z);
-
-       e.maxs_x = rint(e.maxs_x);
-       e.maxs_y = rint(e.maxs_y);
-       e.maxs_z = rint(e.maxs_z);
-}
-
-#ifdef SVQC
-
-bool autocvar_g_triggers_debug = true;
-
-void trigger_init(entity this)
-{
-       string m = this.model;
-       EXACTTRIGGER_INIT;
-       if(autocvar_g_triggers_debug)
-       {
-               if(m != "")
-               {
-                       precache_model(m);
-                       _setmodel(this, m); // no precision needed
-               }
-               setorigin(this, this.origin);
-               if(this.scale)
-                       setsize(this, this.mins * this.scale, this.maxs * this.scale);
-               else
-                       setsize(this, this.mins, this.maxs);
-       }
-
-       if(autocvar_g_triggers_debug)
-               BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
-}
-
-void trigger_link(entity this, bool(entity this, entity to, int sendflags) sendfunc)
-{
-       setSendEntity(this, sendfunc);
-       this.SendFlags = 0xFFFFFF;
-}
-
-void trigger_common_write(entity this, bool withtarget)
-{
-       int f = 0;
-       if(this.warpzone_isboxy)
-               BITSET_ASSIGN(f, 1);
-       if(this.origin != '0 0 0')
-               BITSET_ASSIGN(f, 4);
-       if(this.movedir != '0 0 0')
-               BITSET_ASSIGN(f, 8);
-       if(this.angles != '0 0 0')
-               BITSET_ASSIGN(f, 16);
-       WriteByte(MSG_ENTITY, f);
-
-       if(withtarget)
-       {
-               // probably some way to clean this up...
-               int targbits = 0;
-               if(this.target && this.target != "") targbits |= BIT(0);
-               if(this.target2 && this.target2 != "") targbits |= BIT(1);
-               if(this.target3 && this.target3 != "") targbits |= BIT(2);
-               if(this.target4 && this.target4 != "") targbits |= BIT(3);
-               if(this.targetname && this.targetname != "") targbits |= BIT(4);
-               if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
-
-               WriteByte(MSG_ENTITY, targbits);
-
-               if(targbits & BIT(0))
-                       WriteString(MSG_ENTITY, this.target);
-               if(targbits & BIT(1))
-                       WriteString(MSG_ENTITY, this.target2);
-               if(targbits & BIT(2))
-                       WriteString(MSG_ENTITY, this.target3);
-               if(targbits & BIT(3))
-                       WriteString(MSG_ENTITY, this.target4);
-               if(targbits & BIT(4))
-                       WriteString(MSG_ENTITY, this.targetname);
-               if(targbits & BIT(5))
-                       WriteString(MSG_ENTITY, this.killtarget);
-       }
-
-       if(f & 4)
-               WriteVector(MSG_ENTITY, this.origin);
-
-       if(f & 8)
-               WriteVector(MSG_ENTITY, this.movedir);
-
-       if(f & 16)
-               WriteVector(MSG_ENTITY, this.angles);
-
-       WriteShort(MSG_ENTITY, this.modelindex);
-       WriteVector(MSG_ENTITY, this.mins);
-       WriteVector(MSG_ENTITY, this.maxs);
-       WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
-}
-
-#elif defined(CSQC)
-
-void trigger_common_read(entity this, bool withtarget)
-{
-       int f = ReadByte();
-       this.warpzone_isboxy = (f & 1);
-
-       if(withtarget)
-       {
-               if(this.target) { strunzone(this.target); }
-               if(this.target2) { strunzone(this.target2); }
-               if(this.target3) { strunzone(this.target3); }
-               if(this.target4) { strunzone(this.target4); }
-               if(this.targetname) { strunzone(this.targetname); }
-               if(this.killtarget) { strunzone(this.killtarget); }
-
-               int targbits = ReadByte();
-
-               #define X(xs,b) MACRO_BEGIN { \
-                       if(targbits & BIT(b)) \
-                               xs = strzone(ReadString()); \
-                       else \
-                               xs = string_null; \
-               } MACRO_END
-
-               X(this.target, 0);
-               X(this.target2, 1);
-               X(this.target3, 2);
-               X(this.target4, 3);
-               X(this.targetname, 4);
-               X(this.killtarget, 5);
-               #undef X
-       }
-
-       if(f & 4)
-               this.origin = ReadVector();
-       else
-               this.origin = '0 0 0';
-       setorigin(this, this.origin);
-
-       if(f & 8)
-               this.movedir = ReadVector();
-       else
-               this.movedir = '0 0 0';
-
-       if(f & 16)
-               this.angles = ReadVector();
-       else
-               this.angles = '0 0 0';
-
-       this.modelindex = ReadShort();
-       this.mins = ReadVector();
-       this.maxs = ReadVector();
-       this.scale = ReadByte() / 16;
-       setsize(this, this.mins, this.maxs);
-}
-
-void trigger_remove_generic(entity this)
-{
-       if(this.target) { strunzone(this.target); }
-       this.target = string_null;
-
-       if(this.target2) { strunzone(this.target2); }
-       this.target2 = string_null;
-
-       if(this.target3) { strunzone(this.target3); }
-       this.target3 = string_null;
-
-       if(this.target4) { strunzone(this.target4); }
-       this.target4 = string_null;
-
-       if(this.targetname) { strunzone(this.targetname); }
-       this.target = string_null;
-
-       if(this.killtarget) { strunzone(this.killtarget); }
-       this.killtarget = string_null;
-}
-#endif
-
-
-/*
-==============================
-SUB_UseTargets
-
-the global "activator" should be set to the entity that initiated the firing.
-
-If this.delay is set, a DelayedUse entity will be created that will actually
-do the SUB_UseTargets after that many seconds have passed.
-
-Centerprints any this.message to the activator.
-
-Removes all entities with a targetname that match this.killtarget,
-and removes them, so some events can remove other triggers.
-
-Search for (string)targetname in all entities that
-match (string)this.target and call their .use function
-
-==============================
-*/
-
-void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse)
-{
-//
-// check for a delay
-//
-       if (this.delay)
-       {
-       // create a temp object to fire at a later time
-               entity t = new(DelayedUse);
-               t.nextthink = time + this.delay;
-               setthink(t, DelayThink);
-               t.enemy = actor;
-               t.message = this.message;
-               t.killtarget = this.killtarget;
-               t.target = this.target;
-               t.target2 = this.target2;
-               t.target3 = this.target3;
-               t.target4 = this.target4;
-               t.antiwall_flag = this.antiwall_flag;
-               return;
-       }
-
-       string s;
-
-//
-// print the message
-//
-#ifdef SVQC
-       if(this)
-       if(IS_PLAYER(actor) && this.message != "")
-       if(IS_REAL_CLIENT(actor))
-       {
-               centerprint(actor, this.message);
-               if (this.noise == "")
-                       play2(actor, SND(TALK));
-       }
-
-//
-// kill the killtagets
-//
-       s = this.killtarget;
-       if (s != "")
-       {
-               for(entity t = NULL; (t = find(t, targetname, s)); )
-                       delete(t);
-       }
-#endif
-
-//
-// fire targets
-//
-
-       if(this.target_random)
-               RandomSelection_Init();
-
-       for(int i = 0; i < 4; ++i)
-       {
-               switch(i)
-               {
-                       default:
-                       case 0: s = this.target; break;
-                       case 1: s = this.target2; break;
-                       case 2: s = this.target3; break;
-                       case 3: s = this.target4; break;
-               }
-               if (s != "")
-               {
-                       // Flag to set func_clientwall state
-                       // 1 == deactivate, 2 == activate, 0 == do nothing
-                       int aw_flag = this.antiwall_flag;
-                       for(entity t = NULL; (t = find(t, targetname, s)); )
-                       {
-                               if(t.use && (t.sub_target_used != time || !preventReuse))
-                               {
-                                       if(this.target_random)
-                                       {
-                                               RandomSelection_AddEnt(t, 1, 0);
-                                       }
-                                       else
-                                       {
-                                               if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
-                                                       t.antiwall_flag = aw_flag;
-
-                                               t.use(t, actor, this);
-                                               if(preventReuse)
-                                                       t.sub_target_used = time;
-                                       }
-                               }
-                       }
-               }
-       }
-
-       if(this.target_random && RandomSelection_chosen_ent)
-       {
-               RandomSelection_chosen_ent.use(RandomSelection_chosen_ent, actor, this);
-               if(preventReuse)
-                       RandomSelection_chosen_ent.sub_target_used = time;
-       }
-}
-
-void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false); }
-void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true); }
diff --git a/qcsrc/common/triggers/triggers.qh b/qcsrc/common/triggers/triggers.qh
deleted file mode 100644 (file)
index 2b8274f..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-#pragma once
-
-const float SF_TRIGGER_INIT = 1;
-const float SF_TRIGGER_UPDATE = 2;
-const float SF_TRIGGER_RESET = 4;
-
-const float    SPAWNFLAG_NOMESSAGE = 1;
-const float    SPAWNFLAG_NOTOUCH = 1;
-
-.bool pushable;
-
-.float antiwall_flag; // Variable to define what to do with func_clientwall
-// 0 == do nothing, 1 == deactivate, 2 == activate
-
-.float height;
-
-.float nottargeted;
-#define IFTARGETED if(!this.nottargeted && this.targetname != "")
-
-.float lip;
-
-// used elsewhere (will fix)
-#ifdef SVQC
-void trigger_common_write(entity this, bool withtarget);
-
-string trigger_magicear_processmessage_forallears(entity source, float teamsay, entity privatesay, string msgin);
-
-void target_voicescript_next(entity pl);
-void target_voicescript_clear(entity pl);
-
-void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger);
-#endif
-
-.float sub_target_used;
-
-.float volume, atten;
-
-.vector dest;
-
-void FixSize(entity e);
-
-#ifdef CSQC
-void trigger_common_read(entity this, bool withtarget);
-void trigger_remove_generic(entity this);
-
-.float active;
-.string target;
-.string targetname;
-
-const int ACTIVE_NOT           = 0;
-const int ACTIVE_ACTIVE        = 1;
-const int ACTIVE_IDLE          = 2;
-const int ACTIVE_BUSY          = 2;
-const int ACTIVE_TOGGLE                = 3;
-#endif
index 2a7c41c98c9a8a7175a5b9b5af8acc07d31f6cff..06f8bab9c92a1543b953245fe22af8a1ff3dde62 100644 (file)
@@ -1239,6 +1239,12 @@ void turret_initparams(entity tur)
        #undef TRY
 }
 
+bool turret_closetotarget(entity this, vector targ)
+{
+       vector path_extra_size = '64 64 64';
+       return boxesoverlap(targ - path_extra_size, targ + path_extra_size, this.absmin - path_extra_size, this.absmax + path_extra_size);
+}
+
 void turret_findtarget(entity this)
 {
        entity e = find(NULL, classname, "turret_manager");
index 41a7bd962dc6e8a19ffcef03eb4291db7e55ed29..deee313ab109204ce7e1acbba2cb1aaaa6921aac 100644 (file)
@@ -89,6 +89,9 @@ void turrets_setframe(entity this, float _frame, float client_only);
 
 bool turret_initialize(entity this, Turret tur);
 
+// returns true when box overlaps with a given location
+bool turret_closetotarget(entity this, vector targ);
+
 /// Function to use for target evaluation. usualy turret_targetscore_generic
 .float(entity _turret, entity _target) turret_score_target;
 
index 5625d23fc935e8be8453afb9517ef40e333243a8..9a9001c42d39a99c14434ae662ef4602e3835536 100644 (file)
@@ -17,7 +17,7 @@ const int ewheel_anim_bck_fast = 4;
 void ewheel_move_path(entity this)
 {
     // Are we close enough to a path node to switch to the next?
-    if(vdist(this.origin - this.pathcurrent.origin, <, 64))
+    if(turret_closetotarget(this, this.pathcurrent.origin))
     {
 #ifdef EWHEEL_FANCYPATH
         if (this.pathcurrent.path_next == NULL)
@@ -49,7 +49,6 @@ void ewheel_move_path(entity this)
 
     if (this.pathcurrent)
     {
-
         this.moveto = this.pathcurrent.origin;
         this.steerto = steerlib_attract2(this, this.moveto, 0.5, 500, 0.95);
 
index 96fa81f8eee98cdbbf72ce9761e2f5eaf2c1c717..89ddfbd4f1ca6a28df7f9d45339b016d01923144 100644 (file)
@@ -6,7 +6,7 @@ spawnfunc(turret_plasma) { if (!turret_initialize(this, TUR_PLASMA)) delete(this
 
 METHOD(PlasmaTurret, tr_attack, void(PlasmaTurret this, entity it))
 {
-    if(g_instagib)
+    if(MUTATOR_IS_ENABLED(mutator_instagib))
     {
         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
         FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * max_shot_distance, 10000000000,
index 2a6f997cf3f009f533858d9099c0fb3492e2b7c3..9fa10eefff01e8a2c7cf0a9cbd305014f7be13e4 100644 (file)
@@ -6,7 +6,7 @@ spawnfunc(turret_plasma_dual) { if (!turret_initialize(this, TUR_PLASMA_DUAL)) d
 
 METHOD(DualPlasmaTurret, tr_attack, void(DualPlasmaTurret thistur, entity it))
 {
-    if (g_instagib) {
+    if (MUTATOR_IS_ENABLED(mutator_instagib)) {
         .entity weaponentity = weaponentities[0]; // TODO: unhardcode
         FireRailgunBullet (it, weaponentity, it.tur_shotorg, it.tur_shotorg + it.tur_shotdir_updated * max_shot_distance, 10000000000,
                            800, 0, 0, 0, 0, DEATH_TURRET_PLASMA.m_id);
index 04436c47f8c728af20a160318ce5456999aa3b53..6fdfd32e70cd51c05a1fa6a8a067c7a9d60b8905 100644 (file)
@@ -3,6 +3,7 @@
 #include "plasma_weapon.qh"
 
 CLASS(PlasmaDualAttack, PlasmaAttack)
+/* flags     */ ATTRIB(PlasmaDualAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* refname   */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
 /* wepname   */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
 ENDCLASS(PlasmaDualAttack)
index 8cf795a93895887139b2b014543af8c1623a6d97..93b9483defa5fc06cc1f91ff0dfba51d840934c8 100644 (file)
@@ -281,7 +281,8 @@ void walker_move_path(entity this)
 {
 #ifdef WALKER_FANCYPATHING
     // Are we close enougth to a path node to switch to the next?
-    if(vdist(this.origin - this.pathcurrent.origin, <, 64))
+    if(turret_closetotarget(this, this.pathcurrent.origin))
+    {
         if (this.pathcurrent.path_next == NULL)
         {
             // Path endpoint reached
@@ -304,13 +305,14 @@ void walker_move_path(entity this)
         }
         else
             this.pathcurrent = this.pathcurrent.path_next;
+    }
 
     this.moveto = this.pathcurrent.origin;
     this.steerto = steerlib_attract2(this, this.moveto,0.5,500,0.95);
     walker_move_to(this, this.moveto, 0);
 
 #else
-    if(vdist(this.origin - this.pathcurrent.origin, <, 64))
+    if(turret_closetotarget(this, this.pathcurrent.origin))
         this.pathcurrent = this.pathcurrent.enemy;
 
     if(!this.pathcurrent)
@@ -352,7 +354,7 @@ METHOD(WalkerTurret, tr_think, void(WalkerTurret thistur, entity it))
 {
     fixedmakevectors(it.angles);
 
-    if (it.spawnflags & TSF_NO_PATHBREAK && it.pathcurrent)
+    if ((it.spawnflags & TSF_NO_PATHBREAK) && it.pathcurrent)
         walker_move_path(it);
     else if (it.enemy == NULL)
     {
index 4c84f268d3024679102f158cf5e017bf229ff28a..4e5cb0d5b970a1b7cd57413db2fd5ca6649bf137 100644 (file)
@@ -5,4 +5,10 @@
 float turret_tag_fire_update(entity this);
 void FireImoBeam(entity this, vector start, vector end, vector smin, vector smax, float bforce, float f_dmg, float f_velfactor, float deathtype);
 
+#ifdef TURRET_DEBUG
+void mark_error(vector where,float lifetime);
+void mark_info(vector where,float lifetime);
+entity mark_misc(vector where,float lifetime);
+#endif
+
 #endif
index deba86c289dc8f4966407fa6dd6f7c4f9e308ed8..183302b3a1e0460c246c9c1c8357edfbace43c53 100644 (file)
@@ -2,7 +2,7 @@
 
 #if defined(CSQC)
     #include "constants.qh"
-       #include "../client/mutators/events.qh"
+       #include <client/mutators/_mod.qh>
     #include "mapinfo.qh"
     #include "notifications/all.qh"
        #include "scores.qh"
 #elif defined(MENUQC)
 #elif defined(SVQC)
     #include "constants.qh"
-       #include "../server/mutators/events.qh"
+       #include <server/mutators/_mod.qh>
     #include "notifications/all.qh"
     #include <common/deathtypes/all.qh>
        #include "scores.qh"
     #include "mapinfo.qh"
 #endif
 
+#ifdef SVQC
+float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
+{
+       vector pos, dir, t;
+       float nudge;
+       entity stopentity;
+
+       //nudge = 2 * cvar("collision_impactnudge"); // why not?
+       nudge = 0.5;
+
+       dir = normalize(v2 - v1);
+
+       pos = v1 + dir * nudge;
+
+       float c;
+       c = 0;
+
+       for (;;)
+       {
+               if(pos * dir >= v2 * dir)
+               {
+                       // went too far
+                       trace_fraction = 1;
+                       trace_endpos = v2;
+                       return c;
+               }
+
+               tracebox(pos, mi, ma, v2, nomonsters, forent);
+               ++c;
+
+               if(c == 50)
+               {
+                       LOG_TRACE("When tracing from ", vtos(v1), " to ", vtos(v2));
+                       LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos));
+                       LOG_TRACE("  trace_endpos is ", vtos(trace_endpos));
+                       LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)));
+               }
+
+               stopentity = trace_ent;
+
+               if(trace_startsolid)
+               {
+                       // we started inside solid.
+                       // then trace from endpos to pos
+                       t = trace_endpos;
+                       tracebox(t, mi, ma, pos, nomonsters, forent);
+                       ++c;
+                       if(trace_startsolid)
+                       {
+                               // t is still inside solid? bad
+                               // force advance, then, and retry
+                               pos = t + dir * nudge;
+
+                               // but if we hit an entity, stop RIGHT before it
+                               if(stopatentity && stopentity && stopentity != ignorestopatentity)
+                               {
+                                       trace_ent = stopentity;
+                                       trace_endpos = t;
+                                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                                       return c;
+                               }
+                       }
+                       else
+                       {
+                               // we actually LEFT solid!
+                               trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                               return c;
+                       }
+               }
+               else
+               {
+                       // pos is outside solid?!? but why?!? never mind, just return it.
+                       trace_endpos = pos;
+                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
+                       return c;
+               }
+       }
+}
+
+void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
+{
+       tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
+}
+#endif
+
 #ifdef GAMEQC
+/*
+==================
+findbetterlocation
+
+Returns a point at least 12 units away from walls
+(useful for explosion animations, although the blast is performed where it really happened)
+Ripped from DPMod
+==================
+*/
+vector findbetterlocation (vector org, float mindist)
+{
+       vector vec = mindist * '1 0 0';
+       int c = 0;
+       while (c < 6)
+       {
+               traceline (org, org + vec, true, NULL);
+               vec = vec * -1;
+               if (trace_fraction < 1)
+               {
+                       vector loc = trace_endpos;
+                       traceline (loc, loc + vec, true, NULL);
+                       if (trace_fraction >= 1)
+                               org = loc + vec;
+               }
+               if (c & 1)
+               {
+                       float h = vec.y;
+                       vec.y = vec.x;
+                       vec.x = vec.z;
+                       vec.z = h;
+               }
+               c = c + 1;
+       }
+
+       return org;
+}
+
 /*
 * Get "real" origin, in worldspace, even if ent is attached to something else.
 */
@@ -336,19 +458,18 @@ STATIC_INIT(compressShortVector)
 
        if(cvar("developer"))
        {
-               LOG_INFO("Verifying vector compression table...");
+               LOG_TRACE("Verifying vector compression table...");
                for(i = 0x0F00; i < 0xFFFF; ++i)
                        if(i != compressShortVector(decompressShortVector(i)))
                        {
-                               LOG_INFOF(
+                               LOG_FATALF(
                                    "BROKEN vector compression: %s -> %s -> %s",
                                    ftos(i),
                                    vtos(decompressShortVector(i)),
                                    ftos(compressShortVector(decompressShortVector(i)))
                 );
-                               error("b0rk");
                        }
-               LOG_INFO("Done.");
+               LOG_TRACE("Done.");
        }
 }
 
@@ -453,14 +574,12 @@ void get_mi_min_max(float mode)
 {
        vector mi, ma;
 
-       if(mi_shortname)
-               strunzone(mi_shortname);
-       mi_shortname = mapname;
-       if(!strcasecmp(substring(mi_shortname, 0, 5), "maps/"))
-               mi_shortname = substring(mi_shortname, 5, strlen(mi_shortname) - 5);
-       if(!strcasecmp(substring(mi_shortname, strlen(mi_shortname) - 4, 4), ".bsp"))
-               mi_shortname = substring(mi_shortname, 0, strlen(mi_shortname) - 4);
-       mi_shortname = strzone(mi_shortname);
+       string s = mapname;
+       if(!strcasecmp(substring(s, 0, 5), "maps/"))
+               s = substring(s, 5, strlen(s) - 5);
+       if(!strcasecmp(substring(s, strlen(s) - 4, 4), ".bsp"))
+               s = substring(s, 0, strlen(s) - 4);
+       strcpy(mi_shortname, s);
 
 #ifdef CSQC
        mi = world.mins;
@@ -1129,6 +1248,8 @@ vector healtharmor_applydamage(float a, float armorblock, int deathtype, float d
        vector v;
        if (DEATH_IS(deathtype, DEATH_DROWN))  // Why should armor help here...
                armorblock = 0;
+       if (deathtype & HITTYPE_ARMORPIERCE)
+               armorblock = 0;
        v.y = bound(0, damage * armorblock, a); // save
        v.x = bound(0, damage - v.y, damage); // take
        v.z = 0;
@@ -1397,8 +1518,7 @@ void execute_next_frame()
        if(to_execute_next_frame)
        {
                localcmd("\n", to_execute_next_frame, "\n");
-               strunzone(to_execute_next_frame);
-               to_execute_next_frame = string_null;
+               strfree(to_execute_next_frame);
        }
 }
 void queue_to_execute_next_frame(string s)
@@ -1406,9 +1526,8 @@ void queue_to_execute_next_frame(string s)
        if(to_execute_next_frame)
        {
                s = strcat(s, "\n", to_execute_next_frame);
-               strunzone(to_execute_next_frame);
        }
-       to_execute_next_frame = strzone(s);
+       strcpy(to_execute_next_frame, s);
 }
 
 .float FindConnectedComponent_processing;
index 3304d0e7a455453b02615f44a5664bfaafe8cbdb..a1c0d6785fb416efa1b02c641d409b1e5e05d407 100644 (file)
@@ -1,6 +1,27 @@
 #pragma once
 
+#ifdef SVQC
+       #include <server/autocvars.qh>
+#endif
+
+#ifdef SVQC
+float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity); // returns the number of traces done, for benchmarking
+
+void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity);
+#endif
+
 #ifdef GAMEQC
+/*
+==================
+findbetterlocation
+
+Returns a point at least 12 units away from walls
+(useful for explosion animations, although the blast is performed where it really happened)
+Ripped from DPMod
+==================
+*/
+vector findbetterlocation (vector org, float mindist);
+
 vector real_origin(entity ent);
 #endif
 
index 0ddd02aa7e0ce77125b2a9dc835df604c54d8cf0..d0f63c96a3d77258d25ff5d80ed98208b6ddd677 100644 (file)
@@ -107,6 +107,7 @@ bool vehicle_initialize(entity this, Vehicle info, float nodrop);
 bool vehicle_impulse(entity this, int imp);
 bool vehicles_crushable(entity e);
 float vehicle_altitude(entity this, float amax);
+void vehicles_enter(entity pl, entity veh);
 
 IntrusiveList g_vehicle_returners;
 STATIC_INIT(g_vehicle_returners) { g_vehicle_returners = IL_NEW(); }
index 70ee753e0ed3b282abb80bcaaedef181ce44d5ee..93ed6d31d531ac6b06baa424090d54718f8d2219 100644 (file)
@@ -1,7 +1,7 @@
 #include "racer.qh"
 
 #ifdef SVQC
-#include <common/triggers/trigger/impulse.qh>
+#include <common/mapobjects/trigger/impulse.qh>
 
 bool autocvar_g_vehicle_racer = true;
 
@@ -137,16 +137,16 @@ void racer_align4point(entity this, float _delta)
        this.angles_z *= 1 - (autocvar_g_vehicle_racer_anglestabilizer * _delta);
 }
 
-void racer_fire_rocket_aim(entity player, string tagname, entity trg)
+void racer_fire_rocket_aim(entity this, entity player, string tagname, entity trg)
 {
-       entity racer = player.vehicle;
-       vector v = gettaginfo(racer, gettagindex(racer, tagname));
+       vector v = gettaginfo(this, gettagindex(this, tagname));
        racer_fire_rocket(player, v, v_forward, trg);
 }
 
 bool racer_frame(entity this, float dt)
 {
-       entity vehic = this.vehicle;
+       entity player = this;
+       entity vehic = player.vehicle;
        return = true;
 
        if(game_stopped)
@@ -157,28 +157,27 @@ bool racer_frame(entity this, float dt)
                return;
        }
 
-       vehicles_frame(vehic, this);
+       vehicles_frame(vehic, player);
 
-       traceline(vehic.origin, vehic.origin + '0 0 1', MOVE_NOMONSTERS, this);
-       int cont = trace_dpstartcontents;
+       int cont = Mod_Q1BSP_SuperContentsFromNativeContents(pointcontents(vehic.origin));
        if(!(cont & DPCONTENTS_WATER))
                vehic.air_finished = time + autocvar_g_vehicle_racer_water_time;
 
        if(IS_DEAD(vehic))
        {
-               PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
+               PHYS_INPUT_BUTTON_ATCK(player) = PHYS_INPUT_BUTTON_ATCK2(player) = false;
                return;
        }
 
        racer_align4point(vehic, dt);
 
-       PHYS_INPUT_BUTTON_ZOOM(this) = PHYS_INPUT_BUTTON_CROUCH(this) = false;
+       PHYS_INPUT_BUTTON_ZOOM(player) = PHYS_INPUT_BUTTON_CROUCH(player) = false;
 
        vehic.angles_x *= -1;
 
        // Yaw
        float ftmp = autocvar_g_vehicle_racer_turnspeed * dt;
-       ftmp = bound(-ftmp, shortangle_f(this.v_angle_y - vehic.angles_y, vehic.angles_y), ftmp);
+       ftmp = bound(-ftmp, shortangle_f(player.v_angle_y - vehic.angles_y, vehic.angles_y), ftmp);
        vehic.angles_y = anglemods(vehic.angles_y + ftmp);
 
        // Roll
@@ -186,7 +185,7 @@ bool racer_frame(entity this, float dt)
 
        // Pitch
        ftmp = autocvar_g_vehicle_racer_pitchspeed  * dt;
-       ftmp = bound(-ftmp, shortangle_f(this.v_angle_x - vehic.angles_x, vehic.angles_x), ftmp);
+       ftmp = bound(-ftmp, shortangle_f(player.v_angle_x - vehic.angles_x, vehic.angles_x), ftmp);
        vehic.angles_x = bound(-autocvar_g_vehicle_racer_pitchlimit, anglemods(vehic.angles_x + ftmp), autocvar_g_vehicle_racer_pitchlimit);
 
        makevectors(vehic.angles);
@@ -196,17 +195,17 @@ bool racer_frame(entity this, float dt)
        vector df = vehic.velocity * -autocvar_g_vehicle_racer_friction;
        //vehic.velocity_z = ftmp;
 
-       if(CS(this).movement)
+       if(CS(player).movement)
        {
                if(cont & DPCONTENTS_LIQUIDSMASK)
                {
-                       if(CS(this).movement_x) { df += v_forward * ((CS(this).movement_x > 0) ? autocvar_g_vehicle_racer_water_speed_forward : -autocvar_g_vehicle_racer_water_speed_forward); }
-                       if(CS(this).movement_y) { df += v_right * ((CS(this).movement_y > 0) ? autocvar_g_vehicle_racer_water_speed_strafe : -autocvar_g_vehicle_racer_water_speed_strafe); }
+                       if(CS(player).movement_x) { df += v_forward * ((CS(player).movement_x > 0) ? autocvar_g_vehicle_racer_water_speed_forward : -autocvar_g_vehicle_racer_water_speed_forward); }
+                       if(CS(player).movement_y) { df += v_right * ((CS(player).movement_y > 0) ? autocvar_g_vehicle_racer_water_speed_strafe : -autocvar_g_vehicle_racer_water_speed_strafe); }
                }
                else
                {
-                       if(CS(this).movement_x) { df += v_forward * ((CS(this).movement_x > 0) ? autocvar_g_vehicle_racer_speed_forward : -autocvar_g_vehicle_racer_speed_forward); }
-                       if(CS(this).movement_y) { df += v_right * ((CS(this).movement_y > 0) ? autocvar_g_vehicle_racer_speed_strafe : -autocvar_g_vehicle_racer_speed_strafe); }
+                       if(CS(player).movement_x) { df += v_forward * ((CS(player).movement_x > 0) ? autocvar_g_vehicle_racer_speed_forward : -autocvar_g_vehicle_racer_speed_forward); }
+                       if(CS(player).movement_y) { df += v_right * ((CS(player).movement_y > 0) ? autocvar_g_vehicle_racer_speed_strafe : -autocvar_g_vehicle_racer_speed_strafe); }
                }
 
 #ifdef SVQC
@@ -231,7 +230,7 @@ bool racer_frame(entity this, float dt)
 #endif
 
        // Afterburn
-       if (PHYS_INPUT_BUTTON_JUMP(this) && vehic.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * dt))
+       if (PHYS_INPUT_BUTTON_JUMP(player) && vehic.vehicle_energy >= (autocvar_g_vehicle_racer_afterburn_cost * dt))
        {
 #ifdef SVQC
                if(time - vehic.wait > 0.2)
@@ -282,14 +281,14 @@ bool racer_frame(entity this, float dt)
                dforce = autocvar_g_vehicle_racer_water_downforce;
 
        df -= v_up * (vlen(vehic.velocity) * dforce);
-       CS(this).movement = vehic.velocity += df * dt;
+       CS(player).movement = vehic.velocity += df * dt;
 
 #ifdef SVQC
 
        Weapon wep1 = WEP_RACER;
        .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-       if (!forbidWeaponUse(this))
-       if (PHYS_INPUT_BUTTON_ATCK(this))
+       if (!forbidWeaponUse(player))
+       if (PHYS_INPUT_BUTTON_ATCK(player))
        if (wep1.wr_checkammo1(wep1, vehic, weaponentity))
        {
                string tagname = (vehic.cnt)
@@ -299,7 +298,7 @@ bool racer_frame(entity this, float dt)
                w_shotorg = org;
                w_shotdir = v_forward;
                // Fix z-aim (for chase mode)
-               crosshair_trace(this);
+               crosshair_trace(player);
                w_shotdir.z = normalize(trace_endpos - org).z * 0.5;
                wep1.wr_think(wep1, vehic, weaponentity, 1);
        }
@@ -308,7 +307,7 @@ bool racer_frame(entity this, float dt)
        {
                if(time >= vehic.vehicle_last_trace)
                {
-                       crosshair_trace(this);
+                       crosshair_trace(player);
 
                        vehicles_locktarget(vehic, (1 / autocvar_g_vehicle_racer_rocket_locking_time) * dt,
                                                         (1 / autocvar_g_vehicle_racer_rocket_locking_releasetime) * dt,
@@ -320,63 +319,63 @@ bool racer_frame(entity this, float dt)
                if(vehic.lock_target)
                {
                        if(vehic.lock_strength == 1)
-                               UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '1 0 0', 0);
+                               UpdateAuxiliaryXhair(player, real_origin(vehic.lock_target), '1 0 0', 0);
                        else if(vehic.lock_strength > 0.5)
-                               UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '0 1 0', 0);
+                               UpdateAuxiliaryXhair(player, real_origin(vehic.lock_target), '0 1 0', 0);
                        else if(vehic.lock_strength < 0.5)
-                               UpdateAuxiliaryXhair(this, real_origin(vehic.lock_target), '0 0 1', 0);
+                               UpdateAuxiliaryXhair(player, real_origin(vehic.lock_target), '0 0 1', 0);
                }
        }
 
-       if(!forbidWeaponUse(this))
+       if(!forbidWeaponUse(player))
        if(time > vehic.delay)
-       if(PHYS_INPUT_BUTTON_ATCK2(this))
+       if(PHYS_INPUT_BUTTON_ATCK2(player))
        {
                vehic.misc_bulletcounter += 1;
                vehic.delay = time + 0.3;
 
                if(vehic.misc_bulletcounter == 1)
                {
-                       racer_fire_rocket_aim(this, "tag_rocket_r", (vehic.lock_strength == 1 && vehic.lock_target) ? vehic.lock_target : NULL);
-                       this.vehicle_ammo2 = 50;
+                       racer_fire_rocket_aim(vehic, player, "tag_rocket_r", (vehic.lock_strength == 1 && vehic.lock_target) ? vehic.lock_target : NULL);
+                       player.vehicle_ammo2 = 50;
                }
                else if(vehic.misc_bulletcounter == 2)
                {
-                       racer_fire_rocket_aim(this, "tag_rocket_l", (vehic.lock_strength == 1 && vehic.lock_target) ? vehic.lock_target : NULL);
+                       racer_fire_rocket_aim(vehic, player, "tag_rocket_l", (vehic.lock_strength == 1 && vehic.lock_target) ? vehic.lock_target : NULL);
                        vehic.lock_strength  = 0;
                        vehic.lock_target       = NULL;
                        vehic.misc_bulletcounter = 0;
                        vehic.delay = time + autocvar_g_vehicle_racer_rocket_refire;
                        vehic.lip = time;
-                       this.vehicle_ammo2 = 0;
+                       player.vehicle_ammo2 = 0;
                }
        }
        else if(vehic.misc_bulletcounter == 0)
-               this.vehicle_ammo2 = 100;
+               player.vehicle_ammo2 = 100;
 
-       this.vehicle_reload2 = bound(0, 100 * ((time - vehic.lip) / (vehic.delay - vehic.lip)), 100);
+       player.vehicle_reload2 = bound(0, 100 * ((time - vehic.lip) / (vehic.delay - vehic.lip)), 100);
 
-       if(vehic.vehicle_flags  & VHF_SHIELDREGEN)
+       if(vehic.vehicle_flags & VHF_SHIELDREGEN)
                vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_racer_shield, autocvar_g_vehicle_racer_shield_regen_pause, autocvar_g_vehicle_racer_shield_regen, dt, true);
 
-       if(vehic.vehicle_flags  & VHF_HEALTHREGEN)
+       if(vehic.vehicle_flags & VHF_HEALTHREGEN)
                vehicles_regen(vehic, vehic.dmg_time, vehicle_health, autocvar_g_vehicle_racer_health, autocvar_g_vehicle_racer_health_regen_pause, autocvar_g_vehicle_racer_health_regen, dt, false);
 
-       if(vehic.vehicle_flags  & VHF_ENERGYREGEN)
+       if(vehic.vehicle_flags & VHF_ENERGYREGEN)
                vehicles_regen(vehic, vehic.wait, vehicle_energy, autocvar_g_vehicle_racer_energy, autocvar_g_vehicle_racer_energy_regen_pause, autocvar_g_vehicle_racer_energy_regen, dt, false);
 
-       VEHICLE_UPDATE_PLAYER(this, vehic, health, racer);
-       VEHICLE_UPDATE_PLAYER(this, vehic, energy, racer);
+       VEHICLE_UPDATE_PLAYER(player, vehic, health, racer);
+       VEHICLE_UPDATE_PLAYER(player, vehic, energy, racer);
 
        if(vehic.vehicle_flags & VHF_HASSHIELD)
-               VEHICLE_UPDATE_PLAYER(this, vehic, shield, racer);
+               VEHICLE_UPDATE_PLAYER(player, vehic, shield, racer);
 
-       PHYS_INPUT_BUTTON_ATCK(this) = PHYS_INPUT_BUTTON_ATCK2(this) = false;
+       PHYS_INPUT_BUTTON_ATCK(player) = PHYS_INPUT_BUTTON_ATCK2(player) = false;
 #endif
 
-       setorigin(this, vehic.origin + '0 0 32');
-       this.oldorigin = this.origin; // negate fall damage
-       this.velocity = vehic.velocity;
+       setorigin(player, vehic.origin + '0 0 32');
+       player.oldorigin = player.origin; // negate fall damage
+       player.velocity = vehic.velocity;
 }
 
 void racer_think(entity this)
index e4e5ba991bec4fafa3dfc4bfbe278d69f4e2214c..f2dab7bfd22cd7c8620f3b69e7c10d9f37ece242 100644 (file)
@@ -199,4 +199,10 @@ void viewloc_SetViewLocation()
        }
 }
 
+STATIC_INIT_LATE(viewloc_cursor)
+{
+       // fix the mouse position on init so it isn't in the corner
+       viewloc_mousepos = '0.5 0 0' * autocvar_vid_conwidth + '0 0.5 0' * autocvar_vid_conheight;
+}
+
 #endif
index dca20d0cdbf1b627bf920ddee47aeb93c60ce58d..f118a04667f39c181eb0dee13eede8cc59d42973 100644 (file)
@@ -123,6 +123,8 @@ string W_UndeprecateName(string s)
                case "minstanex": return "vaporizer";
                case "grenadelauncher": return "mortar";
                case "uzi": return "machinegun";
+               case "hmg": return "okhmg";
+               case "rpc": return "okrpc";
                default: return s;
        }
 }
@@ -192,9 +194,8 @@ string W_FixWeaponOrder_ForceComplete(string order)
        return W_FixWeaponOrder(order, 1);
 }
 
-void W_RandomWeapons(entity e, int n)
+WepSet W_RandomWeapons(entity e, WepSet remaining, int n)
 {
-       WepSet remaining = e.weapons;
        WepSet result = '0 0 0';
        for (int j = 0; j < n; ++j)
        {
@@ -207,7 +208,7 @@ void W_RandomWeapons(entity e, int n)
                result |= WepSet_FromWeapon(w);
                remaining &= ~WepSet_FromWeapon(w);
        }
-       e.weapons = result;
+       return result;
 }
 
 string GetAmmoPicture(int ammotype)
index 0af47590078a8dde4c44257de429ff240e0dd19e..9b4c0b46814308dfb037375345a6100c14d444f4 100644 (file)
@@ -304,7 +304,6 @@ STATIC_INIT(register_weapons_done)
         WepSet set = it.m_wepset = _WepSet_FromWeapon(it.m_id = i);
         WEPSET_ALL |= set;
         if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
-        it.weapons = set;
         if (it == WEP_Null) continue;
         int imp = WEP_IMPULSE_BEGIN + it.m_id - 1;
         if (imp <= WEP_IMPULSE_END)
@@ -368,4 +367,8 @@ ENUMCLASS_END(WFRAME)
 
 vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn);
 void CL_WeaponEntity_SetModel(entity this, string name, bool _anim);
+
+#ifdef SVQC
+void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim);
+#endif
 #endif
index 460d95af65e685253865e8cdd65d1abc35fd6ece..a3f2336a9487b275a8a130a031295c462072d77b 100644 (file)
@@ -44,8 +44,6 @@ CLASS(Weapon, Object)
     ATTRIB(Weapon, m_canonical_spawnfunc, string);
     /** control what happens when this weapon is spawned */
     METHOD(Weapon, m_spawnfunc_hookreplace, Weapon(Weapon this, entity e)) { return this; }
-    /** A: WEPSET_id : WEPSET_... */
-    ATTRIB(Weapon, weapons, WepSet, '0 0 0');
     /** M: ammotype  : main ammo type */
     ATTRIB(Weapon, ammo_type, int, RESOURCE_NONE);
     /** M: impulse   : weapon impulse */
@@ -211,7 +209,7 @@ string W_NumberWeaponOrder(string order);
 string W_FixWeaponOrder_BuildImpulseList(string o);
 string W_FixWeaponOrder_AllowIncomplete(entity this, string order);
 string W_FixWeaponOrder_ForceComplete(string order);
-void W_RandomWeapons(entity e, int n);
+WepSet W_RandomWeapons(entity e, WepSet remaining, int n);
 
 string GetAmmoPicture(int ammotype);
 
index 21ca117f4c4ec89980bbb60f9e34e3c4b88a549c..e5d4f2eb23253dccbe414e522d0bc5ec84e8c1f0 100644 (file)
@@ -752,6 +752,9 @@ METHOD(Arc, wr_playerdeath, void(entity thiswep, entity actor, .entity weaponent
 #endif
 #ifdef CSQC
 bool autocvar_cl_arcbeam_teamcolor = true;
+bool autocvar_cl_arcbeam_simple = true;
+
+.int beam_slot;
 
 METHOD(Arc, wr_impacteffect, void(entity thiswep, entity actor))
 {
@@ -802,32 +805,37 @@ void Draw_ArcBeam_callback(vector start, vector hit, vector end)
        vector last_top = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_top);
        vector last_bottom = WarpZone_TransformOrigin(WarpZone_trace_transform, Draw_ArcBeam_callback_last_bottom);
 
-       R_BeginPolygon(beam.beam_image, DRAWFLAG_NORMAL); // DRAWFLAG_ADDITIVE
-       R_PolygonVertex(
-               top,
-               '0 0.5 0' + ('0 0.5 0' * (thickness / beam.beam_thickness)),
-               beam.beam_color,
-               beam.beam_alpha
-       );
-       R_PolygonVertex(
-               last_top,
-               '0 0.5 0' + ('0 0.5 0' * (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
-               beam.beam_color,
-               beam.beam_alpha
-       );
-       R_PolygonVertex(
-               last_bottom,
-               '0 0.5 0' * (1 - (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
-               beam.beam_color,
-               beam.beam_alpha
-       );
-       R_PolygonVertex(
-               bottom,
-               '0 0.5 0' * (1 - (thickness / beam.beam_thickness)),
-               beam.beam_color,
-               beam.beam_alpha
-       );
-       R_EndPolygon();
+       if(autocvar_cl_arcbeam_simple)
+               Draw_CylindricLine(start, end, thickness, beam.beam_image, 0.25, -time * 3, beam.beam_color, beam.beam_alpha, DRAWFLAG_NORMAL, transformed_view_org);
+       else
+       {
+               R_BeginPolygon(beam.beam_image, DRAWFLAG_NORMAL); // DRAWFLAG_ADDITIVE
+               R_PolygonVertex(
+                       top,
+                       '0 0.5 0' + ('0 0.5 0' * (thickness / beam.beam_thickness)),
+                       beam.beam_color,
+                       beam.beam_alpha
+               );
+               R_PolygonVertex(
+                       last_top,
+                       '0 0.5 0' + ('0 0.5 0' * (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
+                       beam.beam_color,
+                       beam.beam_alpha
+               );
+               R_PolygonVertex(
+                       last_bottom,
+                       '0 0.5 0' * (1 - (Draw_ArcBeam_callback_last_thickness / beam.beam_thickness)),
+                       beam.beam_color,
+                       beam.beam_alpha
+               );
+               R_PolygonVertex(
+                       bottom,
+                       '0 0.5 0' * (1 - (thickness / beam.beam_thickness)),
+                       beam.beam_color,
+                       beam.beam_alpha
+               );
+               R_EndPolygon();
+       }
 
        // draw trailing particles
        // NOTES:
@@ -884,17 +892,30 @@ void Draw_ArcBeam(entity this)
                // into a weapon system for client code.
 
                // find where we are aiming
-               makevectors(warpzone_save_view_angles);
+               makevectors(((autocvar_chase_active) ? warpzone_save_view_angles : view_angles));
                vector forward = v_forward;
                vector right = v_right;
                vector up = v_up;
+               entity wepent = viewmodels[this.beam_slot];
+
+               if(autocvar_chase_active)
+                       this.beam_usevieworigin = 1;
+               else
+                       this.beam_usevieworigin = 2;
 
                // decide upon start position
                if(this.beam_usevieworigin == 2)
                        { start_pos = warpzone_save_view_origin; }
+               else if(csqcplayer)
+                       { start_pos = csqcplayer.origin + csqcplayer.view_ofs; }
                else
                        { start_pos = this.origin; }
 
+               int v_shot_idx;  // used later
+               (v_shot_idx = gettagindex(wepent, "shot")) || (v_shot_idx = gettagindex(wepent, "tag_shot"));
+               if(v_shot_idx && this.beam_usevieworigin == 2)
+                       start_pos = gettaginfo(wepent, v_shot_idx) - '0 0 2';
+
                // trace forward with an estimation
                WarpZone_TraceLine(
                        start_pos,
@@ -911,9 +932,16 @@ void Draw_ArcBeam(entity this)
                        end_pos = start_pos + (forward * g_trueaim_minrange);
 
                // move shot origin to the actual gun muzzle origin
-               vector origin_offset =
-                         right * -this.beam_shotorigin.y
-                       + up * this.beam_shotorigin.z;
+               vector origin_offset = '0 0 0';
+               if(!v_shot_idx || this.beam_usevieworigin != 2)
+               {
+                       this.beam_shotorigin = wepent.movedir;
+                       origin_offset =
+                                right * -this.beam_shotorigin.y
+                               + up * this.beam_shotorigin.z;
+               }
+               else
+                       this.beam_shotorigin = '0 0 0';
 
                start_pos = start_pos + origin_offset;
 
@@ -1119,7 +1147,7 @@ void Draw_ArcBeam(entity this)
                        )
                );
        }
-       if(this.beam_muzzleeffect)
+       if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
        {
                pointparticles(
                        this.beam_muzzleeffect,
@@ -1160,11 +1188,13 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
        int slot = ReadByte();
        entity flash;
 
+       this.beam_slot = slot;
+
        if(isnew)
        {
                int gunalign = W_GunAlign(viewmodels[slot], STAT(GUNALIGN)) - 1;
 
-               this.beam_shotorigin = arc_shotorigin[gunalign];
+               this.beam_shotorigin = arc_shotorigin[gunalign]; // get a starting point
 
                // set other main attributes of the beam
                this.draw = Draw_ArcBeam;
@@ -1271,18 +1301,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1297,18 +1327,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; // (EFFECT_GRENADE_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null; // (EFFECT_GRENADE_MUZZLEFLASH);
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1323,18 +1353,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1349,18 +1379,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 0;
                                this.beam_hitlight[3] = 0;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 50;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 0;
                                this.beam_muzzlelight[3] = 0;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1375,18 +1405,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1401,18 +1431,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1427,18 +1457,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1453,18 +1483,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
@@ -1481,18 +1511,18 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
                                this.beam_hitlight[1] = 1;
                                this.beam_hitlight[2] = 1;
                                this.beam_hitlight[3] = 1;
-                               this.beam_muzzleeffect = NULL; //(EFFECT_VORTEX_MUZZLEFLASH);
+                               this.beam_muzzleeffect = EFFECT_Null;
                                this.beam_muzzlelight[0] = 0;
                                this.beam_muzzlelight[1] = 1;
                                this.beam_muzzlelight[2] = 1;
                                this.beam_muzzlelight[3] = 1;
                                this.beam_image = "particles/lgbeam";
-                               if(this.beam_muzzleeffect)
+                               if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
                                {
                                        setmodel(flash, MDL_ARC_MUZZLEFLASH);
                                        flash.alpha = this.beam_alpha;
                                        flash.colormod = this.beam_color;
-                                       flash.scale = 0.5;
+                                       flash.scale = 0.35;
                                }
                                break;
                        }
index 2710768668bdf525eab03fede68542cb530b061f..5a41666bdb74ba1a58b4a09eae9adf341e2a7d8a 100644 (file)
@@ -247,7 +247,7 @@ void W_Crylink_Touch(entity this, entity toucher)
        if(a)
                f *= a;
 
-       float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius), 
+       float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius),
                                                                                NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, this.weaponentity_fld, toucher);
 
        if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(crylink, isprimary, radius)))))
index e48bf5fb3481e8db22c4698662997a648adc3db0..77e0b734e2e7e2c1009ee42fb400691a9bca8ed1 100644 (file)
@@ -71,4 +71,6 @@ SPAWNFUNC_WEAPON(weapon_crylink, WEP_CRYLINK)
 
 .entity queuenext;
 .entity queueprev;
+
+void W_Crylink_Dequeue(entity e);
 #endif
index 0a046389c7fa3d3cc57aa2106324124dce0e3271..c53e110fddb07a699988578d09067db6e73a462c 100644 (file)
@@ -235,11 +235,19 @@ void W_Devastator_Think(entity this)
                        else
                                f = 1;
 
+                       vector md = this.realowner.(weaponentity).movedir;
+                       vector vecs = ((md.x > 0) ? md : '0 0 0');
+
+                       vector dv = v_right * -vecs.y + v_up * vecs.z;
+
+                       if(!W_DualWielding(this.realowner))
+                               dv = '0 0 0'; // don't override!
+
                        velspeed = vlen(this.velocity);
 
                        makevectors(this.realowner.v_angle);
                        desireddir = WarpZone_RefSys_TransformVelocity(this.realowner, this, v_forward);
-                       desiredorigin = WarpZone_RefSys_TransformOrigin(this.realowner, this, this.realowner.origin + this.realowner.view_ofs);
+                       desiredorigin = WarpZone_RefSys_TransformOrigin(this.realowner, this, this.realowner.origin + this.realowner.view_ofs + dv);
                        olddir = normalize(this.velocity);
 
                        // now it gets tricky... we want to move like some curve to approximate the target direction
index 0e8d8b2fbc8b271102ac17363b1435a957db1047..e858d54e42d155f87653fb38c1bb85c304d8e152 100644 (file)
@@ -4,7 +4,7 @@ CLASS(Devastator, Weapon)
 /* spawnfunc */ ATTRIB(Devastator, m_canonical_spawnfunc, string, "weapon_devastator");
 /* ammotype  */ ATTRIB(Devastator, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Devastator, impulse, int, 9);
-/* flags     */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
+/* flags     */ ATTRIB(Devastator, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Devastator, bot_pickupbasevalue, float, 8000);
 /* color     */ ATTRIB(Devastator, wpcolor, vector, '1 1 0');
 /* modelname */ ATTRIB(Devastator, mdl, string, "rl");
index ef2eb91cad89e031398ab71de55ecdd3bf1010c3..ee4b2e0847f27b032837872c4070e3026254113f 100644 (file)
@@ -155,7 +155,6 @@ void W_Fireball_Attack1(entity actor, .entity weaponentity)
        PROJECTILE_MAKETRIGGER(proj);
        proj.projectiledeathtype = WEP_FIREBALL.m_id;
        proj.weaponentity_fld = weaponentity;
-       proj.weaponentity_fld = weaponentity;
        setorigin(proj, w_shotorg);
 
        set_movetype(proj, MOVETYPE_FLY);
index 49ad1c7394cc7e99d7b70cfc6b47e2b8c3477382..8f501653869caad8908a2723ad435dbfd70ff243 100644 (file)
@@ -12,7 +12,7 @@ void W_HLAC_Touch(entity this, entity toucher)
 
        isprimary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
 
-       RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius), 
+       RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius),
                                                NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, this.weaponentity_fld, toucher);
 
        delete(this);
index 8d569d04e253f798debe0b17747233432166bf92..985d2ae59ef3faabdd7fce020d09d0310ddfb3a0 100644 (file)
@@ -261,11 +261,11 @@ float autocvar_cl_grapplehook_alpha = 1;
 void Draw_CylindricLine(vector from, vector to, float thickness, string texture, float aspect, float shift, vector rgb, float theAlpha, float drawflag, vector vieworg);
 
 entityclass(Hook);
-class(Hook) .entity HookType; // ENT_CLIENT_*
-class(Hook) .vector origin;
-class(Hook) .vector velocity;
-class(Hook) .float HookSilent;
-class(Hook) .float HookRange;
+classfield(Hook) .entity HookType; // ENT_CLIENT_*
+classfield(Hook) .vector origin;
+classfield(Hook) .vector velocity;
+classfield(Hook) .float HookSilent;
+classfield(Hook) .float HookRange;
 
 string Draw_GrapplingHook_trace_callback_tex;
 float Draw_GrapplingHook_trace_callback_rnd;
@@ -281,7 +281,7 @@ void Draw_GrapplingHook_trace_callback(vector start, vector hit, vector end)
        Draw_GrapplingHook_trace_callback_rnd += 0.25 * vlen(hit - start) / 8;
 }
 
-class(Hook) .float teleport_time;
+classfield(Hook) .float teleport_time;
 void Draw_GrapplingHook(entity this)
 {
        vector a, b, atrans;
index 25bad729fded903ae27d5b5ee86bd2faaaa997e5..d8075c9fe4d167cf127b4411252bb7cdd75f58db 100644 (file)
@@ -96,7 +96,7 @@ void W_MineLayer_DoRemoteExplode(entity this)
        if(this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FOLLOW)
                this.velocity = this.mine_orientation; // particle fx and decals need .velocity
 
-       RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius), 
+       RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius),
                                                NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, this.weaponentity_fld, NULL);
 
        .entity weaponentity = this.weaponentity_fld;
index 2161d468bf6df5f18c497aee3c2ef484d7c01665..affec0dbcae952696866a9c6e08c84d15b7ba454 100644 (file)
@@ -4,7 +4,7 @@ CLASS(Mortar, Weapon)
 /* spawnfunc */ ATTRIB(Mortar, m_canonical_spawnfunc, string, "weapon_mortar");
 /* ammotype  */ ATTRIB(Mortar, ammo_type, int, RESOURCE_ROCKETS);
 /* impulse   */ ATTRIB(Mortar, impulse, int, 4);
-/* flags     */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
+/* flags     */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
 /* rating    */ ATTRIB(Mortar, bot_pickupbasevalue, float, 7000);
 /* color     */ ATTRIB(Mortar, wpcolor, vector, '1 0 0');
 /* modelname */ ATTRIB(Mortar, mdl, string, "gl");
index f778e164bd9e60a00c0fea8547d820a69bda9ca7..243f5bc34af0497394cfd9cf1c83ffe9739f991e 100644 (file)
@@ -1,7 +1,8 @@
 #include "porto.qh"
 
 #ifdef SVQC
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
+#include <server/weapons/throwing.qh>
 
 REGISTER_MUTATOR(porto_ticker, true);
 MUTATOR_HOOKFUNCTION(porto_ticker, SV_StartFrame) {
@@ -20,7 +21,6 @@ void W_Porto_Success(entity this)
        delete(this);
 }
 
-string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector velo, .entity weaponentity);
 void W_Porto_Fail(entity this, float failhard)
 {
        if(this.realowner == NULL)
@@ -37,7 +37,7 @@ void W_Porto_Fail(entity this, float failhard)
 
        this.realowner.porto_current = NULL;
 
-       if(this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid && !IS_DEAD(this.realowner) && !(this.realowner.weapons & WEPSET(PORTO)))
+       if(this.cnt < 0 && !failhard && this.realowner.playerid == this.playerid && !IS_DEAD(this.realowner) && !(STAT(WEAPONS, this.realowner) & WEPSET(PORTO)))
        {
                setsize(this, '-16 -16 0', '16 16 32');
                setorigin(this, this.origin + trace_plane_normal);
index 93b3a6e9f7da4d73251da4dd731ab1810390227c..a77093944b6e0fbab37bb5ca42aafc5eacc39174 100644 (file)
@@ -44,4 +44,6 @@ SPAWNFUNC_WEAPON(weapon_porto, WEP_PORTO)
 .float porto_v_angle_held;
 .vector right_vector;
 .float porto_forbidden;
+
+void W_Porto_Fail(entity this, float failhard);
 #endif
index 1740c45d84c3fc5fe405dc03345c8e4bfd1147ad..d6996042dc56967ebf02c29a946329ea40ce4323 100644 (file)
@@ -159,7 +159,11 @@ METHOD(Rifle, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponen
 }
 METHOD(Rifle, wr_resetplayer, void(entity thiswep, entity actor))
 {
-    actor.rifle_accumulator = time - WEP_CVAR(rifle, bursttime);
+    for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+    {
+        .entity weaponentity = weaponentities[slot];
+        actor.(weaponentity).rifle_accumulator = time - WEP_CVAR(rifle, bursttime);
+    }
 }
 METHOD(Rifle, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
 {
index 87bc4d7ec1d856424cde3776886176591166ef57..560354c0529b40b5e19e9a4ff389a01946dae6c6 100644 (file)
@@ -4,7 +4,7 @@ CLASS(Rifle, Weapon)
 /* spawnfunc */ ATTRIB(Rifle, m_canonical_spawnfunc, string, "weapon_rifle");
 /* ammotype  */ ATTRIB(Rifle, ammo_type, int, RESOURCE_BULLETS);
 /* impulse   */ ATTRIB(Rifle, impulse, int, 7);
-/* flags     */ ATTRIB(Rifle, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS | WEP_FLAG_NODUAL);
+/* flags     */ ATTRIB(Rifle, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_PENETRATEWALLS);
 /* rating    */ ATTRIB(Rifle, bot_pickupbasevalue, float, 7000);
 /* color     */ ATTRIB(Rifle, wpcolor, vector, '0.5 1 0');
 /* modelname */ ATTRIB(Rifle, mdl, string, "campingrifle");
index 7cabd77103b4a3032c73b409ad3768176243b2ed..057ef3f03a756b6c3d337a7257fada47c88ebd51 100644 (file)
@@ -2,15 +2,16 @@
 
 #ifdef SVQC
 
-void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary)
+void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary, float ammocount, float damage, float bullets, float spread, float solidpenetration, float force)
 {
-       W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo), weaponentity);
+       W_DecreaseAmmo(thiswep, actor, ammocount, weaponentity);
 
-       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets), WEP_SHOTGUN.m_id);
-       for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
-               fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
+       W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), damage * bullets, WEP_SHOTGUN.m_id);
+       for(int sc = 0;sc < bullets;sc = sc + 1)
+               fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, WEP_SHOTGUN.m_id, 0);
 
-       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
+
+       Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, ammocount);
 
        // casing code
        if(autocvar_g_casings >= 1)
@@ -152,7 +153,13 @@ void W_Shotgun_Attack3_Frame2(Weapon thiswep, entity actor, .entity weaponentity
        }
 
        sound(actor, CH_WEAPON_SINGLE, SND_Null, VOL_BASE, ATTN_NORM); // kill previous sound
-       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, true); // actually is secondary, but we trick the last shot into playing full reload sound
+       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, true,
+               WEP_CVAR_PRI(shotgun, ammo),
+               WEP_CVAR_PRI(shotgun, damage),
+               WEP_CVAR_PRI(shotgun, bullets),
+               WEP_CVAR_PRI(shotgun, spread),
+               WEP_CVAR_PRI(shotgun, solidpenetration),
+               WEP_CVAR_PRI(shotgun, force)); // actually is secondary, but we trick the last shot into playing full reload sound
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), w_ready);
 }
 void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity, int fire)
@@ -165,7 +172,13 @@ void W_Shotgun_Attack3_Frame1(Weapon thiswep, entity actor, .entity weaponentity
                return;
        }
 
-       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, false);
+       W_Shotgun_Attack(WEP_SHOTGUN, actor, weaponentity, false,
+               WEP_CVAR_PRI(shotgun, ammo),
+               WEP_CVAR_PRI(shotgun, damage),
+               WEP_CVAR_PRI(shotgun, bullets),
+               WEP_CVAR_PRI(shotgun, spread),
+               WEP_CVAR_PRI(shotgun, solidpenetration),
+               WEP_CVAR_PRI(shotgun, force));
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame2);
 }
 
@@ -178,6 +191,7 @@ METHOD(Shotgun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity)
     else
         PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
 }
+
 METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
     if(WEP_CVAR(shotgun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(shotgun, ammo)) // forced reload
@@ -195,7 +209,13 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit
             {
                 if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(shotgun, animtime)))
                 {
-                    W_Shotgun_Attack(thiswep, actor, weaponentity, true);
+                    W_Shotgun_Attack(thiswep, actor, weaponentity, true,
+                                               WEP_CVAR_PRI(shotgun, ammo),
+                                               WEP_CVAR_PRI(shotgun, damage),
+                                               WEP_CVAR_PRI(shotgun, bullets),
+                                               WEP_CVAR_PRI(shotgun, spread),
+                                               WEP_CVAR_PRI(shotgun, solidpenetration),
+                                               WEP_CVAR_PRI(shotgun, force));
                     actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_PRI(shotgun, refire) * W_WeaponRateFactor(actor);
                     weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(shotgun, animtime), w_ready);
                 }
@@ -207,7 +227,13 @@ METHOD(Shotgun, wr_think, void(entity thiswep, entity actor, .entity weaponentit
             {
                 if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(shotgun, alt_animtime)))
                 {
-                    W_Shotgun_Attack(thiswep, actor, weaponentity, false);
+                    W_Shotgun_Attack(thiswep, actor, weaponentity, false,
+                                               WEP_CVAR_PRI(shotgun, ammo),
+                                               WEP_CVAR_PRI(shotgun, damage),
+                                               WEP_CVAR_PRI(shotgun, bullets),
+                                               WEP_CVAR_PRI(shotgun, spread),
+                                               WEP_CVAR_PRI(shotgun, solidpenetration),
+                                               WEP_CVAR_PRI(shotgun, force));
                     actor.(weaponentity).shotgun_primarytime = time + WEP_CVAR_SEC(shotgun, alt_refire) * W_WeaponRateFactor(actor);
                     weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_SEC(shotgun, alt_animtime), W_Shotgun_Attack3_Frame1);
                 }
index ffa1dd6e2dd5589e5623611655bce63a87bf4042..d932d98bd16f6d7554c32fb7f447ca9419be3c15 100644 (file)
@@ -45,9 +45,9 @@ SPAWNFUNC_WEAPON(weapon_tuba, WEP_TUBA)
 
 #ifdef CSQC
 entityclass(Tuba);
-class(Tuba) .int note;
-class(Tuba) .bool tuba_attenuate;
-class(Tuba) .float tuba_volume;
-class(Tuba) .float tuba_volume_initial;
-class(Tuba) .int tuba_instrument;
+classfield(Tuba) .int note;
+classfield(Tuba) .bool tuba_attenuate;
+classfield(Tuba) .float tuba_volume;
+classfield(Tuba) .float tuba_volume_initial;
+classfield(Tuba) .int tuba_instrument;
 #endif
index 06562f68a8c5c5e071096d8490347449458ba47b..c3baa12127b6c3b39a947aa8fec40524362a1443 100644 (file)
@@ -125,7 +125,7 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        yoda = 0;
        damage_goodhits = 0;
-       FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, vaporizer_damage, 800, 0, 0, 0, 0, WEP_VAPORIZER.m_id);
+       FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, vaporizer_damage, WEP_CVAR_PRI(vaporizer, force), 0, 0, 0, 0, WEP_VAPORIZER.m_id);
 
        // do this now, as goodhits is disabled below
        SendCSQCVaporizerBeamParticle(actor, damage_goodhits);
@@ -144,7 +144,7 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        if(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
                W_RocketMinsta_Explosion(actor, weaponentity, trace_endpos);
 
-       W_DecreaseAmmo(thiswep, actor, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)), weaponentity);
+       W_DecreaseAmmo(thiswep, actor, ((autocvar_g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)), weaponentity);
 }
 
 void W_RocketMinsta_Laser_Explode (entity this, entity directhitentity)
@@ -288,7 +288,7 @@ METHOD(Vaporizer, wr_aim, void(entity thiswep, entity actor, .entity weaponentit
 }
 METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
-    float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
+    float vaporizer_ammo = ((autocvar_g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
     // if the laser uses load, we also consider its ammo for reloading
     if(WEP_CVAR(vaporizer, reload_ammo) && WEP_CVAR_SEC(vaporizer, ammo) && actor.(weaponentity).clip_load < min(vaporizer_ammo, WEP_CVAR_SEC(vaporizer, ammo))) { // forced reload
         thiswep.wr_reload(thiswep, actor, weaponentity);
@@ -349,7 +349,7 @@ METHOD(Vaporizer, wr_setup, void(entity thiswep, entity actor, .entity weaponent
 }
 METHOD(Vaporizer, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
 {
-    float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
+    float vaporizer_ammo = ((autocvar_g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
     float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= vaporizer_ammo;
     ammo_amount += actor.(weaponentity).(weapon_load[WEP_VAPORIZER.m_id]) >= vaporizer_ammo;
     return ammo_amount;
@@ -368,7 +368,7 @@ METHOD(Vaporizer, wr_resetplayer, void(entity thiswep, entity actor))
 }
 METHOD(Vaporizer, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
 {
-    float vaporizer_ammo = ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
+    float vaporizer_ammo = ((autocvar_g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo));
     float used_ammo;
     if(WEP_CVAR_SEC(vaporizer, ammo))
         used_ammo = min(vaporizer_ammo, WEP_CVAR_SEC(vaporizer, ammo));
index ea9f8dd2ba60db6a8452b088e424e5ed0d976046..9bbc5e9bdded6c4098a31020e9da6139b1795b07 100644 (file)
@@ -22,7 +22,8 @@ CLASS(Vaporizer, Weapon)
        BEGIN(class) \
                P(class, prefix, ammo, float, PRI) \
        P(class, prefix, animtime, float, PRI) \
-       P(class, prefix, damage, float, PRI) \
+        P(class, prefix, damage, float, PRI) \
+       P(class, prefix, force, float, PRI) \
        P(class, prefix, refire, float, PRI) \
        P(class, prefix, ammo, float, SEC) \
        P(class, prefix, animtime, float, SEC) \
index 8c590bf6e2c6841f56c2a5b978123f5fad64d3f4..b8963229710e23266cba03cb023c2a443773d6b1 100644 (file)
@@ -105,6 +105,10 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i
        myforcehalflife = WEP_CVAR_BOTH(vortex, !issecondary, damagefalloff_forcehalflife);
        myammo = WEP_CVAR_BOTH(vortex, !issecondary, ammo);
 
+    float dtype = WEP_VORTEX.m_id;
+    if(WEP_CVAR_BOTH(vortex, !issecondary, armorpierce))
+        dtype |= HITTYPE_ARMORPIERCE;
+
        float flying;
        flying = IsFlying(actor); // do this BEFORE to make the trace values from FireRailgunBullet last
 
@@ -120,7 +124,7 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i
        mydmg *= charge;
        myforce *= charge;
 
-       W_SetupShot(actor, weaponentity, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg, WEP_VORTEX.m_id);
+       W_SetupShot(actor, weaponentity, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg, dtype);
        if(charge > WEP_CVAR(vortex, charge_animlimit) && WEP_CVAR(vortex, charge_animlimit)) // if the Vortex is overcharged, we play an extra sound
        {
                sound(actor, CH_WEAPON_B, SND_NEXCHARGE, VOL_BASE * (charge - 0.5 * WEP_CVAR(vortex, charge_animlimit)) / (1 - 0.5 * WEP_CVAR(vortex, charge_animlimit)), ATTN_NORM);
@@ -128,7 +132,7 @@ void W_Vortex_Attack(Weapon thiswep, entity actor, .entity weaponentity, float i
 
        yoda = 0;
        damage_goodhits = 0;
-       FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, WEP_VORTEX.m_id);
+       FireRailgunBullet(actor, weaponentity, w_shotorg, w_shotorg + w_shotdir * max_shot_distance, mydmg, myforce, mymindist, mymaxdist, myhalflife, myforcehalflife, dtype);
 
        if(yoda && flying)
                Send_Notification(NOTIF_ONE, actor, MSG_ANNCE, ANNCE_ACHIEVEMENT_YODA);
index 59152e2759f93b144585d9b8fcc6f394e6751627..8a11b2e13e4c3a00a751400047f4ded606a94789 100644 (file)
@@ -4,7 +4,7 @@ CLASS(Vortex, Weapon)
 /* spawnfunc */ ATTRIB(Vortex, m_canonical_spawnfunc, string, "weapon_vortex");
 /* ammotype  */ ATTRIB(Vortex, ammo_type, int, RESOURCE_CELLS);
 /* impulse   */ ATTRIB(Vortex, impulse, int, 7);
-/* flags     */ ATTRIB(Vortex, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_NODUAL);
+/* flags     */ ATTRIB(Vortex, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN);
 /* rating    */ ATTRIB(Vortex, bot_pickupbasevalue, float, 8000);
 /* color     */ ATTRIB(Vortex, wpcolor, vector, '0.5 1 1');
 /* modelname */ ATTRIB(Vortex, mdl, string, "nex");
@@ -22,6 +22,7 @@ CLASS(Vortex, Weapon)
        BEGIN(class) \
                P(class, prefix, ammo, float, BOTH) \
                P(class, prefix, animtime, float, BOTH) \
+               P(class, prefix, armorpierce, float, BOTH) \
                P(class, prefix, chargepool, float, SEC) \
                P(class, prefix, chargepool_pause_regen, float, SEC) \
                P(class, prefix, chargepool_regen, float, SEC) \
index 1b9abdbf0ecb4f1ae694cff46164dc417a5df38d..9488c4c2c6bc0927a3ba8b30eebeb96baf9a2ccc 100644 (file)
@@ -26,6 +26,10 @@ MACRO_END
        { WriteByte(chan, this.vortex_charge * 255); }, \
        { (viewmodels[this.m_wepent_slot]).vortex_charge = ReadByte() / 255; }) \
     \
+    PROP(false, oknex_charge, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.oknex_charge * 16); }, \
+       { (viewmodels[this.m_wepent_slot]).oknex_charge = ReadByte() / 16; }) \
+    \
     PROP(false, m_gunalign, WEPENT_SET_NORMAL, \
        { WriteByte(chan, this.m_gunalign); }, \
        { (viewmodels[this.m_wepent_slot]).m_gunalign = ReadByte(); }) \
@@ -58,7 +62,11 @@ MACRO_END
        { WriteByte(chan, this.vortex_chargepool_ammo * 16); }, \
        { (viewmodels[this.m_wepent_slot]).vortex_chargepool_ammo = ReadByte() / 16; }) \
     \
-    PROP(false, clip_load, WEPENT_SET_NORMAL, \
+       PROP(false, oknex_chargepool_ammo, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.oknex_chargepool_ammo * 16); }, \
+       { (viewmodels[this.m_wepent_slot]).oknex_chargepool_ammo = ReadByte() / 16; }) \
+    \
+       PROP(false, clip_load, WEPENT_SET_NORMAL, \
        { WriteShort(chan, this.clip_load); }, \
        { (viewmodels[this.m_wepent_slot]).clip_load = ReadShort(); }) \
     \
index dbd38fc10f8916510d0ef3c37c624c0c4ef533c4..d6db7745b9fe1cc5e1ebc8f0f0edcfca78382214 100644 (file)
@@ -5,6 +5,8 @@ REGISTER_NET_TEMP(CLIENT_WEPENT)
 
 .float vortex_charge;
 .float vortex_chargepool_ammo;
+.float oknex_charge;
+.float oknex_chargepool_ammo;
 .int tuba_instrument;
 .int minelayer_mines;
 .float arc_heat_percent;
index c8b459962eb0102247c4f308459d680e2965cf76..8896b5a442ba42d78c4420ee3c0332dacb2956c6 100644 (file)
@@ -43,7 +43,7 @@ void sys_phys_update(entity this, float dt)
        float maxspeed_mod = (!this.in_swamp) ? 1 : this.swamp_slowdown;  // cvar("g_balance_swamp_moverate");
 
 // conveyors: first fix velocity
-       if (this.conveyor.state) { this.velocity -= this.conveyor.movedir; }
+       if (this.conveyor.active) { this.velocity -= this.conveyor.movedir; }
        MUTATOR_CALLHOOK(PlayerPhysics, this, dt);
 
        if (!IS_PLAYER(this)) {
@@ -156,7 +156,7 @@ void sys_phys_update(entity this, float dt)
        LABEL(end)
        if (IS_ONGROUND(this)) { this.lastground = time; }
 // conveyors: then break velocity again
-       if (this.conveyor.state) { this.velocity += this.conveyor.movedir; }
+       if (this.conveyor.active) { this.velocity += this.conveyor.movedir; }
        this.lastflags = this.flags;
 
        this.lastclassname = this.classname;
index 5ae47c394da75d90665680af45cb8fccbfa9f71a..c3594c0136cfff9cfca75c0573cbfd1349ed2d8e 100644 (file)
@@ -4,6 +4,7 @@ void sys_phys_fix(entity this, float dt)
 {
        WarpZone_PlayerPhysics_FixVAngle(this);
        Physics_UpdateStats(this);
+       PM_ClientMovement_UpdateStatus(this);
 }
 
 bool sys_phys_override(entity this, float dt)
index d44c5e89cdda2acacbd1b615bfbc55dc8bb93b9f..0bed40bbf081fcd3c784719cc463c0db1be14dcb 100644 (file)
        #define bool float
 #endif
 
+#ifndef QCC_SUPPORT_ACCUMULATE
+       #warning "QCC does not support accumulate, may not compile correctly"
+       #define ACCUMULATE
+#else
+       #define ACCUMULATE [[accumulate]]
+#endif
+
 #ifndef QCC_SUPPORT_ERASEABLE
        #define ERASEABLE
 #else
        #define ERASEABLE [[eraseable]]
 #endif
 
+#ifndef QCC_SUPPORT_ALIAS
+    #warning "QCC does not support alias, may not compile correctly"
+    #define ALIAS(var)
+#else
+    #define ALIAS(var) [[alias(var)]]
+#endif
+
 #include <dpdefs/pre.qh>
 
 #if defined(CSQC)
 
 #include <dpdefs/post.qh>
 
+#ifndef QCC_SUPPORT_POW
+    #define pow(a, b) pow(a, b)
+#else
+    #define pow(a, b) ((a) ** (b))
+#endif
+
 #include "self.qh"
 
 #define USING(name, T) typedef T name
 #include "oo.qh"
 #include "p2mathlib.qc"
 #include "progname.qh"
+#include "promise.qc"
 #include "random.qc"
 #include "registry.qh"
 #include "registry_net.qh"
index 115a6a070fe7b076bc651d80ef5933b0f6eaed27..8df43c95f4fbec1957848010211ff54561923750 100644 (file)
@@ -2,6 +2,7 @@
 #include <lib/angle.qc>
 #include <lib/json.qc>
 #include <lib/p2mathlib.qc>
+#include <lib/promise.qc>
 #include <lib/random.qc>
 #include <lib/sortlist.qc>
 #include <lib/test.qc>
index fd97f51b65dc09130abfa19daeb6b2266a20c9f6..8645347d6914cf07c915ff7c088737e2dcf6f8c3 100644 (file)
@@ -2,6 +2,7 @@
 #include <lib/angle.qh>
 #include <lib/json.qh>
 #include <lib/p2mathlib.qh>
+#include <lib/promise.qh>
 #include <lib/random.qh>
 #include <lib/sortlist.qh>
 #include <lib/test.qh>
index c265325f8f6c75d20de492fcf1c81211195e5849..2d1e40212fba3c9cd2d9f28216a5a3c2071c3d7e 100644 (file)
@@ -2,7 +2,7 @@
 
 #ifdef QCC_SUPPORT_ACCUMULATE
        #define ACCUMULATE_FUNCTION(func, otherfunc) \
-               [[accumulate]] void func() \
+               ACCUMULATE void func() \
                { \
                        otherfunc(); \
                }
index 5f9297f2dab1f5be24887ff2fead30390ee59fd6..6f7a7326de41f5cce1953dc26a5ac27aa933296d 100644 (file)
@@ -25,13 +25,13 @@ vector colormapPaletteColor_(int c, bool isPants, float t)
                case 14: return '1.000000 0.666667 0.000000';
                case 15:
                        if (isPants)
-                               return '1 0 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 0.0000000000))
-                                      + '0 1 0' * (0.502 + 0.498 * sin(t / 2.7182818285 + 2.0943951024))
-                                      + '0 0 1' * (0.502 + 0.498 * sin(t / 2.7182818285 + 4.1887902048));
+                               return '1 0 0' * (0.502 + 0.498 * sin(t / M_E + 0))
+                                       + '0 1 0' * (0.502 + 0.498 * sin(t / M_E + M_PI * 2 / 3))
+                                       + '0 0 1' * (0.502 + 0.498 * sin(t / M_E + M_PI * 4 / 3));
                        else
-                               return '1 0 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 5.2359877560))
-                                      + '0 1 0' * (0.502 + 0.498 * sin(t / 3.1415926536 + 3.1415926536))
-                                      + '0 0 1' * (0.502 + 0.498 * sin(t / 3.1415926536 + 1.0471975512));
+                               return '1 0 0' * (0.502 + 0.498 * sin(t / M_PI + M_PI * 5 / 3))
+                                       + '0 1 0' * (0.502 + 0.498 * sin(t / M_PI + M_PI))
+                                       + '0 0 1' * (0.502 + 0.498 * sin(t / M_PI + M_PI * 1 / 3));
                default: return '0.000 0.000 0.000';
        }
 }
index d1bdc4fe5b55e609bc4d02b32dc0f55b0761f21a..5ca0ed56525ee33886c46a0a7c27ecfd7763068b 100644 (file)
        #endif
 #endif
 
+#ifndef QCC_SUPPORT_ALIAS
+       #ifdef GMQCC
+               #define QCC_SUPPORT_ALIAS
+       #endif
+#endif
+
+#ifndef QCC_SUPPORT_POW
+    #ifdef GMQCC
+        #define QCC_SUPPORT_POW
+    #endif
+#endif
+
 #ifdef GMQCC
     #define LABEL(id) :id
 #else
index a17f2bad72397d55a470fc32bb64851cfcbe5152..e8e2c54880a1a29eed6c48d50a6ac0cd44c016ff 100644 (file)
@@ -87,7 +87,7 @@ const noref vector default_vector = '0 0 0';
 //  e.g.: AUTOCVAR(mycvar, float, 2.5, "cvar description")
 
 #define __AUTOCVAR(file, archive, var, type, desc, default) \
-       [[accumulate]] void RegisterCvars(void(string, string, string, bool, string) f) \
+       ACCUMULATE void RegisterCvars(void(string, string, string, bool, string) f) \
        { \
                f( #var, repr_cvar_##type(default), desc, archive, file); \
        } \
index 4f34bb4853ade7f0149274ebdb3c325d4468147a..5d6473080a60d9b470856efb27fc1344056764c3 100644 (file)
@@ -6,8 +6,8 @@
        #include "self.qh"
 
        entityclass(Defer);
-       class(Defer).entity owner;
-       class(Defer).void(entity) defer_func;
+       classfield(Defer).entity owner;
+       classfield(Defer).void(entity) defer_func;
 
        /** Remove entity */
        void SUB_Remove(entity this)
index f20b1c66e5bf120be7748737dabe8b9e8dec9f88..d8f19906a3eb26b1d9003e74f4493450f4b018d8 100644 (file)
@@ -324,9 +324,9 @@ vector solve_quadratic(float a, float b, float c)
 }
 
 /// Maps values between the src and dest range: src_min to dest_min, src_max to dest_max, values between them
-/// to the curresponding values between and extrapolates for values outside the range.
+/// to the corresponding values between and extrapolates for values outside the range.
 ///
-/// src_min and src_max must not be the same or division by zero accurs.
+/// src_min and src_max must not be the same or division by zero occurs.
 ///
 /// dest_max can be smaller than dest_min if you want the resulting range to be inverted, all values can be negative.
 ERASEABLE
index 449aa373b31885d5aa3a5958d7855c94c4fd3d6c..1b58eb1b9fcf75d0ddd7196843a6cb5be402d695 100644 (file)
@@ -5,12 +5,10 @@
 GENERIC_COMMAND(mx, "Send a matrix command") {
     switch (argv(1)) {
         case "user":
-            if (matrix_user) strunzone(matrix_user);
-            matrix_user = strzone(substring(command, argv_start_index(2), -1));
+            strcpy(matrix_user, substring(command, argv_start_index(2), -1));
             break;
         case "token":
-            if (matrix_access_token) strunzone(matrix_access_token);
-            matrix_access_token = strzone(substring(command, argv_start_index(2), -1));
+            strcpy(matrix_access_token, substring(command, argv_start_index(2), -1));
             break;
         case "messages":
             MX_Messages(string_null);
index c399c2aa6cf86e2d9a9ba910667c8cd1c926ba43..57754d04e4334d05da4a3701217d7bf6e17d7cb4 100644 (file)
@@ -204,7 +204,8 @@ void MX_Say_(entity fh, entity pass, int status)
             fh.url_verb = "PUT";
             fh.url_content_type = "application/json";
             url_fputs(fh, sprintf("{\"msgtype\": \"m.text\", \"body\": \"%s\"}", pass.message));
-            strunzone(pass.message); delete(pass);
+            strfree(pass.message);
+            delete(pass);
             url_fclose(fh);
             break;
         }
index 6c29a4b88dd100f74ded51a0fe91ad82179c7d25..cbb1079244d2ef5a6806f94387a8826380dc9589 100644 (file)
 
        #include "p99.qh"
        #define OVERLOAD(F, ...) P99_IF_EMPTY(__VA_ARGS__)(P99_PASTE2(F, _00)())(P99_PASTE3(F, _, P00_NARG(__VA_ARGS__))(__VA_ARGS__))
-       /** for use within a macro */
+       /** for use within macros */
        #define OVERLOAD_(F, ...) P99_IF_EMPTY(__VA_ARGS__)(P99_PASTE2(F, _00)())(P99_PASTE3(F, _, P00_NARG(__VA_ARGS__))(__VA_ARGS__))
+       #define OVERLOAD__(F, ...) P99_IF_EMPTY(__VA_ARGS__)(P99_PASTE2(F, _00)())(P99_PASTE3(F, _, P00_NARG(__VA_ARGS__))(__VA_ARGS__))
 #else
        #define EVAL(...) __VA_ARGS__
 
-       #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
        #define OVERLOAD(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+       #define OVERLOAD_(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
+       #define OVERLOAD__(F, ...) F##_##__VA_COUNT__(__VA_ARGS__)
 #endif
 
 #if defined(CSQC)
index b1f5326a9bb5a441b5094de347cfe973086d5bd6..7b3f581b38f059cd4e4252905ae0dcf243983209 100644 (file)
@@ -50,7 +50,7 @@ STATIC_INIT(RegisterTempEntities_renumber) { FOREACH(TempEntities, true, it.m_id
 
 #ifdef CSQC
        #define REGISTER_NET_LINKED(id) \
-               [[accumulate]] NET_HANDLE(id, bool isnew) \
+               ACCUMULATE NET_HANDLE(id, bool isnew) \
                { \
                        this = __self; \
                        this.sourceLoc = __FILE__ ":" STR(__LINE__); \
@@ -107,7 +107,6 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); }
 #ifdef SVQC
        const int MSG_ENTITY = 5;
 
-       .int Version;  // deprecated, use SendFlags
        .int SendFlags;
 
        IntrusiveList g_uncustomizables;
@@ -202,8 +201,7 @@ STATIC_INIT(C2S_Protocol_renumber) { FOREACH(C2S_Protocol, true, it.m_id = i); }
        {
                if (g_buf == "") return;
                localcmd("\ncmd c2s \"", strreplace("$", "$$", g_buf), "\"\n");
-               strunzone(g_buf);
-               g_buf = string_null;
+               strfree(g_buf);
        }
 #endif
 
@@ -301,8 +299,12 @@ MACRO_END
                string s = string_null;
                yenc_single(b, s);
                string tmp = strcat(g_buf, s);
-               if (g_buf) strunzone(g_buf);
-               g_buf = strzone(tmp);
+               strcpy(g_buf, tmp);
+       }
+       void WriteShort(int to, int b)
+       {
+               WriteByte(to, (b >> 8) & 0xFF);
+               WriteByte(to, b & 0xFF);
        }
 #elif defined(SVQC)
        int ReadByte()
@@ -311,6 +313,10 @@ MACRO_END
                ydec_single(g_buf, ret);
                return ret;
        }
+       int ReadShort()
+       {
+               return (ReadByte() << 8) | (ReadByte());
+       }
        void WriteByte(int to, int b);
 #endif
 
index 782798c9fe5c492799d0892f4f1f5cc3f155731d..5ef9cf8b6b17708b6bed1bb664b593d049496e53 100644 (file)
@@ -2,11 +2,11 @@
 
 // noises "usually" start in the range -1..1
 entityclass(Noise);
-class(Noise).float noise_baccum;
-class(Noise).float noise_paccum;
-class(Noise).float noise_paccum2;
-class(Noise).float noise_paccum3;
-class(Noise).float noise_bstate;
+classfield(Noise).float noise_baccum;
+classfield(Noise).float noise_paccum;
+classfield(Noise).float noise_paccum2;
+classfield(Noise).float noise_paccum3;
+classfield(Noise).float noise_bstate;
 
 ERASEABLE
 float Noise_Brown(entity e, float dt)
index f57bf8e909c4e7d1a594a0e36f2415b715483fda..b22ff791501c9a990c93e5d9c7f3dabc2c35f661 100644 (file)
@@ -5,19 +5,16 @@
 #include "static.qh"
 
 .vector origin;
+
 .bool pure_data;
-/** @deprecated use new_pure or NEW(class) */
-#define make_pure(e) \
-       MACRO_BEGIN \
-       { \
-               (e).pure_data = true; \
-       } MACRO_END
-#define make_impure(e) \
-       MACRO_BEGIN \
-       { \
-               (e).pure_data = false; \
-       } MACRO_END
 #define is_pure(e) ((e).pure_data)
+/** @deprecated use new_pure or NEW(class) */
+#define make_pure(e) MACRO_BEGIN \
+       (e).pure_data = true; \
+MACRO_END
+#define make_impure(e) MACRO_BEGIN \
+       (e).pure_data = false; \
+MACRO_END
 
 .string classname;
 /** Location entity was spawned from in source */
@@ -58,11 +55,11 @@ entity __spawn(string _classname, string _sourceLoc, bool pure)
 #define entityclass_1(name) entityclass_2(name, Object)
 #ifndef QCC_SUPPORT_ENTITYCLASS
        #define entityclass_2(name, base) USING(name, entity)
-       #define class(name)
+       #define classfield(name)
        #define _new(class, pure) __spawn( #class, __FILE__ ":" STR(__LINE__), pure)
 #else
        #define entityclass_2(name, base) entityclass name : base {}
-       #define class(name) [[class(name)]]
+       #define classfield(name) [[class(name)]]
        #define _new(class, pure) ((class) __spawn( #class, __FILE__ ":" STR(__LINE__), pure))
 #endif
 /** entities you care about seeing (.origin works) */
@@ -71,12 +68,13 @@ entity __spawn(string _classname, string _sourceLoc, bool pure)
 #define new_pure(class) _new(class, true)
 #define spawn() __spawn("entity", __FILE__ ":" STR(__LINE__), false)
 
-[[accumulate]] void ONREMOVE(entity this) {}
+ACCUMULATE void ONREMOVE(entity this) {}
 
 #ifndef SVQC
        #define delete_fn builtin_remove
 #endif
 
+.void(entity this) dtor;
 #define delete(this) MACRO_BEGIN { \
     entity _this = (this); \
     void(entity) _dtor = _this.dtor; \
@@ -104,7 +102,7 @@ void clearentity(entity e)
 }
 
 // Classes have a `spawn##cname(entity)` constructor
-// The parameter is used across [[accumulate]] functions
+// The parameter is used across ACCUMULATE functions
 
 .bool transmute;
 
@@ -138,12 +136,149 @@ void clearentity(entity e)
     } \
     MACRO_END
 
-#define CONSTRUCTOR(cname, ...) \
-       cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__) \
-       { \
-               return = this; \
-       } \
-       [[accumulate]] cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
+#define CLASS(...) EVAL_CLASS(OVERLOAD__(CLASS, __VA_ARGS__))
+#define EVAL_CLASS(...) __VA_ARGS__
+
+#define ATTRIB(...) EVAL_ATTRIB(OVERLOAD_(ATTRIB, __VA_ARGS__))
+#define EVAL_ATTRIB(...) __VA_ARGS__
+
+#ifdef QCC_SUPPORT_CLASS
+
+#warning "QCC_SUPPORT_CLASS not implemented"
+
+#define CLASS_1(name)                               CLASS_2(name, entity)
+#define CLASS_2(name, base)                         class name : base {
+
+#define INIT(class)                                     void class::class()
+#define CONSTRUCTOR(class, ...)                         void class::class(__VA_ARGS__)
+#define DESTRUCTOR(class)                               class::~class()
+
+#define SUPER(class)                                    super
+
+#define ATTRIB_3(class, name, T)                        T name
+#define ATTRIB_4(class, name, T, val)                   ATTRIB_3(class, name, T) = val
+#define STATIC_ATTRIB(class, name, T, val)              static T name = val
+
+#define ATTRIB_STRZONE(class, name, T, val)             T name = val
+#define STATIC_ATTRIB_STRZONE(class, name, T, val)      static T name = val
+
+#define ATTRIBARRAY(class, name, T, val)                T name[val]
+
+#define METHOD(class, name, prototype)                  virtual void class::name()
+#define STATIC_METHOD(class, name, prototype)           static void class::name()
+
+#define ENDCLASS(class)                             };
+
+#else
+
+#define CLASS_1(cname) CLASS_2(cname, )
+#define CLASS_2(cname, base)                                                                       \
+       entityclass(cname, base);                                                                      \
+       classfield(cname).bool instanceOf##cname;                                                      \
+       DEBUG_STUFF(cname)                                                                             \
+       VTBL(cname, base)                                                                              \
+       _INIT_STATIC(cname)                                                                            \
+       {                                                                                              \
+               if (cname##_vtbl && !this.transmute)                                                       \
+               {                                                                                          \
+                       copyentity(cname##_vtbl, this);                                                        \
+                       return;                                                                                \
+               }                                                                                          \
+               spawn##base##_static(this);                                                                \
+               this.instanceOf##cname = true;                                                             \
+       }                                                                                              \
+       INIT(cname)                                                                                    \
+       {                                                                                              \
+               /* Only statically initialize the current class, it contains everything it inherits */     \
+               if (cname##_vtbl.vtblname == this.classname)                                               \
+               {                                                                                          \
+                       spawn##cname##_static(this);                                                           \
+                       this.transmute = false;                                                                \
+                       this.classname = #cname;                                                               \
+                       this.vtblname = string_null;                                                           \
+                       this.vtblbase = cname##_vtbl;                                                          \
+               }                                                                                          \
+               spawn##base##_1(this);                                                                     \
+       }
+
+#define INIT(cname)                                                                                \
+       ACCUMULATE cname spawn##cname##_1(cname this)
+
+#define CONSTRUCTOR(cname, ...)                                                                    \
+       cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)                                          \
+       {                                                                                              \
+               return = this;                                                                             \
+       }                                                                                              \
+       ACCUMULATE cname OVERLOAD(spawn##cname, cname this, __VA_ARGS__)
+
+#define DESTRUCTOR(cname)                                                                          \
+       STATIC_METHOD(cname, dtorimpl, void(cname this));                                              \
+    METHOD(cname, dtor, void(cname this))                                                          \
+    {                                                                                              \
+        METHOD_REFERENCE(cname, dtorimpl)(this);                                                   \
+        this.instanceOf##cname = false;                                                            \
+        entity super = SUPER(cname);                                                               \
+        if (super != cname##_vtbl) super.dtor(this);                                               \
+    }                                                                                              \
+       STATIC_METHOD(cname, dtorimpl, void(cname this))
+
+#define SUPER(cname) (cname##_vtbl.vtblbase)
+
+#define ATTRIB_3(cname, name, type) classfield(cname) .type name
+#define ATTRIB_4(cname, name, type, val)                                                           \
+       ATTRIB_3(cname, name, type);                                                                   \
+       INIT(cname)                                                                                    \
+       {                                                                                              \
+               noref bool strzone; /* Error on strzone() calls. */                                        \
+               this.name = val;                                                                           \
+       }                                                                                              \
+       ATTRIB_3(cname, name, type)
+
+#define STATIC_ATTRIB(cname, name, type, val)                                                      \
+       type cname##_##name;                                                                           \
+       _INIT_STATIC(cname)                                                                            \
+       {                                                                                              \
+               noref bool strzone; /* Error on strzone() calls. */                                        \
+               cname##_##name = val;                                                                      \
+       }
+
+// cleanup potentially zoned strings from base classes
+#define ATTRIB_STRZONE(cname, name, type, val)                                                     \
+       classfield(cname).type name;                                                                   \
+       INIT(cname)                                                                                    \
+       {                                                                                              \
+               strcpy(this.name, val);                                                                    \
+       }
+
+#define STATIC_ATTRIB_STRZONE(cname, name, type, val)                                              \
+       type cname##_##name;                                                                           \
+       _INIT_STATIC(cname)                                                                            \
+       {                                                                                              \
+               strcpy(cname##_##name, val);                                                               \
+       }
+
+#define ATTRIBARRAY(cname, name, type, cnt)                                                        \
+       classfield(cname) .type name[cnt]
+
+#define METHOD(cname, name, prototype)                                                             \
+       STATIC_METHOD(cname, name, prototype);                                                         \
+       classfield(cname) .prototype name;                                                             \
+       _INIT_STATIC(cname)                                                                            \
+       {                                                                                              \
+               this.name = METHOD_REFERENCE(cname, name);                                                 \
+       }                                                                                              \
+       STATIC_METHOD(cname, name, prototype)
+
+#define STATIC_METHOD(cname, name, prototype)                                                      \
+       prototype METHOD_REFERENCE(cname, name)
+
+#define ENDCLASS(cname)                                                                            \
+       INIT(cname)                                                                                    \
+       {                                                                                              \
+               return this;                                                                               \
+       }
+
+// impl
 
 .string vtblname;
 .entity vtblbase;
@@ -168,128 +303,25 @@ STATIC_INIT(RegisterClasses)
        } \
        ACCUMULATE_FUNCTION(RegisterClasses, cname##_vtbl_init)
 
-#define _INIT_STATIC(cname) [[accumulate]] void spawn##cname##_static(cname this)
-#define INIT(cname) [[accumulate]] cname spawn##cname##_1(cname this)
+#define _INIT_STATIC(cname) ACCUMULATE void spawn##cname##_static(cname this)
 
 #if NDEBUG
        #define DEBUG_STUFF(cname)
 #else
        #define DEBUG_STUFF(cname) \
-               bool is_##cname(entity e) { return e.instanceOf##cname; } \
-               void isnt_##cname(entity e) { eprint(e); }
+               ERASEABLE bool is_##cname(entity e) { return e.instanceOf##cname; } \
+               ERASEABLE void isnt_##cname(entity e) { eprint(e); }
 #endif
 
-
-#define CLASS(cname, base)                  \
-       entityclass(cname, base);               \
-       class(cname).bool instanceOf##cname;    \
-       DEBUG_STUFF(cname)                      \
-       VTBL(cname, base)                       \
-       _INIT_STATIC(cname)                     \
-       {                                       \
-               if (cname##_vtbl && !this.transmute)\
-               {                                   \
-                       copyentity(cname##_vtbl, this); \
-                       return;                         \
-               }                                   \
-               spawn##base##_static(this);         \
-               this.instanceOf##cname = true;      \
-       }                                       \
-       INIT(cname)                             \
-       {                                       \
-               /* Only statically initialize the current class, it contains everything it inherits */ \
-               if (cname##_vtbl.vtblname == this.classname) \
-               {                                   \
-                       spawn##cname##_static(this);    \
-                       this.transmute = false;         \
-                       this.classname = #cname;        \
-                       this.vtblname = string_null;    \
-                       this.vtblbase = cname##_vtbl;   \
-               }                                   \
-               spawn##base##_1(this);              \
-       }
-
 #define METHOD_REFERENCE(cname, name) \
        cname##_##name
 
-#define STATIC_METHOD(cname, name, prototype) \
-       prototype METHOD_REFERENCE(cname, name)
-
-#define METHOD(cname, name, prototype) \
-       STATIC_METHOD(cname, name, prototype); \
-       class(cname) .prototype name; \
-       _INIT_STATIC(cname) \
-       { \
-               this.name = METHOD_REFERENCE(cname, name); \
-       } \
-       STATIC_METHOD(cname, name, prototype)
-
-#define DESTRUCTOR(cname) \
-       STATIC_METHOD(cname, dtorimpl, void(cname this)); \
-    METHOD(cname, dtor, void(cname this)) \
-    { \
-        METHOD_REFERENCE(cname, dtorimpl)(this); \
-        this.instanceOf##cname = false; \
-        entity super = SUPER(cname); \
-        if (super != cname##_vtbl) super.dtor(this); \
-    } \
-       STATIC_METHOD(cname, dtorimpl, void(cname this))
-
-#define ATTRIB(...) EVAL_ATTRIB(OVERLOAD_(ATTRIB, __VA_ARGS__))
-#define EVAL_ATTRIB(...) __VA_ARGS__
-#define ATTRIB_3(cname, name, type) INIT(cname) {} class(cname) .type name
-#define ATTRIB_4(cname, name, type, val) \
-       ATTRIB_3(cname, name, type); \
-       INIT(cname) \
-       { \
-               noref bool strzone; /* Error on strzone() calls. */ \
-               this.name = val; \
-       } \
-       ATTRIB_3(cname, name, type)
-
-#define STATIC_ATTRIB(cname, name, type, val) \
-       type cname##_##name; \
-       _INIT_STATIC(cname) \
-       { \
-               noref bool strzone; /* Error on strzone() calls. */ \
-               cname##_##name = val; \
-       }
-
-// cleanup potentially zoned strings from base classes
-
-#define ATTRIB_STRZONE(cname, name, type, val)      \
-       class(cname).type name;                \
-       INIT(cname) \
-       { \
-               if (this.name) \
-                       strunzone(this.name); \
-               this.name = strzone(val); \
-       }
-
-#define STATIC_ATTRIB_STRZONE(cname, name, type, val) \
-       type cname##_##name; \
-       _INIT_STATIC(cname) \
-       { \
-        if (cname##_##name) \
-            strunzone(cname##_##name); \
-               cname##_##name = val; \
-       }
-
-#define ATTRIBARRAY(cname, name, type, cnt) \
-       class(cname) .type name[cnt]
-
-#define ENDCLASS(cname) \
-       INIT(cname) \
-       { \
-               return this; \
-       }
-
-#define SUPER(cname) (cname##_vtbl.vtblbase)
+#endif
 
 #define spawn_static(this)
 #define spawn_1(this)
 #define _vtbl NULL
-CLASS(Object, );
+CLASS(Object)
     DESTRUCTOR(Object) { builtin_remove(this); }
     #define remove(this) delete(this)
        METHOD(Object, describe, string(Object this))
diff --git a/qcsrc/lib/promise.qc b/qcsrc/lib/promise.qc
new file mode 100644 (file)
index 0000000..475208e
--- /dev/null
@@ -0,0 +1,214 @@
+#include "promise.qh"
+
+.int _ref_count;
+.void(entity this) _ref_finalize;
+
+void ref_init(entity this, int init, void(entity this) finalize)
+{
+    this._ref_count = init;
+    this._ref_finalize = finalize;
+}
+
+// todo: rename to `ref`
+entity REF(entity this)
+{
+    this._ref_count += 1;
+    return this;
+}
+
+entity unref(Promise this)
+{
+    this._ref_count -= 1;
+    if (!this._ref_count) {
+        LOG_DEBUGF("Finalize entity %i (from %s)", this, this.sourceLoc);
+        this._ref_finalize(this);
+        return NULL;
+    }
+    return this;
+}
+
+enum {
+    PROMISE_PENDING,
+    PROMISE_RESOLVED,
+    PROMISE_REJECTED,
+};
+
+classfield(Promise) .int _promise_state;
+classfield(Promise) .entity _promise_result;
+classfield(Promise) .IntrusiveList _promise_handlers;
+
+entityclass(PromiseHandler);
+classfield(PromiseHandler) .Promise _promise_handler_ret;
+classfield(PromiseHandler) .entity _promise_handler_data;
+classfield(PromiseHandler) .Promise(Promise ret, entity result, entity userdata) _promise_handler_resolve;
+classfield(PromiseHandler) .Promise(Promise ret, entity err, entity userdata) _promise_handler_reject;
+
+void _Promise_finalize(Promise this)
+{
+    delete(this);
+}
+
+Promise Promise_new_(Promise this)
+{
+    ref_init(this, 2, _Promise_finalize);
+    this._promise_result = this; // promises default to being their own result to save on entities
+    return this;
+}
+
+void _Promise_handle(Promise this, PromiseHandler h);
+
+void Promise_resolve(Promise this)
+{
+    if (!this) {
+        LOG_SEVERE("Attempted to resolve a null promise");
+        return;
+    }
+    if (this._promise_state != PROMISE_PENDING) {
+        LOG_SEVEREF("Resolved non-pending promise %i", this);
+        return;
+    }
+    this._promise_state = PROMISE_RESOLVED;
+    if (this._promise_handlers) {
+        IL_EACH(this._promise_handlers, true, _Promise_handle(this, it));
+        IL_DELETE(this._promise_handlers);
+    }
+    unref(this);
+    return;
+}
+
+void Promise_reject(Promise this)
+{
+    if (!this) {
+        LOG_SEVERE("Attempted to reject a null promise");
+        return;
+    }
+    if (this._promise_state != PROMISE_PENDING) {
+        LOG_SEVEREF("Rejected non-pending promise %i", this);
+        return;
+    }
+    this._promise_state = PROMISE_REJECTED;
+    if (this._promise_handlers) {
+        IL_EACH(this._promise_handlers, true, _Promise_handle(this, it));
+        IL_DELETE(this._promise_handlers);
+    }
+    unref(this);
+    return;
+}
+
+Promise _Promise_then(
+        Promise this,
+        Promise ret,
+        Promise(Promise ret, entity result, entity userdata) onResolve,
+        Promise(Promise ret, entity result, entity userdata) onReject,
+        entity userdata
+);
+
+void _Promise_handle(Promise this, PromiseHandler h)
+{
+    switch (this._promise_state) {
+        case PROMISE_PENDING:
+            if (!this._promise_handlers) {
+                this._promise_handlers = IL_NEW();
+            }
+            IL_PUSH(this._promise_handlers, h);
+            break;
+        case PROMISE_RESOLVED: {
+            Promise ret = h._promise_handler_ret;
+            Promise p = h._promise_handler_resolve(ret, this._promise_result, h._promise_handler_data);
+            if (p != ret) _Promise_then(p, ret, func_null, func_null, NULL); // bind p -> ret
+            delete(h);
+            break;
+        }
+        case PROMISE_REJECTED: {
+            Promise ret = h._promise_handler_ret;
+            Promise p = h._promise_handler_reject(ret, this._promise_result, h._promise_handler_data);
+            if (p != ret) _Promise_then(p, ret, func_null, func_null, NULL); // bind p -> ret
+            delete(h);
+            break;
+        }
+    }
+}
+
+void _Promise_done(
+        Promise this,
+        Promise(Promise ret, entity result, entity userdata) onResolve,
+        Promise(Promise ret, entity err, entity userdata) onReject,
+        Promise ret,
+        entity userdata
+)
+{
+    PromiseHandler h = new_pure(PromiseHandler);
+    h._promise_handler_ret = ret;
+    h._promise_handler_data = userdata;
+    h._promise_handler_resolve = onResolve;
+    h._promise_handler_reject = onReject;
+    _Promise_handle(this, h);
+}
+
+Promise _Promise_onResolve_default(Promise ret, entity result, entity userdata)
+{
+    ret._promise_result = result;
+    Promise_resolve(ret);
+    return ret;
+}
+
+Promise _Promise_onReject_default(Promise ret, entity err, entity userdata)
+{
+    ret._promise_result = err;
+    Promise_reject(ret);
+    return ret;
+}
+
+Promise _Promise_then(
+        Promise this,
+        Promise ret,
+        Promise(Promise ret, entity result, entity userdata) onResolve,
+        Promise(Promise ret, entity result, entity userdata) onReject,
+        entity userdata
+)
+{
+    _Promise_done(
+            this,
+            (onResolve ? onResolve : _Promise_onResolve_default),
+            (onReject ? onReject : _Promise_onReject_default),
+            ret,
+            userdata
+    );
+    return ret;
+}
+
+Promise Promise_then_(
+        Promise this,
+        Promise ret,
+        Promise(Promise ret, entity result, entity userdata) onResolve,
+        entity userdata
+)
+{
+    unref(ret); // ret is a temporary
+    return _Promise_then(this, ret, onResolve, func_null, userdata);
+}
+
+Promise Promise_catch_(
+        Promise this,
+        Promise ret,
+        Promise(Promise ret, entity result, entity userdata) onReject,
+        entity userdata
+)
+{
+    unref(ret); // ret is a temporary
+    return _Promise_then(this, ret, func_null, onReject, userdata);
+}
+
+// utils
+
+#ifndef MENUQC
+
+Promise Promise_sleep(float n)
+{
+    Promise p = unref(Promise_new());
+    setthink(p, Promise_resolve);
+    p.nextthink = time + n;
+    return p;
+}
+
+#endif
diff --git a/qcsrc/lib/promise.qh b/qcsrc/lib/promise.qh
new file mode 100644 (file)
index 0000000..a793f58
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+entityclass(Promise);
+
+#define Promise_new() Promise_new_(new_pure(Promise))
+Promise Promise_new_(Promise this);
+
+/**
+ * notify all Promise_then subscribers that this promise has resolved
+ */
+void Promise_resolve(Promise this);
+
+#define Promise_then(this, handler, userdata) Promise_then_(this, Promise_new(), handler, userdata)
+Promise Promise_then_(Promise this, Promise ret, Promise(Promise ret, entity result, entity userdata) handler, entity userdata);
+
+/**
+ * notify all Promise_catch subscribers that this promise has rejected
+ */
+void Promise_reject(Promise this);
+
+#define Promise_catch(this, handler, userdata) Promise_catch_(this, Promise_new(), handler, userdata)
+Promise Promise_catch_(Promise this, Promise ret, Promise(Promise ret, entity err, entity userdata) handler, entity userdata);
+
+// utils
+
+#ifndef MENUQC
+
+// TODO: support menu
+Promise Promise_sleep(float n);
+
+#endif
index 2d41e5d431b3ba9c7b63ccbb87268a4b96615267..d8f18a02c96e4ab98b749530dd5f1f58550609b5 100644 (file)
@@ -22,9 +22,9 @@
  */
 #define REGISTRY(id, max) \
        void Register##id(); \
-       [[accumulate]] void REGISTRY_DEPENDS_(id) {} \
-       [[accumulate]] REGISTRY_BEGIN(id) {} \
-       [[accumulate]] REGISTRY_END(id) {} \
+       ACCUMULATE void REGISTRY_DEPENDS_(id) {} \
+       REGISTRY_BEGIN(id) {} \
+       REGISTRY_END(id) {} \
        void _Register##id() {} \
        int id##_state = 0; \
        void Register##id() { if (id##_state) return; id##_state = 1; REGISTRY_DEPENDS_(id); REGISTRY_BEGIN_(id); _Register##id(); id##_state = 2; REGISTRY_END_(id); } \
 #define REGISTRY_DEPENDS_(id) Register##id##_Depends()
 
 /** Called before initializing a registry. */
-#define REGISTRY_BEGIN(id) [[accumulate]] void REGISTRY_BEGIN_(id) { noref void() f = Register##id; } void REGISTRY_BEGIN_(id)
+#define REGISTRY_BEGIN(id) ACCUMULATE void REGISTRY_BEGIN_(id) { noref void() f = Register##id; } void REGISTRY_BEGIN_(id)
 #define REGISTRY_BEGIN_(id) Register##id##_First()
 
 /** Called after initializing a registry. */
-#define REGISTRY_END(id) [[accumulate]] void REGISTRY_END_(id) { noref void() f = Register##id; } void REGISTRY_END_(id)
+#define REGISTRY_END(id) ACCUMULATE void REGISTRY_END_(id) { noref void() f = Register##id; } void REGISTRY_END_(id)
 #define REGISTRY_END_(id) Register##id##_Done()
 
 REGISTRY(Registries, BITS(8))
@@ -104,7 +104,7 @@ REGISTRY(Registries, BITS(8))
        REGISTRY_PUSH(registry, fld, e); \
 } MACRO_END
 
-#define REGISTER_INIT(id) [[accumulate]] void Register_##id##_init(entity this)
+#define REGISTER_INIT(id) ACCUMULATE void Register_##id##_init(entity this)
 
 /** internal next pointer */
 #define REGISTRY_NEXT enemy
@@ -147,9 +147,9 @@ REGISTRY(Registries, BITS(8))
 #define REGISTRY_HASH(id) Registry_hash_##id
 
 ERASEABLE
-[[accumulate]] void Registry_check(string r, string server) { }
+ACCUMULATE void Registry_check(string r, string server) { }
 ERASEABLE
-[[accumulate]] void Registry_send_all() { }
+ACCUMULATE void Registry_send_all() { }
 
 #ifdef SVQC
 void Registry_send(string id, string hash);
index c7a42042deac253dc3172aeaf929a80ba2958b18..656989782672e60c948199c0b8deb94f2f10b0a6 100644 (file)
        #define REPLICATE(...) EVAL_REPLICATE(OVERLOAD(REPLICATE, __VA_ARGS__))
        #define EVAL_REPLICATE(...) __VA_ARGS__
 
-       [[accumulate]] void ReplicateVars(entity this, entity store, string thisname, int i) {}
+       ACCUMULATE void ReplicateVars(entity this, entity store, string thisname, int i) {}
 
        #define REPLICATE_3(fld, type, var) REPLICATE_4(fld, type, var, )
        #define REPLICATE_4(fld, type, var, func) REPLICATE_##type(fld, var, func)
        #define REPLICATE_string(fld, var, func) \
                REPLICATE_7(fld, string, var, , \
-       { if (field) strunzone(field); field = strzone(it); }, \
-       { if (field) strunzone(field); field = string_null; }, \
+       { strcpy(field, it); }, \
+       { strfree(field); }, \
        { \
                /* also initialize to the default value of func when requesting cvars */ \
                string s = func(field); \
                if (s != field) \
                { \
-                   strunzone(field); \
-                   field = strzone(s); \
+                   strcpy(field, s); \
                } \
        })
        #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func,  { field = stof(it); },          , )
index 0a61cc003dfdc9046acf24dc7b33b057115732e8..4299c19cd3674a286d3b5eea310a0754f3db0ad1 100644 (file)
@@ -12,7 +12,7 @@
 // Step 2: const self
 #if 1
     #define self (RVALUE, self)
-    [[alias("self")]] entity __self;
+    ALIAS("self") entity __self;
     #define setself(s) (__self = s)
     #define WITHSELF(value, block) WITH(entity, __self, value, (RVALUE, block))
 #endif
index af4b47ab8058ad35a8f8b6405538cc3f4ed32a31..8c362d4305cd98721075bfe84aa8a7a1ab0c4910 100644 (file)
@@ -2,7 +2,7 @@
 
 entityclass(Sort);
 // .float(entity,entity) sort_cmp;
-class(Sort).entity chain, sort_next, sort_prev;
+classfield(Sort).entity chain, sort_next, sort_prev;
 
 entity Sort_Spawn();
 
index ac9ad505801b76edce158c34b8e3176c369e7c71..d3198b3ce4c7666bf986564916b9d9678b3dc097 100644 (file)
@@ -19,13 +19,13 @@ noref bool require_spawnfunc_prefix;
        }
 
        #define _spawnfunc_checktypes(fld) \
-               if (fieldname == #fld) \
-                       if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", fieldname);
+               if (s == #fld) \
+                       if (!entityfieldassignablefromeditor(i)) LOG_FATALF("Entity field '%s' cannot be whitelisted", s);
 #else
        #define _spawnfunc_checktypes(fld)
 #endif
        #define _spawnfunc_check(fld) \
-               if (fieldname == #fld) continue;
+               if (s == #fld) continue;
 
        noref int __spawnfunc_expecting;
        noref entity __spawnfunc_expect;
@@ -86,7 +86,7 @@ noref bool require_spawnfunc_prefix;
        #define spawnfunc_1(id) spawnfunc_2(id, FIELDS_UNION)
        #define spawnfunc_2(id, whitelist) \
                void __spawnfunc_##id(entity this); \
-               [[accumulate]] void spawnfunc_##id(entity this) \
+               ACCUMULATE void spawnfunc_##id(entity this) \
                { \
                    if (!__spawnfunc_first) { \
                 __spawnfunc_first = true; \
@@ -111,13 +111,13 @@ noref bool require_spawnfunc_prefix;
                        if (!this.spawnfunc_checked) { \
                                for (int i = 0, n = numentityfields(); i < n; ++i) { \
                                        string value = getentityfieldstring(i, this); \
-                                       string fieldname = entityfieldname(i); \
+                                       string s = entityfieldname(i); \
                                        whitelist(_spawnfunc_checktypes) \
                                        if (value == "") continue; \
-                                       if (fieldname == "") continue; \
+                                       if (s == "") continue; \
                                        FIELDS_COMMON(_spawnfunc_check) \
                                        whitelist(_spawnfunc_check) \
-                                       LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, fieldname, value); \
+                                       LOG_WARNF(_("Entity field %s.%s (%s) is not whitelisted. If you believe this is an error, please file an issue."), #id, s, value); \
                                } \
                                this.spawnfunc_checked = true; \
                                if (this) { \
@@ -163,6 +163,7 @@ noref bool require_spawnfunc_prefix;
                FIELD_SCALAR(fld, bgmscriptsustain) \
                FIELD_SCALAR(fld, bgmscript) \
                FIELD_SCALAR(fld, button0) \
+               FIELD_SCALAR(fld, chmap) \
                FIELD_SCALAR(fld, cnt) \
                FIELD_SCALAR(fld, colormap) \
                FIELD_SCALAR(fld, count) \
@@ -182,10 +183,12 @@ noref bool require_spawnfunc_prefix;
                FIELD_SCALAR(fld, dmg_force) \
                FIELD_SCALAR(fld, dmg_radius) \
                FIELD_SCALAR(fld, effects) \
+               FIELD_SCALAR(fld, falloff) \
                FIELD_SCALAR(fld, flags) \
                FIELD_SCALAR(fld, fog) \
                FIELD_SCALAR(fld, frags) \
                FIELD_SCALAR(fld, frame) \
+               FIELD_SCALAR(fld, gametype) \
                FIELD_SCALAR(fld, gametypefilter) \
                FIELD_SCALAR(fld, geomtype) \
                FIELD_SCALAR(fld, gravity) \
@@ -216,6 +219,7 @@ noref bool require_spawnfunc_prefix;
                FIELD_SCALAR(fld, noalign) \
                FIELD_SCALAR(fld, noise1) \
                FIELD_SCALAR(fld, noise2) \
+               FIELD_SCALAR(fld, noise3) \
                FIELD_SCALAR(fld, noise) \
                FIELD_SCALAR(fld, phase) \
                FIELD_SCALAR(fld, platmovetype) \
@@ -243,6 +247,7 @@ noref bool require_spawnfunc_prefix;
                FIELD_SCALAR(fld, target_random) \
                FIELD_SCALAR(fld, target_range) \
                FIELD_SCALAR(fld, team) \
+               FIELD_SCALAR(fld, trigger_reverse) \
                FIELD_SCALAR(fld, turret_scale_health) \
                FIELD_SCALAR(fld, turret_scale_range) \
                FIELD_SCALAR(fld, turret_scale_respawn) \
@@ -256,13 +261,13 @@ noref bool require_spawnfunc_prefix;
                FIELD_VEC(fld, absmin) \
                FIELD_VEC(fld, angles) \
                FIELD_VEC(fld, avelocity) \
+               FIELD_VEC(fld, beam_color)\
                FIELD_VEC(fld, debrisavelocityjitter) \
                FIELD_VEC(fld, debrisvelocity) \
                FIELD_VEC(fld, debrisvelocityjitter) \
                FIELD_VEC(fld, color) \
                FIELD_VEC(fld, mangle) \
                FIELD_VEC(fld, maxs) \
-               FIELD_VEC(fld, maxs) \
                FIELD_VEC(fld, mins) \
                FIELD_VEC(fld, modelscale_vec) \
                FIELD_VEC(fld, velocity) \
index 6f511fcecfa1c9c1f2ef842ad5fe47ac44fbd7ef..e0ec96b8ec0c43872992e12523329c0be74e8f5d 100644 (file)
@@ -17,7 +17,9 @@ void profile(string s)
 }
 
 #define _STATIC_INIT(func, where) \
-       [[accumulate]] void _static_##func() { profile(#func); } \
+       ACCUMULATE void _static_##func##profile() { profile(#func); } \
+       ACCUMULATE_FUNCTION(where, _static_##func##profile) \
+       ACCUMULATE void _static_##func(); \
        ACCUMULATE_FUNCTION(where, _static_##func) \
        void _static_##func()
 
index 1100c474cb9eb49074cd85d08431fd0f0ba61012..03bd34b813af0714b0380c0aa3ea423713b86bd3 100644 (file)
@@ -53,7 +53,7 @@ int g_magic_stats_hole = 0;
                                REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
                        } \
                } \
-               [[accumulate]] void stats_get() \
+               ACCUMULATE void stats_get() \
                { \
                        T it = getstat_##T(STAT_##id.m_id); \
                        /* if (it != CAT(_STAT(id), _prev)) \
@@ -111,7 +111,7 @@ int g_magic_stats_hole = 0;
                                REGISTRY_RESERVE(Stats, m_id, STAT_##id, z); \
                        } \
                } \
-               [[accumulate]] void stats_add() \
+               ACCUMULATE void stats_add() \
                { \
                        .T fld = _STAT(id); \
                        addstat_##T(STAT_##id.m_id, fld); \
@@ -120,7 +120,7 @@ int g_magic_stats_hole = 0;
     /** TODO: do we want the global copy to update? */
     #define REGISTER_STAT_3(id, T, expr) \
        REGISTER_STAT_2(id, T); \
-       [[accumulate]] void GlobalStats_update(entity this) { STAT(id, this) = (expr); } \
+       ACCUMULATE void GlobalStats_update(entity this) { STAT(id, this) = (expr); } \
        STATIC_INIT(worldstat_##id) { entity this = STATS; STAT(id, this) = (expr); }
 #else
        #define REGISTER_STAT_2(id, type)
index 0a3fb085c1d5fb988298073071745b829578cb3d..96e8a3a276258d568380219e0b1d8218ac9b7cf5 100644 (file)
@@ -4,6 +4,25 @@
 #include "sort.qh"
 #include "oo.qh"
 
+// string logic
+//
+// true: is truthy
+// == "": is equal to ""
+// is "": has the same string index as the string constant ""
+// strunzone: can be strunzoned
+//
+// |              | true | == "" | is "" | strunzone |
+// | :----------: | :--: | :---: | :---: | :-------: |
+// | nil          |      | yes   |       |           |
+// | strcat(nil)  | yes  | yes   |       |           |
+// | strzone(nil) | yes  | yes   |       | yes       |
+// | ""           | yes  | yes   | yes   |           |
+// | strcat("")   | yes  | yes   |       |           |
+// | strzone("")  | yes  | yes   |       | yes       |
+// | "s"          | yes  |       |       |           |
+// | strcat("s")  | yes  |       |       |           |
+// | strzone("s") | yes  |       |       | yes       |
+
 #ifdef CSQC
        float stringwidth_colors(string s, vector theSize)
        {
        }
 #endif
 
+#define strcpy(this, s) MACRO_BEGIN \
+       if (this) { \
+               strunzone(this); \
+       } \
+       this = strzone(s); \
+MACRO_END
+
+#define strfree(this) MACRO_BEGIN \
+       if (this) { \
+               strunzone(this); \
+       } \
+       this = string_null; \
+MACRO_END
+
 ERASEABLE
 string seconds_tostring(float sec)
 {
@@ -161,6 +194,14 @@ string cons(string a, string b)
        return strcat(a, " ", b);
 }
 
+ERASEABLE
+string cons_mid(string a, string mid, string b)
+{
+       if (a == "") return b;
+       if (b == "") return a;
+       return strcat(a, mid, b);
+}
+
 ERASEABLE
 string substring_range(string s, float b, float e)
 {
index ff6f2d23d5b52f1e00d75ba699c6552031ba8f5b..8d8de76ec6119abecd88093b0bd52bd8e1bb08e3 100644 (file)
@@ -5,7 +5,7 @@
 /** Use UpperCamelCase for suite and test only */
 #define TEST(suite, test) \
        void _TEST_##suite##_##test(); \
-       [[accumulate]] int TEST_RunAll_accumulated(int f) { \
+       ACCUMULATE int TEST_RunAll_accumulated(int f) { \
                if (!TEST_Run(#suite "_" #test)) ++f; \
                return = f; \
        } \
index 1572fec07cb2d1962870f63d7a3e3021db220841..2ad7bda2464b6842daa52fb70b2889c1835ab02c 100644 (file)
@@ -55,7 +55,7 @@ float url_URI_Get_Callback(int id, float status, string data)
                {
                        LOG_INFO("url_URI_Get_Callback: out of memory in buf_create");
                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
-                       strunzone(e.url_url);
+                       strfree(e.url_url);
                        delete(e);
                        return 1;
                }
@@ -64,7 +64,7 @@ float url_URI_Get_Callback(int id, float status, string data)
                {
                        LOG_INFO("url_URI_Get_Callback: out of memory in buf_create");
                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
-                       strunzone(e.url_url);
+                       strfree(e.url_url);
                        delete(e);
                        return 1;
                }
@@ -77,7 +77,7 @@ float url_URI_Get_Callback(int id, float status, string data)
        {
                // an ERROR
                e.url_ready(e, e.url_ready_pass, -fabs(status));
-               strunzone(e.url_url);
+               strfree(e.url_url);
                delete(e);
                return 1;
        }
@@ -108,7 +108,7 @@ void url_single_fopen(string url, int mode, url_ready_func rdy, entity pass)
                                {
                                        LOG_INFO("url_single_fopen: out of memory in buf_create");
                                        rdy(e, pass, URL_READY_ERROR);
-                                       strunzone(e.url_url);
+                                       strfree(e.url_url);
                                        delete(e);
                                        return;
                                }
@@ -231,7 +231,7 @@ void url_fclose(entity e)
                                        LOG_INFO("url_fclose: too many concurrent requests");
                                        e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
                                        buf_del(e.url_wbuf);
-                                       strunzone(e.url_url);
+                                       strfree(e.url_url);
                                        delete(e);
                                        return;
                                }
@@ -243,7 +243,7 @@ void url_fclose(entity e)
                                LOG_INFO("url_fclose: failure in crypto_uri_postbuf");
                                e.url_ready(e, e.url_ready_pass, URL_READY_ERROR);
                                buf_del(e.url_wbuf);
-                               strunzone(e.url_url);
+                               strfree(e.url_url);
                                delete(e);
                                return;
                        }
@@ -264,7 +264,7 @@ void url_fclose(entity e)
                        // we have READ all data, just close
                        e.url_ready(e, e.url_ready_pass, URL_READY_CLOSED);
                        buf_del(e.url_rbuf);
-                       strunzone(e.url_url);
+                       strfree(e.url_url);
                        delete(e);
                }
        }
@@ -341,7 +341,7 @@ void url_multi_ready(entity fh, entity me, float status)
                {
                        LOG_INFO("uri_multi_ready: got HTTP error 422, data is in unusable format - not continuing");
                        me.url_ready(fh, me.url_ready_pass, status);
-                       strunzone(me.url_url);
+                       strfree(me.url_url);
                        delete(me);
                        return;
                }
@@ -350,7 +350,7 @@ void url_multi_ready(entity fh, entity me, float status)
                if (n <= me.url_attempt)
                {
                        me.url_ready(fh, me.url_ready_pass, status);
-                       strunzone(me.url_url);
+                       strfree(me.url_url);
                        delete(me);
                        return;
                }
index acbc1c61d4dda0f69cb0d256467f16bc2808cb07..4a7c8861069f7eb8420ec819b9525d606ffbe2d2 100644 (file)
@@ -63,11 +63,11 @@ float tanh(float e)
 
 float exp(float e)
 {
-       return (M_E ** e);
+       return pow(M_E, e);
 }
 float exp2(float e)
 {
-       return (2 ** e);
+       return pow(2, e);
 }
 float expm1(float e)
 {
@@ -79,16 +79,16 @@ vector frexp(float e)
        vector v;
        v.z = 0;
        v.y = ilogb(e) + 1;
-       v.x = e / (2 ** v.y);
+       v.x = e / pow(2, v.y);
        return v;
 }
 int ilogb(float e)
 {
        return floor(log2(fabs(e)));
 }
-float ldexp(float e, int e)
+float ldexp(float x, int e)
 {
-       return e * (2 ** e);
+       return x * pow(2, e);
 }
 float logn(float e, float base)
 {
@@ -117,12 +117,12 @@ vector modf(float f)
 
 float scalbn(float e, int n)
 {
-       return e * (2 ** n);
+       return e * pow(2, n);
 }
 
 float cbrt(float e)
 {
-       return copysign((fabs(e) ** (1.0/3.0)), e);
+       return copysign(pow(fabs(e), (1.0/3.0)), e);
 }
 float hypot(float e, float f)
 {
index ce4535452da5405d3b57495462ac51d27c9dd1ce..2805c005096582383c78f9464906ccecca337817 100644 (file)
@@ -6,7 +6,7 @@
 #elif defined(SVQC)
        #include <common/constants.qh>
        #include <common/net_linked.qh>
-       #include <common/triggers/subs.qh>
+       #include <common/mapobjects/subs.qh>
        #include <common/util.qh>
        #include <server/constants.qh>
        #include <server/defs.qh>
index e727b39e6446acbb10e8745c5b0a5bb93d3fcdea..bd45230c97ab61964f43a7153d69242fb896e38c 100644 (file)
@@ -3,7 +3,7 @@
 #include "../menu.qh"
 #include "../item.qh"
 
-#include "../mutators/events.qh"
+#include <menu/mutators/_mod.qh>
 
 #include <common/command/_mod.qh>
 
index a418dc2ce0fffa7b761fff860ebe8f950dbb09bf..d02f4661f5cd84bf891af26a6c1bef694244f463 100644 (file)
@@ -22,7 +22,7 @@
 
        void InputBox_setText(entity me, string txt)
        {
-               if (me.text) strunzone(me.text);
+               strfree(me.text);
                SUPER(InputBox).setText(me, strzone(txt));
        }
 
index d21b5676bd597d32da93d61b3f3a850d15d5af7b..f7a782dabbf877a3b0bcef5adee11db333d8edc0 100644 (file)
@@ -9,8 +9,7 @@
                me.text = txt;
                if (txt != me.currentText)
                {
-                       if (me.currentText) strunzone(me.currentText);
-                       me.currentText = strzone(txt);
+                       strcpy(me.currentText, txt);
                        me.recalcPos = 1;
                }
        }
                        t = me.textEntity.toString(me.textEntity);
                        if (t != me.currentText)
                        {
-                               if (me.currentText) strunzone(me.currentText);
-                               me.currentText = strzone(t);
+                               strcpy(me.currentText, t);
                                me.recalcPos = 1;
                        }
                }
index af14e0842b4dc749897a45e7fc2f18ae2dcaf6c4..fb6c4aeeda60a612cbe47ffe4c6804022b315c23 100644 (file)
@@ -217,8 +217,7 @@ void m_init_delayed()
        if (m_goto_buffer)
        {
                m_goto(m_goto_buffer);
-               strunzone(m_goto_buffer);
-               m_goto_buffer = string_null;
+               strfree(m_goto_buffer);
        }
 
        if (Menu_Active) m_display();  // delayed menu display
@@ -550,8 +549,7 @@ void m_tooltip(vector pos)
                        {
                                // fade out if tooltip of a certain item has changed
                                menuTooltipState = 3;
-                               if (prev_tooltip) strunzone(prev_tooltip);
-                               prev_tooltip = strzone(it.tooltip);
+                               strcpy(prev_tooltip, it.tooltip);
                        }
                        else if (menuTooltipItem && !m_testmousetooltipbox(pos))
                        {
@@ -584,8 +582,7 @@ void m_tooltip(vector pos)
 
                                        menuTooltipOrigin.x = -1;  // unallocated
 
-                                       if (menuTooltipText) strunzone(menuTooltipText);
-                                       menuTooltipText = strzone(gettooltip());
+                                       strcpy(menuTooltipText, gettooltip());
 
                                        int i = 0;
                                        float w = 0;
@@ -635,11 +632,7 @@ void m_tooltip(vector pos)
 
        if (menuTooltipItem == NULL)
        {
-               if (menuTooltipText)
-               {
-                       strunzone(menuTooltipText);
-                       menuTooltipText = string_null;
-               }
+               strfree(menuTooltipText);
                return;
        }
        else
@@ -953,8 +946,7 @@ void m_goto(string itemname)
 {
        if (!menuInitialized)
        {
-               if (m_goto_buffer) strunzone(m_goto_buffer);
-               m_goto_buffer = strzone(itemname);
+               strcpy(m_goto_buffer, itemname);
                return;
        }
        if (itemname == "")  // this can be called by GameCommand
index 98fb4815c1ce28cc699a429537ea75c2643b4487..26980926907738b2dcf21eff8fd91fb0392e639f 100644 (file)
@@ -1 +1,2 @@
 // generated file; do not modify
+#include <menu/mutators/events.qc>
index 98fb4815c1ce28cc699a429537ea75c2643b4487..93432be42cad402636ed8ad992678b44471b873f 100644 (file)
@@ -1 +1,2 @@
 // generated file; do not modify
+#include <menu/mutators/events.qh>
diff --git a/qcsrc/menu/mutators/events.qc b/qcsrc/menu/mutators/events.qc
new file mode 100644 (file)
index 0000000..c2dbb70
--- /dev/null
@@ -0,0 +1 @@
+#include "events.qh"
index 1df38f5af09c571df07e280b3c9691ec192f837b..af1b7f6324ffaae82ade9eab7002e640aa63ce0e 100644 (file)
@@ -2,6 +2,11 @@
 
 #include <common/mutators/base.qh>
 
+// register all possible hooks here
+
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
+
 // globals
 
 string cmd_name;
index cb418a4e1834fcce6076672f337e818fef681ca5..9f953f66f542f9a8b9238d65e813a6b5cdf777c7 100644 (file)
@@ -14,8 +14,7 @@ void rewrapCampaign(float w, float l0, float emptyheight, vector theFontSize)
        for(i = 0; i < campaign_entries; ++i)
        {
                l = l0;
-               if(campaign_longdesc_wrapped[i])
-                       strunzone(campaign_longdesc_wrapped[i]);
+               strfree(campaign_longdesc_wrapped[i]);
                n = tokenizebyseparator(campaign_longdesc[i], "\n");
                r = "";
                for(j = 0; j < n; ++j)
@@ -70,12 +69,8 @@ void XonoticCampaignList_destroy(entity me)
 void XonoticCampaignList_loadCvars(entity me)
 {
        // read campaign cvars
-       if(campaign_name)
-               strunzone(campaign_name);
-       if(me.cvarName)
-               strunzone(me.cvarName);
-       campaign_name = strzone(cvar_string("g_campaign_name"));
-       me.cvarName = strzone(strcat("g_campaign", campaign_name, "_index"));
+       strcpy(campaign_name, cvar_string("g_campaign_name"));
+       strcpy(me.cvarName, strcat("g_campaign", campaign_name, "_index"));
        registercvar(me.cvarName, "", 0); // saved by server QC anyway
        CampaignFile_Unload();
        CampaignFile_Load(0, CAMPAIGN_MAX_ENTRIES);
index e11d7dcc0f04d4f9401edbb4d16273b823162542..f3c3fe24fa48ee237b2be4c277b5a0a912f1254f 100644 (file)
@@ -25,9 +25,7 @@ void XonoticCrosshairPreview_draw(entity me)
        float a;
        rgb = stov(cvar_string("crosshair_color"));
        a = cvar("crosshair_alpha");
-       if(me.src)
-               strunzone(me.src);
-       me.src = strzone(strcat("/gfx/crosshair", cvar_string("crosshair")));
+       strcpy(me.src, strcat("/gfx/crosshair", cvar_string("crosshair")));
 
        sz = draw_PictureSize(me.src);
        sz = globalToBoxSize(sz, me.size);
index 12bb2810ba87282e54d9df9c43b7df5e1dba38c1..9587d5432d83c7ebc80dcbac53a26dfc0af370e8 100644 (file)
@@ -107,17 +107,10 @@ void XonoticCvarList_setSelected(entity me, float i)
        if(me.nItems == 0)
                return;
 
-       if(me.cvarName)
-               strunzone(me.cvarName);
-       if(me.cvarDescription)
-               strunzone(me.cvarDescription);
-       if(me.cvarType)
-               strunzone(me.cvarType);
-       if(me.cvarDefault)
-               strunzone(me.cvarDefault);
-       me.cvarName = strzone(bufstr_get(me.handle, me.selectedItem));
-       me.cvarDescription = strzone(cvar_description(me.cvarName));
-       me.cvarDefault = strzone(cvar_defstring(me.cvarName));
+       strfree(me.cvarType);
+       strcpy(me.cvarName, bufstr_get(me.handle, me.selectedItem));
+       strcpy(me.cvarDescription, cvar_description(me.cvarName));
+       strcpy(me.cvarDefault, cvar_defstring(me.cvarName));
        me.cvarNameBox.setText(me.cvarNameBox, me.cvarName);
        me.cvarDescriptionBox.setText(me.cvarDescriptionBox, me.cvarDescription);
        float needsForcing = me.updateCvarType(me);
index b527542a5965b1408ed6e299c856ccb414b846df..16d5370f5d7beeef0487001e7aae4c7ad76bb77c 100644 (file)
@@ -129,8 +129,7 @@ void DemoList_Refresh_Click(entity btn, entity me)
 
 void DemoList_Filter_Change(entity box, entity me)
 {
-       if(me.filterString)
-               strunzone(me.filterString);
+       strfree(me.filterString);
 
        if(box.text != "")
        {
index 2e67e7acf861294bb39a6d97bf2a5155e008eaac..611ef4a45e714de1b8292f68904659f3891e9b98 100644 (file)
@@ -10,7 +10,9 @@ void XonoticHUDAmmoDialog_fill(entity me)
        entity e;
        string panelname = "ammo";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Ammunition display:")));
index 9113a02794b1b08f810b009dd491c06fd8be7ab6..3af373e4388d30ee7b9c5623c623625f2b789e60 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDAmmoDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDAmmoDialog, title, string, _("Ammo Panel"));
        ATTRIB(XonoticHUDAmmoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDAmmoDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDAmmoDialog, rows, float, 15);
+       ATTRIB(XonoticHUDAmmoDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDAmmoDialog, columns, float, 4);
        ATTRIB(XonoticHUDAmmoDialog, name, string, "HUDammo");
        ATTRIB(XonoticHUDAmmoDialog, requiresConnection, float, true);
index 332f6753f76d62273411801ab6cd584f46077a9a..938f69a8c57be823a7d95857e70101d37569c2c2 100644 (file)
@@ -10,7 +10,9 @@ void XonoticHUDCenterprintDialog_fill(entity me)
        entity e;
        string panelname = "centerprint";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TDempty(me, 0.2);
index 9fc6846eb9a0d5d044a27ed4c99937190ab3137c..2b952580ecb6e055ae51a1b6bd219d091f73d5de 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDCenterprintDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDCenterprintDialog, title, string, _("Centerprint Panel"));
        ATTRIB(XonoticHUDCenterprintDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDCenterprintDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15);
+       ATTRIB(XonoticHUDCenterprintDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDCenterprintDialog, columns, float, 4);
        ATTRIB(XonoticHUDCenterprintDialog, name, string, "HUDcenterprint");
        ATTRIB(XonoticHUDCenterprintDialog, requiresConnection, float, true);
index 1ffa41f68c802d9c1cdb96995f2aa50619db762e..d1612412e66c8d419f0887b002534c070c091c88 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDChatDialog_fill(entity me)
        entity e;
        string panelname = "chat";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 2, e = makeXonoticTextLabel(0, _("Chat entries:")));
index 570c2d616cde334e7402acc4d061ccad7c299d5d..da2f329bbaa57503569d16c8d1ed5630a2d59052 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDChatDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDChatDialog, title, string, _("Chat Panel"));
        ATTRIB(XonoticHUDChatDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDChatDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDChatDialog, rows, float, 15);
+       ATTRIB(XonoticHUDChatDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDChatDialog, columns, float, 4);
        ATTRIB(XonoticHUDChatDialog, name, string, "HUDchat");
        ATTRIB(XonoticHUDChatDialog, requiresConnection, float, true);
index b46d3aa02eff1fbd791331d3ac731c394506f426..ef63756870dd8d587901593ab2511efd65b99395 100644 (file)
@@ -8,7 +8,9 @@ void XonoticHUDEngineInfoDialog_fill(entity me)
        entity e;
        string panelname = "engineinfo";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Engine info:")));
index b741465024d78a9917639aedabd61c209ae026ca..706767146c776c621c6304fe618be4f2164eabf0 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDEngineInfoDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDEngineInfoDialog, title, string, _("Engine Info Panel"));
        ATTRIB(XonoticHUDEngineInfoDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDEngineInfoDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15);
+       ATTRIB(XonoticHUDEngineInfoDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDEngineInfoDialog, columns, float, 4);
        ATTRIB(XonoticHUDEngineInfoDialog, name, string, "HUDengineinfo");
        ATTRIB(XonoticHUDEngineInfoDialog, requiresConnection, float, true);
index ac305b83258638cd4352305a7071d338a5d85b3d..e67f63ffcda27281ceb077c18c979baa3f097700 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDHealthArmorDialog_fill(entity me)
        entity e;
        string panelname = "healtharmor";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_healtharmor_combined", _("Combine health and armor")));
index b37f41b76ef5f1ecf91a8d2056d2fe8cab68a98e..9342e293306137427ea3d339b34dcf49b749cc85 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDHealthArmorDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDHealthArmorDialog, title, string, _("Health/Armor Panel"));
        ATTRIB(XonoticHUDHealthArmorDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDHealthArmorDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 16);
+       ATTRIB(XonoticHUDHealthArmorDialog, rows, float, 16.5);
        ATTRIB(XonoticHUDHealthArmorDialog, columns, float, 4);
        ATTRIB(XonoticHUDHealthArmorDialog, name, string, "HUDhealtharmor");
        ATTRIB(XonoticHUDHealthArmorDialog, requiresConnection, float, true);
index d758ad206643dcdba154fbfe48be74eca5726b58..6b11a691513c236689e8395df6f798968abd85ff 100644 (file)
@@ -8,7 +8,9 @@ void XonoticHUDInfoMessagesDialog_fill(entity me)
        entity e;
        string panelname = "infomessages";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Info messages:")));
index 5d9032ffb0fdf3e307190fd5a77353b425b5a099..a6370d33e30e88d9566d3508d8ad49d0f3cabf22 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDInfoMessagesDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDInfoMessagesDialog, title, string, _("Info Messages Panel"));
        ATTRIB(XonoticHUDInfoMessagesDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDInfoMessagesDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15);
+       ATTRIB(XonoticHUDInfoMessagesDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDInfoMessagesDialog, columns, float, 4);
        ATTRIB(XonoticHUDInfoMessagesDialog, name, string, "HUDinfomessages");
        ATTRIB(XonoticHUDInfoMessagesDialog, requiresConnection, float, true);
index aeb8c8c774d639fa11a2073135e343e9d8c78f33..32264c5bcd32789aa21add5f6644a67e8a3d95ff 100644 (file)
@@ -13,12 +13,12 @@ void XonoticHUDItemsTimeDialog_fill(entity me)
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_itemstime"));
-                       e.addValue(e, ZCTX(_("PNL^Disabled")), "0");
-                       e.addValue(e, ZCTX(_("PNL^Enabled spectating")), "1");
-                       e.addValue(e, ZCTX(_("PNL^Enabled even playing in warmup")), "2");
+                       e.addValue(e, _("Disable"), "0");
+                       e.addValue(e, _("Enable spectating"), "1");
+                       e.addValue(e, _("Enable even playing in warmup"), "2");
                        e.configureXonoticTextSliderValues(e);
 
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Align icon:")));
index 507dedb7c95cc068adc2d478cf4a83795c72e620..0cb74ea6770fd64031c99f00a93ba45c70076327 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDItemsTimeDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDItemsTimeDialog, title, string, _("Items Time Panel"));
        ATTRIB(XonoticHUDItemsTimeDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDItemsTimeDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDItemsTimeDialog, rows, float, 15);
+       ATTRIB(XonoticHUDItemsTimeDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDItemsTimeDialog, columns, float, 4);
        ATTRIB(XonoticHUDItemsTimeDialog, name, string, "HUDitemstime");
 ENDCLASS(XonoticHUDItemsTimeDialog)
index 53cad1a930383ca693df2d8c5aa2419255df556b..5023d7a2d900fabdcc92e2e7e6613d905fe6a15f 100644 (file)
@@ -4,8 +4,10 @@
 
 void XonoticHUDModIconsDialog_fill(entity me)
 {
-       entity e;
+       //entity e;
        string panelname = "modicons";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 }
index 3a3b72f6c9989df94d4695b135ed30f96f6186e5..a59d09af4b008950114dd03ee860cec51a0e694d 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDModIconsDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDModIconsDialog, title, string, _("Mod Icons Panel"));
        ATTRIB(XonoticHUDModIconsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDModIconsDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDModIconsDialog, rows, float, 15);
+       ATTRIB(XonoticHUDModIconsDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDModIconsDialog, columns, float, 4);
        ATTRIB(XonoticHUDModIconsDialog, name, string, "HUDmodicons");
        ATTRIB(XonoticHUDModIconsDialog, requiresConnection, float, true);
index 490051846e378fd7835c50d684d9294083ef0ddc..1dc0a15b70617ec0cc42d17a90b93c9bacfca8bb 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDNotificationDialog_fill(entity me)
        entity e;
        string panelname = "notify";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Notifications:")));
index f816e4ffe042fd9d6f6f6ba84c46cecbdddc97b6..be51051f6c2b9acd138acd192c2677a5e46d606e 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDNotificationDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDNotificationDialog, title, string, _("Notification Panel"));
        ATTRIB(XonoticHUDNotificationDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDNotificationDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDNotificationDialog, rows, float, 15);
+       ATTRIB(XonoticHUDNotificationDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDNotificationDialog, columns, float, 4);
        ATTRIB(XonoticHUDNotificationDialog, name, string, "HUDnotify");
        ATTRIB(XonoticHUDNotificationDialog, requiresConnection, float, true);
index eabc93dab51021e7c44b1ac2cbe8dab9eda843ec..3a1e0bee1822a42e2fd363323e8f41cec73296f4 100644 (file)
@@ -12,13 +12,13 @@ void XonoticHUDPhysicsDialog_fill(entity me)
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_physics"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled"), "1");
-                       e.addValue(e, _("Panel enabled even observing"), "2");
-                       e.addValue(e, _("Panel enabled only in Race/CTS"), "3");
+                       e.addValue(e, _("Disable"), "0");
+                       e.addValue(e, _("Enable"), "1");
+                       e.addValue(e, _("Enable even observing"), "2");
+                       e.addValue(e, _("Enable only in Race/CTS"), "3");
                        e.configureXonoticTextSliderValues(e);
 
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 1.4, e = makeXonoticCheckBox(0, "hud_panel_physics_progressbar", _("Status bar")));
index f6f19135d1f7a257d001d4af567bd01d50d03adc..2a52bef91b8841e8f60e42a6f83e31f476e6363f 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDPhysicsDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDPhysicsDialog, title, string, _("Physics Panel"));
        ATTRIB(XonoticHUDPhysicsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDPhysicsDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15);
+       ATTRIB(XonoticHUDPhysicsDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDPhysicsDialog, columns, float, 4);
        ATTRIB(XonoticHUDPhysicsDialog, name, string, "HUDphysics");
        ATTRIB(XonoticHUDPhysicsDialog, sliderTopspeedTime, entity);
index 1b490d10272fdb3dc8bb28ee3d337b483afd751b..7e0ffae1a4137a46d20cccd1b96269d56349de6f 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDPowerupsDialog_fill(entity me)
        entity e;
        string panelname = "powerups";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticCheckBox(0, "hud_panel_powerups_progressbar", _("Enable status bar")));
index 7f67fa6007b6f2423dfd54158ead5a20f038f36d..c82f98278095b5aed91d1501e59657be65aa3b64 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDPowerupsDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDPowerupsDialog, title, string, _("Powerups Panel"));
        ATTRIB(XonoticHUDPowerupsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDPowerupsDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDPowerupsDialog, rows, float, 14);
+       ATTRIB(XonoticHUDPowerupsDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDPowerupsDialog, columns, float, 4);
        ATTRIB(XonoticHUDPowerupsDialog, name, string, "HUDpowerups");
        ATTRIB(XonoticHUDPowerupsDialog, requiresConnection, float, true);
index 4e24ff998eeb67f2b0351d999056784898dfc7af..30d95721090c17406c900b865d8ccab8d7bac3d6 100644 (file)
@@ -11,12 +11,12 @@ void XonoticHUDPressedKeysDialog_fill(entity me)
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_pressedkeys"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled when spectating"), "1");
-                       e.addValue(e, _("Panel always enabled"), "2");
+                       e.addValue(e, ("Disable"), "0");
+                       e.addValue(e, ("Enable when spectating"), "1");
+                       e.addValue(e, ("Always enable"), "2");
                        e.configureXonoticTextSliderValues(e);
 
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TDempty(me, 0.2);
index cc82959e6443af3c3ffc594da63504f66cf399dd..46452c696dfa76469fa3fe3b3ccd2b1dec78ed56 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDPressedKeysDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDPressedKeysDialog, title, string, _("Pressed Keys Panel"));
        ATTRIB(XonoticHUDPressedKeysDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDPressedKeysDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15);
+       ATTRIB(XonoticHUDPressedKeysDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDPressedKeysDialog, columns, float, 4);
        ATTRIB(XonoticHUDPressedKeysDialog, name, string, "HUDpressedkeys");
        ATTRIB(XonoticHUDPressedKeysDialog, requiresConnection, float, true);
index 4012bc61ac13b64975a57ff9c47e8bf356432af6..128951c0c8acfbde8bc5d33e84af28d49ca74776 100644 (file)
@@ -9,7 +9,10 @@ void XonoticHUDQuickMenuDialog_fill(entity me)
        entity e;
        string panelname = "quickmenu";
 
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+       // this panel has no main cvar
+       //dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Text alignment:")));
index 16f93c13d584579397f754ca3a78ec9dcdba7de4..ac6693a648155fe71a93257c7f7cc42d36ce583c 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDQuickMenuDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDQuickMenuDialog, title, string, _("Quick Menu Panel"));
        ATTRIB(XonoticHUDQuickMenuDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDQuickMenuDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDQuickMenuDialog, rows, float, 15);
+       ATTRIB(XonoticHUDQuickMenuDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDQuickMenuDialog, columns, float, 4);
        ATTRIB(XonoticHUDQuickMenuDialog, name, string, "HUDquickmenu");
 ENDCLASS(XonoticHUDQuickMenuDialog)
index 2673e546039a5afc5fb86d72e25e78193f1ce201..dec6fe364493c2edd26828edd9ae626caee1e898 100644 (file)
@@ -4,8 +4,10 @@
 
 void XonoticHUDRaceTimerDialog_fill(entity me)
 {
-       entity e;
+       //entity e;
        string panelname = "racetimer";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 }
index 7c814e3823e3586d7a2c9d14edb9a2a688f67cd0..81a8f005341aa3c5be0c3b4549ecc39710a6ce56 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDRaceTimerDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDRaceTimerDialog, title, string, _("Race Timer Panel"));
        ATTRIB(XonoticHUDRaceTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDRaceTimerDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15);
+       ATTRIB(XonoticHUDRaceTimerDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDRaceTimerDialog, columns, float, 4);
        ATTRIB(XonoticHUDRaceTimerDialog, name, string, "HUDracetimer");
        ATTRIB(XonoticHUDRaceTimerDialog, requiresConnection, float, true);
index de9ed6898b821e7df49781fcb2176c85fcd103a1..3e8db6686c09b79c96b6096eb6d9052a245b65b1 100644 (file)
@@ -12,12 +12,12 @@ void XonoticHUDRadarDialog_fill(entity me)
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextSlider("hud_panel_radar"));
-                       e.addValue(e, _("Panel disabled"), "0");
-                       e.addValue(e, _("Panel enabled in teamgames"), "1");
-                       e.addValue(e, _("Panel always enabled"), "2");
+                       e.addValue(e, _("Disable"), "0");
+                       e.addValue(e, _("Enable in team games"), "1");
+                       e.addValue(e, _("Always enable"), "2");
                        e.configureXonoticTextSliderValues(e);
 
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE();
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Radar:")));
index 04617b677f4c04a7444cf5de08444c1c67532f25..d02f5cd59298fe3b45bba6ca0aefd81f0c8c6d06 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDRadarDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDRadarDialog, title, string, _("Radar Panel"));
        ATTRIB(XonoticHUDRadarDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDRadarDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDRadarDialog, rows, float, 15);
+       ATTRIB(XonoticHUDRadarDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDRadarDialog, columns, float, 4);
        ATTRIB(XonoticHUDRadarDialog, name, string, "HUDradar");
        ATTRIB(XonoticHUDRadarDialog, requiresConnection, float, true);
index f04ca30da9397f358055366fa8bb726398847078..afb97e5fd42de9a8fed0ce82d6352bb22a9fddd9 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDScoreDialog_fill(entity me)
        entity e;
        string panelname = "score";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Score:")));
index d97787404e921121ce3453be7f8a42bfd1a940fb..20fa6cf967f86aa1a26a4644f32aaf4ae652e2a3 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDScoreDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDScoreDialog, title, string, _("Score Panel"));
        ATTRIB(XonoticHUDScoreDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDScoreDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDScoreDialog, rows, float, 15);
+       ATTRIB(XonoticHUDScoreDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDScoreDialog, columns, float, 4);
        ATTRIB(XonoticHUDScoreDialog, name, string, "HUDscore");
        ATTRIB(XonoticHUDScoreDialog, requiresConnection, float, true);
index dd9a7b8788923f0a5f424e9e76c6655ce248c226..84c6d862dbebb8a4644e2546516a9d9b70a71de1 100644 (file)
@@ -8,7 +8,9 @@ void XonoticHUDTimerDialog_fill(entity me)
        entity e;
        string panelname = "timer";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 4, e = makeXonoticTextLabel(0, _("Timer:")));
index 61955495edd4c7ac985ee989c39fe2d23b27cf3c..dac91cc2a67a57ec9fe1e79f9568a98857179931 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDTimerDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDTimerDialog, title, string, _("Timer Panel"));
        ATTRIB(XonoticHUDTimerDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDTimerDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDTimerDialog, rows, float, 15);
+       ATTRIB(XonoticHUDTimerDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDTimerDialog, columns, float, 4);
        ATTRIB(XonoticHUDTimerDialog, name, string, "HUDtimer");
        ATTRIB(XonoticHUDTimerDialog, requiresConnection, float, true);
index e8afa7ca706b91a71b050c9af2c12de684924bf4..39c9a69f707a0465aee72da99363c2c5123ae72c 100644 (file)
@@ -9,7 +9,9 @@ void XonoticHUDVoteDialog_fill(entity me)
        entity e;
        string panelname = "vote";
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Alpha after voting:")));
index 061c69e56c4797b3d904739b0adcedfe97d79bba..b07b189e5b81d031ccd8069a053e117eec7271d5 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDVoteDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDVoteDialog, title, string, _("Vote Panel"));
        ATTRIB(XonoticHUDVoteDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDVoteDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDVoteDialog, rows, float, 15);
+       ATTRIB(XonoticHUDVoteDialog, rows, float, 15.5);
        ATTRIB(XonoticHUDVoteDialog, columns, float, 4);
        ATTRIB(XonoticHUDVoteDialog, name, string, "HUDvote");
        ATTRIB(XonoticHUDVoteDialog, requiresConnection, float, true);
index 61339b6b938cc54800e1326bba256b00d08488a4..116b8ae2f06798a47e1854b5306c6eb58130acf9 100644 (file)
@@ -13,7 +13,9 @@ void XonoticHUDWeaponsDialog_fill(entity me)
        string panelname = "weapons";
        float i;
 
-       DIALOG_HUDPANEL_COMMON();
+       dialog_hudpanel_main_checkbox(me, panelname);
+
+       dialog_hudpanel_main_settings(me, panelname);
 
        me.TR(me);
                me.TDempty(me, 0.2);
index fad14749e6f4665f00b4c460c238a018811d0f37..4f877d4d3f3419e444f0fbbab65c7bbde913d970 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticHUDWeaponsDialog, XonoticRootDialog)
        ATTRIB(XonoticHUDWeaponsDialog, title, string, _("Weapons Panel"));
        ATTRIB(XonoticHUDWeaponsDialog, color, vector, SKINCOLOR_DIALOG_TEAMSELECT);
        ATTRIB(XonoticHUDWeaponsDialog, intendedWidth, float, 0.4);
-       ATTRIB(XonoticHUDWeaponsDialog, rows, float, 21);
+       ATTRIB(XonoticHUDWeaponsDialog, rows, float, 21.5);
        ATTRIB(XonoticHUDWeaponsDialog, columns, float, 4);
        ATTRIB(XonoticHUDWeaponsDialog, name, string, "HUDweapons");
        ATTRIB(XonoticHUDWeaponsDialog, requiresConnection, float, true);
index 481914200a99f625338e4be2466d158a1e5bcd34..2a2144598bbfecd56097c0a8efea20b4918228fd 100644 (file)
@@ -27,16 +27,8 @@ void GameType_ConfigureSliders(entity me, string pLabel, float pMin, float pMax,
        // clear old values
        for(i = 0; i < e.nValues; ++i);
        {
-               if(e.(valueStrings[i]))
-               {
-                       strunzone(e.(valueStrings[i]));
-                       e.(valueStrings[i]) = string_null;
-               }
-               if(e.(valueIdentifiers[i]))
-               {
-                       strunzone(e.(valueIdentifiers[i]));
-                       e.(valueIdentifiers[i]) = string_null;
-               }
+               strfree(e.(valueStrings[i]));
+               strfree(e.(valueIdentifiers[i]));
        }
        e.clearValues(e);
 
index 2f2ab901a84239a9c37c21866552b449f7089ed6..87ffadf3831d8015641eb7b3b9e50e7d8e95ecc7 100644 (file)
@@ -12,19 +12,11 @@ void XonoticMapInfoDialog_loadMapInfo(entity me, int i, entity mlb)
        me.startButton.onClickEntity = mlb;
        MapInfo_Get_ByID(i);
 
-       if(me.currentMapBSPName)
-       {
-               strunzone(me.currentMapBSPName);
-               strunzone(me.currentMapTitle);
-               strunzone(me.currentMapAuthor);
-               strunzone(me.currentMapDescription);
-               strunzone(me.currentMapPreviewImage);
-       }
-       me.currentMapBSPName = strzone(MapInfo_Map_bspname);
-       me.currentMapTitle = strzone(strdecolorize(MapInfo_Map_title));
-       me.currentMapAuthor = strzone(strdecolorize(MapInfo_Map_author));
-       me.currentMapDescription = strzone(MapInfo_Map_description);
-       me.currentMapPreviewImage = strzone(strcat("/maps/", MapInfo_Map_bspname));
+       strcpy(me.currentMapBSPName, MapInfo_Map_bspname);
+       strcpy(me.currentMapTitle, strdecolorize(MapInfo_Map_title));
+       strcpy(me.currentMapAuthor, strdecolorize(MapInfo_Map_author));
+       strcpy(me.currentMapDescription, MapInfo_Map_description);
+       strcpy(me.currentMapPreviewImage, strcat("/maps/", MapInfo_Map_bspname));
 
        me.frame.setText(me.frame, me.currentMapBSPName);
        me.titleLabel.setText(me.titleLabel, me.currentMapTitle);
index 0ea24a8891931157853a55fe461888271abd5947..994c5a7c95cc3f44ff03e6e842aad3ff864a7f2c 100644 (file)
@@ -20,7 +20,7 @@ string weaponarenastring_cvar;
 string WeaponArenaString()
 {
        string s;
-       float n, i;
+       float n;
        s = cvar_string("g_weaponarena");
        if(s == "0")
                return "";
@@ -30,81 +30,80 @@ string WeaponArenaString()
                return _("Most Weapons Arena");
        if(s == weaponarenastring_cvar)
                return weaponarenastring;
-       if(weaponarenastring)
-               strunzone(weaponarenastring);
-       if(weaponarenastring_cvar)
-               strunzone(weaponarenastring_cvar);
 
-       weaponarenastring_cvar = strzone(s);
+       strcpy(weaponarenastring_cvar, s);
 
        n = tokenize_console(s);
        s = "";
-       for(i = 0; i < n; ++i)
+       for(int j = 0; j < n; ++j)
        {
                FOREACH(Weapons, it != WEP_Null, {
-                       if(argv(i) == it.netname)
-                               s = strcat(s, " & ", it.m_name);
+                       if(argv(j) == it.netname)
+                               s = cons_mid(s, " & ", it.m_name);
                });
        }
-       s = sprintf(_("%s Arena"), substring(s, 3, strlen(s) - 3));
+       s = sprintf(_("%s Arena"), s);
 
-       weaponarenastring = strzone(s);
+       strcpy(weaponarenastring, s);
 
        return weaponarenastring;
 }
 
 string XonoticMutatorsDialog_toString(entity me)
 {
-       string s;
-       s = "";
+       string s = "";
        if(cvar("g_dodging"))
-               s = strcat(s, ", ", _("Dodging"));
+               s = cons_mid(s, ", ", _("Dodging"));
        if(cvar("g_instagib"))
-               s = strcat(s, ", ", _("InstaGib"));
+               s = cons_mid(s, ", ", _("InstaGib"));
        if(cvar("g_new_toys"))
-               s = strcat(s, ", ", _("New Toys"));
+               s = cons_mid(s, ", ", _("New Toys"));
        if(cvar("g_nix"))
-               s = strcat(s, ", ", _("NIX"));
+               s = cons_mid(s, ", ", _("NIX"));
        if(cvar("g_rocket_flying"))
-               s = strcat(s, ", ", _("Rocket Flying"));
+               s = cons_mid(s, ", ", _("Rocket Flying"));
        if(cvar("g_invincible_projectiles"))
-               s = strcat(s, ", ", _("Invincible Projectiles"));
+               s = cons_mid(s, ", ", _("Invincible Projectiles"));
        if(cvar_string("g_weaponarena") != "0")
-               s = strcat(s, ", ", WeaponArenaString());
+               s = cons_mid(s, ", ", WeaponArenaString());
        else if(cvar("g_balance_blaster_weaponstartoverride") == 0)
-               s = strcat(s, ", ", _("No start weapons"));
+               s = cons_mid(s, ", ", _("No start weapons"));
        if(cvar("sv_gravity") < stof(cvar_defstring("sv_gravity")))
-               s = strcat(s, ", ", _("Low gravity"));
+               s = cons_mid(s, ", ", _("Low gravity"));
        if(cvar("g_cloaked"))
-               s = strcat(s, ", ", _("Cloaked"));
+               s = cons_mid(s, ", ", _("Cloaked"));
        if(cvar("g_grappling_hook"))
-               s = strcat(s, ", ", _("Hook"));
+               s = cons_mid(s, ", ", _("Hook"));
        if(cvar("g_midair"))
-               s = strcat(s, ", ", _("Midair"));
+               s = cons_mid(s, ", ", _("Midair"));
+       if(cvar("g_melee_only"))
+               s = cons_mid(s, ", ", _("Melee only"));
        if(cvar("g_vampire"))
-               s = strcat(s, ", ", _("Vampire"));
+               s = cons_mid(s, ", ", _("Vampire"));
        if(cvar("g_pinata"))
-               s = strcat(s, ", ", _("Piñata"));
+               s = cons_mid(s, ", ", _("Piñata"));
        if(cvar("g_weapon_stay"))
-               s = strcat(s, ", ", _("Weapons stay"));
+               s = cons_mid(s, ", ", _("Weapons stay"));
        if(cvar("g_bloodloss") > 0)
-               s = strcat(s, ", ", _("Blood loss"));
+               s = cons_mid(s, ", ", _("Blood loss"));
        if(cvar("g_jetpack"))
-               s = strcat(s, ", ", _("Jet pack"));
+               s = cons_mid(s, ", ", _("Jet pack"));
        if(cvar("g_buffs") > 0)
-               s = strcat(s, ", ", _("Buffs"));
+               s = cons_mid(s, ", ", _("Buffs"));
        if(cvar("g_overkill"))
-               s = strcat(s, ", ", _("Overkill"));
+               s = cons_mid(s, ", ", _("Overkill"));
        if(cvar("g_powerups") == 0)
-               s = strcat(s, ", ", _("No powerups"));
+               s = cons_mid(s, ", ", _("No powerups"));
        if(cvar("g_powerups") > 0)
-               s = strcat(s, ", ", _("Powerups"));
+               s = cons_mid(s, ", ", _("Powerups"));
        if(cvar("g_touchexplode") > 0)
-               s = strcat(s, ", ", _("Touch explode"));
+               s = cons_mid(s, ", ", _("Touch explode"));
+       if(cvar("g_walljump"))
+               s = cons_mid(s, ", ", _("Wall jumping"));
        if(s == "")
                return ZCTX(_("MUT^None"));
        else
-               return substring(s, 2, strlen(s) - 2);
+               return s;
 }
 
 float checkCompatibility_pinata(entity me)
@@ -113,6 +112,10 @@ float checkCompatibility_pinata(entity me)
                return 0;
        if(cvar("g_nix"))
                return 0;
+       if(cvar("g_overkill"))
+               return 0;
+       if(cvar("g_melee_only"))
+               return 0;
        if(cvar_string("g_weaponarena") != "0")
                return 0;
        return 1;
@@ -168,10 +171,11 @@ void XonoticMutatorsDialog_fill(entity me)
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox(0, "g_buffs", _("Buffs")));
+                       e.cvarOffValue = "-1"; // TODO: make this a radio button?
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_midair", _("Midair"),
-                       _("Only possible to inflict damage on your enemy while he's airborne")));
+                       _("Only possible to inflict damage on your enemy while they're airborne")));
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_vampire", _("Vampire"),
@@ -233,32 +237,40 @@ void XonoticMutatorsDialog_fill(entity me)
 
        me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
+       string weaponarena_tooltip = strzone(_("Players will be given a set of weapons at spawn as well as unlimited ammo, without weapon pickups"));
        me.TR(me);
-               me.TD(me, 1, 2, e = makeXonoticRadioButton_T(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:"),
-                       _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+               me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon arenas:")));
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "menu_weaponarena", _("Custom weapons"), weaponarena_tooltip));
                        e.cvarValueIsAnotherCvar = true;
                        e.cvarOffValue = "0";
+
+               me.TDempty(me, 0.1); // fix initial position
        for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
        {
                w = Weapons_from(i);
                if(w.spawnflags & WEP_FLAG_HIDDEN)
                        continue;
                if((j & 1) == 0)
+                       me.TDempty(me, 0.2);
+               else
+               {
                        me.TR(me);
-               me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
+                       me.TDempty(me, 0.4);
+               }
+               me.TD(me, 1, 1.7, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
                        setDependentWeird(e, checkCompatibility_weaponarena_weapon);
                ++j;
        }
+
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "most", _("Most weapons"),
-                       _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "most", _("Most weapons"), weaponarena_tooltip));
                        e.cvarOffValue = "0";
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "all", _("All weapons"),
-                       _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+               me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "all", _("All weapons"), weaponarena_tooltip));
                        e.cvarOffValue = "0";
        me.TR(me);
                me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Special arenas:")));
index a34d0d80a1cb12a9e713efb213d147b5f272226d..1792ec635b41f1e594e3be4fbf6b455980f9d204 100644 (file)
@@ -5,6 +5,7 @@
 #include "textlabel.qh"
 #include "inputbox.qh"
 #include "checkbox.qh"
+#include "commandbutton.qh"
 #include "button.qh"
 
 entity makeXonoticServerListTab()
@@ -81,7 +82,10 @@ void XonoticServerListTab_fill(entity me)
                        e.onClickEntity = slist;
                        slist.infoButton = e;
        me.TR(me);
-               me.TD(me, 1, me.columns, e = makeXonoticButton(_("Join!"), '0 0 0'));
+               me.TD(me, 1, 1, e = makeXonoticCommandButton_T(_("Disconnect"), '0 0 0', "disconnect", 0,
+                       _("Disconnect from the server")));
+                       slist.disconnectButton = e;
+               me.TD(me, 1, me.columns-1, e = makeXonoticButton(_("Join!"), '0 0 0'));
                        e.onClick = ServerList_Connect_Click;
                        e.onClickEntity = slist;
                        slist.connectButton = e;
index baeb9a51bcbf127d14f8dc89acb36b6814ab5901..5745ce072e044940ddadd3d2e19dd41875e65dbb 100644 (file)
@@ -16,61 +16,21 @@ void XonoticServerInfoDialog_loadServerInfo(entity me, float i)
        // ====================================
        //  First clear and unzone the strings
        // ====================================
-       if(me.currentServerName)
-               strunzone(me.currentServerName);
-       me.currentServerName = string_null;
-
-       if(me.currentServerCName)
-               strunzone(me.currentServerCName);
-       me.currentServerCName = string_null;
-
-       if(me.currentServerType)
-               strunzone(me.currentServerType);
-       me.currentServerType = string_null;
-
-       if(me.currentServerMap)
-               strunzone(me.currentServerMap);
-       me.currentServerMap = string_null;
-
-       if(me.currentServerPlayers)
-               strunzone(me.currentServerPlayers);
-       me.currentServerPlayers = string_null;
-
-       if(me.currentServerNumPlayers)
-               strunzone(me.currentServerNumPlayers);
-       me.currentServerNumPlayers = string_null;
-
-       if(me.currentServerNumBots)
-               strunzone(me.currentServerNumBots);
-       me.currentServerNumBots = string_null;
-
-       if(me.currentServerNumFreeSlots)
-               strunzone(me.currentServerNumFreeSlots);
-       me.currentServerNumFreeSlots = string_null;
-
-       if(me.currentServerMod)
-               strunzone(me.currentServerMod);
-       me.currentServerMod = string_null;
-
-       if(me.currentServerVersion)
-               strunzone(me.currentServerVersion);
-       me.currentServerVersion = string_null;
-
+       strfree(me.currentServerName);
+       strfree(me.currentServerCName);
+       strfree(me.currentServerType);
+       strfree(me.currentServerMap);
+       strfree(me.currentServerPlayers);
+       strfree(me.currentServerNumPlayers);
+       strfree(me.currentServerNumBots);
+       strfree(me.currentServerNumFreeSlots);
+       strfree(me.currentServerMod);
+       strfree(me.currentServerVersion);
        // not zoned!
-       //if(me.currentServerEncrypt)
-       //      strunzone(me.currentServerEncrypt);
-       //me.currentServerEncrypt = string_null;
-       if(me.currentServerPure)
-               strunzone(me.currentServerPure);
-       me.currentServerPure = string_null;
-
-       if(me.currentServerKey)
-               strunzone(me.currentServerKey);
-       me.currentServerKey = string_null;
-
-       if(me.currentServerID)
-               strunzone(me.currentServerID);
-       me.currentServerID = string_null;
+       //      strfree(me.currentServerEncrypt);
+       strfree(me.currentServerPure);
+       strfree(me.currentServerKey);
+       strfree(me.currentServerID);
 
        // ==========================
        //  Now, fill in the strings
index 1229be714491116f7348641b47f7d31fd2310126..afde0914a48b981db347492f8db456e31ae4da64 100644 (file)
@@ -19,9 +19,7 @@ void XonoticScreenshotBrowserTab_loadPreviewScreenshot(entity me, string scrImag
 {
        if (me.currentScrPath == scrImage)
                return;
-       if (me.currentScrPath)
-               strunzone(me.currentScrPath);
-       me.currentScrPath = strzone(scrImage);
+       strcpy(me.currentScrPath, scrImage);
        me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
 }
 void XonoticScreenshotBrowserTab_fill(entity me)
index d6d545eeeaf00b939ce5b8ad35b6243bd8e66868..57dd75679e03b3d272432dbe79088261220e4c87 100644 (file)
@@ -24,9 +24,7 @@ void XonoticScreenshotViewerDialog_loadScreenshot(entity me, string scrImage)
 
        if (me.currentScrPath == scrImage)
                return;
-       if (me.currentScrPath)
-               strunzone(me.currentScrPath);
-       me.currentScrPath = strzone(scrImage);
+       strcpy(me.currentScrPath, scrImage);
        me.screenshotImage.load(me.screenshotImage, me.currentScrPath);
        me.frame.setText(me.frame, me.screenshotImage.screenshotTitle);
 }
index 66c96046d88e9e4a2b156b2ed2d149188613ab22..d97d7131a473b36c0a46e8935b1efba6078c51d9 100644 (file)
@@ -188,19 +188,15 @@ void HUDSkinList_Refresh_Click(entity btn, entity me)
 
 void HUDSkinList_SavedName_Change(entity box, entity me)
 {
-       if(me.savedName)
-               strunzone(me.savedName);
+       strfree(me.savedName);
 
        if(box.text != "")
                me.savedName = strzone(box.text);
-       else
-               me.savedName = string_null;
 }
 
 void HUDSkinList_Filter_Change(entity box, entity me)
 {
-       if(me.filterString)
-               strunzone(me.filterString);
+       strfree(me.filterString);
 
        if(box.text != "")
        {
@@ -209,8 +205,6 @@ void HUDSkinList_Filter_Change(entity box, entity me)
                else
                        me.filterString = strzone(strcat("*", box.text, "*"));
        }
-       else
-               me.filterString = string_null;
 
        me.getHUDSkins(me);
 }
index 1f28a1bdfede23aa181f110ca297596457a85976..cde80d693d422a6a44b1664cd06f29fa7ceee87d 100644 (file)
@@ -246,12 +246,8 @@ void XonoticKeyBinder_destroy(entity me)
 
        for(int i = 0; i < MAX_KEYBINDS; ++i)
        {
-               if(Xonotic_KeyBinds_Functions[i])
-                       strunzone(Xonotic_KeyBinds_Functions[i]);
-               Xonotic_KeyBinds_Functions[i] = string_null;
-               if(Xonotic_KeyBinds_Descriptions[i])
-                       strunzone(Xonotic_KeyBinds_Descriptions[i]);
-               Xonotic_KeyBinds_Descriptions[i] = string_null;
+               strfree(Xonotic_KeyBinds_Functions[i]);
+               strfree(Xonotic_KeyBinds_Descriptions[i]);
        }
        Xonotic_KeyBinds_Count = 0;
 }
index 0afd27c8d67ee5802309671cc895bf37f3dd34fa..110b796be61d09ce0375b4827ec663fc1707e773 100644 (file)
@@ -1,6 +1,6 @@
 #include "mainwindow.qh"
 
-#include "../mutators/events.qh"
+#include <menu/mutators/_mod.qh>
 
 #include "nexposee.qh"
 #include "inputbox.qh"
index 111744e9668da9e0b3909f7c97e15c8f01062e72..73ef8a32ae8cfd738852859b0ccb47fa5bf6bbd0 100644 (file)
@@ -181,8 +181,6 @@ void XonoticMapList_refilter(entity me)
 
        for(i = 0; i < MapInfo_count; ++i)
                draw_PreloadPicture(strcat("/maps/", MapInfo_BSPName_ByID(i)));
-       if(me.g_maplistCache)
-               strunzone(me.g_maplistCache);
        s = "0";
        for(i = 1; i < MapInfo_count; i *= 2)
                s = strcat(s, s);
@@ -201,7 +199,7 @@ void XonoticMapList_refilter(entity me)
                                );
                }
        }
-       me.g_maplistCache = strzone(s);
+       strcpy(me.g_maplistCache, s);
        if(gt != me.lastGametype || f != me.lastFeatures)
        {
                me.lastGametype = gt;
@@ -217,12 +215,9 @@ void XonoticMapList_refilterCallback(entity me, entity cb)
 
 void MapList_StringFilterBox_Change(entity box, entity me)
 {
-       if(me.stringFilter)
-               strunzone(me.stringFilter);
+       strfree(me.stringFilter);
        if(box.text != "")
                me.stringFilter = strzone(box.text);
-       else
-               me.stringFilter = string_null;
 
        me.refilter(me);
 }
@@ -345,9 +340,7 @@ float XonoticMapList_keyDown(entity me, float scan, float ascii, float shift)
                if(time < me.typeToSearchTime)
                {
                        save = substring(me.typeToSearchString, 0, strlen(me.typeToSearchString) - 1);
-                       if(me.typeToSearchString)
-                               strunzone(me.typeToSearchString);
-                       me.typeToSearchString = strzone(save);
+                       strcpy(me.typeToSearchString, save);
                        me.typeToSearchTime = time + 0.5;
                        if(strlen(me.typeToSearchString))
                        {
@@ -364,9 +357,7 @@ float XonoticMapList_keyDown(entity me, float scan, float ascii, float shift)
                        save = ch;
                else
                        save = strcat(me.typeToSearchString, ch);
-               if(me.typeToSearchString)
-                       strunzone(me.typeToSearchString);
-               me.typeToSearchString = strzone(save);
+               strcpy(me.typeToSearchString, save);
                me.typeToSearchTime = time + 0.5;
                MapInfo_FindName(me.typeToSearchString);
                if(MapInfo_FindName_firstResult >= 0)
index c679d4449d7177598dc649228f7e4cc96b11be76..1ad651bdb5a5824deef0e972601fd469fadb7fb4 100644 (file)
@@ -113,21 +113,12 @@ void XonoticPlayerModelSelector_go(entity me, float d)
 {
        me.idxModels = mod(me.idxModels + d + me.numModels, me.numModels);
 
-       if(me.currentModel)
-               strunzone(me.currentModel);
-       if(me.currentModelTitle)
-               strunzone(me.currentModelTitle);
-       if(me.currentModelImage)
-               strunzone(me.currentModelImage);
-       if(me.currentModelDescription)
-               strunzone(me.currentModelDescription);
-
        // select model #i!
-       me.currentModelTitle = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_TITLE));
-       me.currentModelImage = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_IMAGE));
+       strcpy(me.currentModelTitle, bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_TITLE));
+       strcpy(me.currentModelImage, bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_IMAGE));
        me.currentSkin = stof(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_SKIN));
-       me.currentModel = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_MODEL));
-       me.currentModelDescription = strzone(bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_DESC));
+       strcpy(me.currentModel, bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_MODEL));
+       strcpy(me.currentModelDescription, bufstr_get(me.bufModels, BUFMODELS_COUNT*me.idxModels+BUFMODELS_DESC));
 
        // fix the image
        if(draw_PictureSize(me.currentModelImage) == '0 0 0')
index 8e8f3ccf738bd4f32de72be843b87510b558d8d8..af987e7b58c9ab78491ef7829a8e57a1885842f5 100644 (file)
@@ -19,9 +19,7 @@ void XonoticScreenshotImage_load(entity me, string theImage)
 {
        me.screenshotTime = time;
        me.src = theImage;
-       if (me.screenshotTitle)
-               strunzone(me.screenshotTitle);
-       me.screenshotTitle = strzone(substring(me.src, 13, strlen(theImage) - 13)); //strip "/screenshots/"
+       strcpy(me.screenshotTitle, substring(me.src, 13, strlen(theImage) - 13)); //strip "/screenshots/"
 
        me.initZoom(me); // this image may have a different size
        me.setZoom(me, 0, 0);
index a948ce86f842dfb79d7bf85c631835fcc6bf751b..de0adc793815796c0e175f32bf1e6e473b2709e1 100644 (file)
@@ -153,8 +153,7 @@ void ScreenshotList_Refresh_Click(entity btn, entity me)
 
 void ScreenshotList_Filter_Change(entity box, entity me)
 {
-       if(me.filterString)
-               strunzone(me.filterString);
+       strfree(me.filterString);
 
        if(box.text != "")
        {
@@ -163,8 +162,6 @@ void ScreenshotList_Filter_Change(entity box, entity me)
                else
                        me.filterString = strzone(strcat("*", box.text, "*"));
        }
-       else
-               me.filterString = string_null;
 
        ScreenshotList_Refresh_Click(NULL, me);
 }
index 5e6a567b6af907de399757b63a265675d265d340..eec56ca5fd56725c7106d0ba246f8f70396d104f 100644 (file)
@@ -37,8 +37,7 @@ void RegisterSLCategories()
                                } } \
                                if(catnum) \
                                { \
-                                       strunzone(categories[i].override_string); \
-                                       categories[i].override_string = string_null; \
+                                       strfree(categories[i].override_string); \
                                        categories[i].override_field = catnum; \
                                        continue; \
                                } \
@@ -51,8 +50,7 @@ void RegisterSLCategories()
                                        ); \
                                } \
                        } \
-                       strunzone(categories[i].override_string); \
-                       categories[i].override_string = string_null; \
+                       strfree(categories[i].override_string); \
                        categories[i].override_field = 0; \
                }
        PROCESS_OVERRIDE(cat_enoverride_string, cat_enoverride)
@@ -308,9 +306,7 @@ void XonoticServerList_setSelected(entity me, int i)
        if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
                return; // sorry, it would be wrong
 
-       if(me.selectedServer)
-               strunzone(me.selectedServer);
-       me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
+       strcpy(me.selectedServer, gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
 
        me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);
        me.ipAddressBox.cursorPos = strlen(me.selectedServer);
@@ -549,9 +545,10 @@ void XonoticServerList_draw(entity me)
        }
        else { me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT); }
 
-       me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
-       me.infoButton.disabled = ((me.nItems == 0) || !owned);
-       me.favoriteButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));
+       me.connectButton.disabled = (me.lockedSelectedItem || (me.nItems == 0 && me.ipAddressBox.text == ""));
+       me.disconnectButton.disabled = (!(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)));
+       me.infoButton.disabled = (me.lockedSelectedItem || me.nItems == 0 || !owned);
+       me.favoriteButton.disabled = (me.lockedSelectedItem || (me.nItems == 0 && me.ipAddressBox.text == ""));
 
        if(me.lockedSelectedItem)
        {
@@ -559,9 +556,7 @@ void XonoticServerList_draw(entity me)
                {
                        if(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem) != me.selectedServer)
                        {
-                               if(me.selectedServer)
-                                       strunzone(me.selectedServer);
-                               me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
+                               strcpy(me.selectedServer, gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
                        }
                        found = true;
                }
@@ -586,9 +581,7 @@ void XonoticServerList_draw(entity me)
                        // selected server disappeared, select the last server (scrolling to it)
                        if(me.selectedItem >= me.nItems)
                                SUPER(XonoticServerList).setSelected(me, me.nItems - 1);
-                       if(me.selectedServer)
-                               strunzone(me.selectedServer);
-                       me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
+                       strcpy(me.selectedServer, gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
                }
        }
 
@@ -666,12 +659,9 @@ void ServerList_TypeSort_Click(entity btn, entity me)
 }
 void ServerList_Filter_Change(entity box, entity me)
 {
-       if(me.filterString)
-               strunzone(me.filterString);
+       strfree(me.filterString);
        if(box.text != "")
                me.filterString = strzone(box.text);
-       else
-               me.filterString = string_null;
        me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
 
        me.ipAddressBox.setText(me.ipAddressBox, "");
@@ -717,9 +707,7 @@ void XonoticServerList_setSortOrder(entity me, int fld, int direction)
        me.sortButton4.forcePressed = 0;
        me.sortButton5.forcePressed = (fld == SLIST_FIELD_NUMHUMANS);
        me.selectedItem = 0;
-       if(me.selectedServer)
-               strunzone(me.selectedServer);
-       me.selectedServer = string_null;
+       strfree(me.selectedServer);
        me.refreshServerList(me, REFRESHSERVERLIST_REFILTER);
 }
 void XonoticServerList_positionSortButton(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
@@ -775,11 +763,10 @@ void XonoticServerList_resizeNotify(entity me, vector relOrigin, vector relSize,
 }
 void ServerList_Connect_Click(entity btn, entity me)
 {
-       localcmd(sprintf("connect %s\n",
-               ((me.ipAddressBox.text != "") ?
-                       me.ipAddressBox.text : me.selectedServer
-               )
-       ));
+       if (me.lockedSelectedItem)
+               return;
+       string sv = (me.ipAddressBox.text != "") ? me.ipAddressBox.text : me.selectedServer;
+       localcmd(sprintf("connect %s\n", sv));
 }
 void ServerList_Favorite_Click(entity btn, entity this)
 {
@@ -857,7 +844,7 @@ void XonoticServerList_drawListBoxItem(entity me, int i, vector absSize, bool is
                }
        }
 
-       if(isSelected)
+       if(isSelected && !me.lockedSelectedItem)
                draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
        else if(isFocused)
        {
index e45abfda33b528cce9e9e72035dd4ab1807d47c5..74f3bd570d5fee88efdcdbab3fbdaa341c2545a6 100644 (file)
@@ -30,7 +30,7 @@ CLASS(XonoticServerList, XonoticListBox)
        ATTRIB(XonoticServerList, columnTypeSize, float, 0);
        ATTRIB(XonoticServerList, columnPlayersOrigin, float, 0);
        ATTRIB(XonoticServerList, columnPlayersSize, float, 0);
-       ATTRIB(XonoticServerList, lockedSelectedItem, bool, true);      // initially keep selected the first item of the list, avoiding an unwanted scrolling
+       ATTRIB(XonoticServerList, lockedSelectedItem, bool, true); // initially keep selected the first item of the list to avoid unwanted scrolling
 
        ATTRIB(XonoticServerList, selectedServer, string); // to restore selected server when needed
        METHOD(XonoticServerList, setSelected, void(entity, float));
@@ -52,6 +52,7 @@ CLASS(XonoticServerList, XonoticListBox)
        ATTRIB(XonoticServerList, sortButton4, entity);
        ATTRIB(XonoticServerList, sortButton5, entity);
        ATTRIB(XonoticServerList, connectButton, entity);
+       ATTRIB(XonoticServerList, disconnectButton, entity);
        ATTRIB(XonoticServerList, infoButton, entity);
        ATTRIB(XonoticServerList, currentSortOrder, float, 0);
        ATTRIB(XonoticServerList, currentSortField, float, -1);
index 13e6ba34c03395f74fbe2f7f6fccfa3c26fd16f6..6d77e1adf929c1e94f2aa964c7edb7bff88837da 100644 (file)
@@ -104,13 +104,10 @@ void SoundList_Menu_Track_Reset(entity box, entity me)
 
 void SoundList_Filter_Change(entity box, entity me)
 {
-       if(me.filterString)
-               strunzone(me.filterString);
+       strfree(me.filterString);
 
        if(box.text != "")
                me.filterString = strzone(box.text);
-       else
-               me.filterString = string_null;
 
        me.getSounds(me);
 }
index 3f9dc410b3c53ceb17b0e931997ab3ca6b30a837..401a6eadda0026b5f7e2b6533c40352c597961ea 100644 (file)
@@ -100,7 +100,7 @@ void XonoticStatsList_getStats(entity me)
                        case "overall/last_seen_dt":
                        {
                                order = 1;
-                               outstr = _("Last seen:");
+                               outstr = _("Last match:");
                                data = XonoticStatsList_convertDate(car(data));
                                break;
                        }
index 7b381b544588ae4d9049d972ad0d74d44c7c9a23..fb4bb92a80b5421e80d65ef05d2cd178c04ef6e7 100644 (file)
@@ -1,4 +1,5 @@
 #include "util.qh"
+#include "dialog.qh"
 
 #include "../item.qh"
 
@@ -266,8 +267,7 @@ void setZonedTooltip(entity e, string theTooltip, string theCvar)
                theTooltip = string_null;
        }
 
-       if(e.tooltip)
-               strunzone(e.tooltip);
+       strfree(e.tooltip);
        e.tooltip = (theTooltip != "") ? strzone(theTooltip) : string_null;
 }
 
@@ -458,21 +458,18 @@ void UpdateNotification_URI_Get_Callback(float id, float status, string data)
 
 void updateCheck()
 {
-       if(cvar("menu_updatecheck"))
+       if(!_Nex_ExtResponseSystem_Queried)
        {
-               if(!_Nex_ExtResponseSystem_Queried)
-               {
-                       _Nex_ExtResponseSystem_Queried = 1;
-                       float startcnt;
-                       string uri;
+               _Nex_ExtResponseSystem_Queried = 1;
+               float startcnt;
+               string uri;
 
-                       cvar_set("cl_startcount", ftos(startcnt = cvar("cl_startcount") + 1));
+               cvar_set("cl_startcount", ftos(startcnt = cvar("cl_startcount") + 1));
 
-                       // for privacy, munge the start count a little
-                       startcnt = floor((floor(startcnt / 10) + random()) * 10);
-                       uri = sprintf("http://update.xonotic.org/checkupdate.txt?version=%s&cnt=%d", uri_escape(cvar_string("g_xonoticversion")), startcnt);
-                       uri_get(uri, URI_GET_UPDATENOTIFICATION);
-               }
+               // for privacy, munge the start count a little
+               startcnt = floor((floor(startcnt / 10) + random()) * 10);
+               uri = sprintf("http://update.xonotic.org/checkupdate.txt?version=%s&cnt=%d", uri_escape(cvar_string("g_xonoticversion")), startcnt);
+               uri_get(uri, URI_GET_UPDATENOTIFICATION);
        }
 
        if(_Nex_ExtResponseSystem_PacksStep > 0)
@@ -565,7 +562,7 @@ void preMenuDraw()
 
        updateCheck();
 
-       if(_Nex_ExtResponseSystem_UpdateTo != "")
+       if(_Nex_ExtResponseSystem_UpdateTo != "" && !(gamestatus & (GAME_CONNECTED | GAME_ISSERVER)))
        {
                // TODO rather turn this into a dialog
                fs = ((1/draw_scale.x) * eX + (1/draw_scale.y) * eY) * 12;
@@ -611,8 +608,7 @@ void preMenuDraw()
        }
        else
        {
-               strunzone(campaign_name_previous);
-               campaign_name_previous = strzone(campaign_name);
+               strcpy(campaign_name_previous, campaign_name);
                campaign_won_previous = cvar(strcat("g_campaign", campaign_name, "_won"));
        }
 }
@@ -749,6 +745,7 @@ string GameType_GetIcon(int cnt)
 .void(entity) TR;
 .void(entity, float, float, entity) TD;
 .void(entity, float) TDempty;
+.void(entity, float, float) gotoRC;
 entity makeXonoticTextLabel(float theAlign, string theText);
 entity makeXonoticTextSlider(string);
 .void(entity, string, string) addValue;
@@ -758,12 +755,21 @@ entity makeXonoticCheckBoxString(string, string, string, string);
 entity makeXonoticCheckBox(float, string, string);
 .bool sendCvars;
 
-void dialog_hudpanel_common_notoggle(entity me, string panelname)
+void dialog_hudpanel_main_checkbox(entity me, string panelname)
 {
-       float i;
        entity e;
 
        me.TR(me);
+               me.TDempty(me, 1.5);
+               me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, strzone(strcat("hud_panel_", panelname)), _("Enable")));
+}
+
+void dialog_hudpanel_main_settings(entity me, string panelname)
+{
+       float i;
+       entity e;
+
+       me.gotoRC(me, me.currentRow + 1.5, 0);
                me.TD(me, 1, 1.4, e = makeXonoticTextLabel(0, _("Background:")));
                        me.TD(me, 1, 2.6, e = makeXonoticTextSlider(strzone(strcat("hud_panel_", panelname, "_bg"))));
                                e.addValue(e, _("Default"), "");
index 96fef2ad4006f553a3bd8a5b22dd594b684df5c3..f5bd636d81f98c1b481b0919776ed2051d5fddaf 100644 (file)
@@ -36,13 +36,8 @@ string GameType_GetIcon(int cnt);
 int GameType_GetCount();
 int GameType_GetTotalCount();
 
-void dialog_hudpanel_common_notoggle(entity me, string panelname);
-#define DIALOG_HUDPANEL_COMMON_NOTOGGLE() \
-       dialog_hudpanel_common_notoggle(me, panelname)
-#define DIALOG_HUDPANEL_COMMON() \
-       me.TR(me); \
-               me.TD(me, 1, 4, e = makeXonoticCheckBox(0, strzone(strcat("hud_panel_", panelname)), _("Enable panel"))); \
-       DIALOG_HUDPANEL_COMMON_NOTOGGLE()
+void dialog_hudpanel_main_checkbox(entity me, string panelname);
+void dialog_hudpanel_main_settings(entity me, string panelname);
 
 float getFadedAlpha(float currentAlpha, float startAlpha, float targetAlpha);
 
index fd4f51385bb898cf74fd498b1bc13b3673c02805..695b2d7873144974af98443e14ca3f36dd680141 100644 (file)
@@ -21,9 +21,8 @@ void XonoticWeaponarenaCheckBox_setChecked(entity me, float foo)
 }
 void XonoticWeaponarenaCheckBox_loadCvars(entity me)
 {
-       float n = tokenize_console(cvar_string("menu_weaponarena"));
-       float i;
-       for(i=0; i<n; ++i)
+       int n = tokenize_console(cvar_string("menu_weaponarena"));
+       for (int i = 0; i < n; i++)
        {
                if(argv(i) == me.netname)
                {
index 569301c5d65c369b60deb900f44be3bf1447c5bf..0e6ec096df5eff5bc988368e3f53340e86529afb 100644 (file)
@@ -6,9 +6,6 @@
 #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/handicap.qc>
 #include <server/impulse.qc>
index 2013fd6bb5db5c521737cf0985fc65c13a43846e..a897b456a6d97ad44a47c7c9be6cce4142d2088d 100644 (file)
@@ -6,9 +6,6 @@
 #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/handicap.qh>
 #include <server/impulse.qh>
index 4062f7f660df2d15dfb01ea48bdf822a81599995..c6e26e09e8fdbf77e641a6f9937e1ade5e60ac24 100644 (file)
@@ -5,6 +5,7 @@
     #include <server/defs.qh>
     #include <common/state.qh>
     #include <common/vehicles/all.qh>
+       #include <lib/warpzone/common.qh>
     #include "antilag.qh"
 #endif
 
@@ -146,3 +147,78 @@ void antilag_restore_all(entity ignore)
                antilag_restore(it, it);
        });
 }
+
+/*
+==================
+traceline_antilag
+
+A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
+Additionally it moves players back into the past before the trace and restores them afterward.
+==================
+*/
+void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
+{
+       // check whether antilagged traces are enabled
+       if (lag < 0.001)
+               lag = 0;
+       if (!IS_REAL_CLIENT(forent))
+               lag = 0; // only antilag for clients
+
+       // change shooter to SOLID_BBOX so the shot can hit corpses
+       int oldsolid = source.dphitcontentsmask;
+       if(source)
+               source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
+
+       if (lag)
+               antilag_takeback_all(forent, lag);
+
+       // do the trace
+       if(wz)
+               WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
+       else
+               tracebox (v1, mi, ma, v2, nomonst, forent);
+
+       // restore players to current positions
+       if (lag)
+               antilag_restore_all(forent);
+
+       // restore shooter solid type
+       if(source)
+               source.dphitcontentsmask = oldsolid;
+}
+void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
+{
+       tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
+}
+void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
+{
+       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
+       if (autocvar_g_antilag != 2 || noantilag)
+               lag = 0;
+       traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
+}
+void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
+{
+       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
+       if (autocvar_g_antilag != 2 || noantilag)
+               lag = 0;
+       tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
+}
+void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
+{
+       tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
+}
+void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
+{
+       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
+       if (autocvar_g_antilag != 2 || noantilag)
+               lag = 0;
+       WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
+}
+void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
+{
+       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
+       if (autocvar_g_antilag != 2 || noantilag)
+               lag = 0;
+       tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
+}
index d57762ccd3899ef8588a560229b39e25ac89210e..c3be5553a946837a3f8e7960121fdc0d0681cb66 100644 (file)
@@ -13,3 +13,19 @@ void antilag_restore_all(entity ignore);
 
 #define ANTILAG_LATENCY(e) min(0.4, CS(e).ping * 0.001)
 // add one ticrate?
+
+/*
+==================
+traceline_antilag
+
+A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
+Additionally it moves players back into the past before the trace and restores them afterward.
+==================
+*/
+void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz);
+void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
+void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
+void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag);
+void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
+void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
+void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag);
index a2f9ab49b4f9c48497e8599806adc6ff7cd247a2..7d73a73a8b7e65086756c1e261a1b9edcacd3b90 100644 (file)
@@ -167,7 +167,7 @@ int autocvar_g_maxplayers;
 float autocvar_g_maxplayers_spectator_blocktime;
 float autocvar_g_maxpushtime;
 float autocvar_g_maxspeed;
-bool autocvar_g_instagib;
+#define autocvar_g_instagib cvar("g_instagib")
 #define autocvar_g_mirrordamage cvar("g_mirrordamage")
 #define autocvar_g_mirrordamage_virtual cvar("g_mirrordamage_virtual")
 bool autocvar_g_mirrordamage_onlyweapons;
@@ -240,6 +240,7 @@ float autocvar_g_turrets_targetscan_mindelay;
 bool autocvar_g_use_ammunition;
 bool autocvar_g_waypointeditor;
 bool autocvar_g_waypointeditor_symmetrical;
+bool autocvar_g_waypointeditor_symmetrical_allowload = true;
 vector autocvar_g_waypointeditor_symmetrical_origin;
 int autocvar_g_waypointeditor_symmetrical_order;
 vector autocvar_g_waypointeditor_symmetrical_axis;
@@ -256,7 +257,6 @@ bool autocvar_lastlevel;
 //int autocvar_leadlimit;
 int autocvar_leadlimit_and_fraglimit;
 int autocvar_leadlimit_override;
-int autocvar_loddebug;
 int autocvar_minplayers;
 string autocvar_nextmap;
 string autocvar_quit_and_redirect;
@@ -470,6 +470,8 @@ float autocvar_g_nades_entrap_strength = 0.01;
 float autocvar_g_nades_entrap_speed = 0.5;
 float autocvar_g_nades_entrap_radius = 500;
 float autocvar_g_nades_entrap_time = 10;
+float autocvar_g_nades_veil_time = 8;
+float autocvar_g_nades_veil_radius = 300;
 string autocvar_g_nades_pokenade_monster_type;
 float autocvar_g_nades_pokenade_monster_lifetime;
 bool autocvar_g_jump_grunt;
index 51ac148fc13c42c1185866cd87d6430165f61b8e..0ecd7b87725b41f7ca894570f7343836a845d3da 100644 (file)
@@ -79,7 +79,9 @@ bool havocbot_goalrating_item_pickable_check_players(entity this, vector org, en
 
 vector havocbot_middlepoint;
 float havocbot_middlepoint_radius;
-vector havocbot_symmetryaxis_equation;
+float havocbot_symmetry_axis_m;
+float havocbot_symmetry_axis_q;
+float havocbot_symmetry_origin_order;
 
 .float goalentity_lock_timeout;
 .float ignoregoaltime;
index 5ad1295f990f0b3d16be6b989e3263e4b17b3466..3a9befde403f9ee2a8fb6c2f99076af8ca433d9f 100644 (file)
@@ -11,7 +11,7 @@
 
 #include "../../weapons/weaponsystem.qh"
 
-#include "../../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 
 // traces multiple trajectories to find one that will impact the target
 // 'end' vector is the place it aims for,
@@ -139,10 +139,12 @@ bool bot_shouldattack(entity this, entity targ)
                return false;
        if (IS_DEAD(targ))
                return false;
-       if (PHYS_INPUT_BUTTON_CHAT(targ))
+       if (PHYS_INPUT_BUTTON_CHAT(targ) && !autocvar_bot_typefrag)
                return false;
        if(targ.flags & FL_NOTARGET)
                return false;
+       if(targ.alpha <= 0.1 && targ.alpha != 0)
+               return false; // invisible via alpha
 
        if(MUTATOR_CALLHOOK(BotShouldAttack, this, targ))
                return false;
index a605fc0689e73259ba266cd41047ca573bb252ad..976d67ec996d3e28c67088d95d19798c584d037b 100644 (file)
@@ -21,7 +21,7 @@
 #include "../../race.qh"
 #include <common/t_items.qh>
 
-#include "../../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 
 #include "../../weapons/accuracy.qh"
 
@@ -396,18 +396,10 @@ void bot_clientdisconnect(entity this)
        if (!IS_BOT_CLIENT(this))
                return;
        bot_clearqueue(this);
-       if(this.cleanname)
-               strunzone(this.cleanname);
-       if(this.netname_freeme)
-               strunzone(this.netname_freeme);
-       if(this.playermodel_freeme)
-               strunzone(this.playermodel_freeme);
-       if(this.playerskin_freeme)
-               strunzone(this.playerskin_freeme);
-       this.cleanname = string_null;
-       this.netname_freeme = string_null;
-       this.playermodel_freeme = string_null;
-       this.playerskin_freeme = string_null;
+       strfree(this.cleanname);
+       strfree(this.netname_freeme);
+       strfree(this.playermodel_freeme);
+       strfree(this.playerskin_freeme);
        if(this.bot_cmd_current)
                delete(this.bot_cmd_current);
        if(bot_waypoint_queue_owner == this)
index 16b2aaf4312367da99abc30e2d9427f23c1d2402..aea112d9edf75d126ded64b3907ad1c6dcfa1097 100644 (file)
@@ -54,6 +54,7 @@ bool autocvar_bot_usemodelnames;
 bool autocvar_bot_debug_tracewalk;
 bool autocvar_bot_debug_goalstack;
 bool autocvar_bot_wander_enable;
+bool autocvar_bot_typefrag;
 bool autocvar_g_debug_bot_commands;
 int autocvar_g_waypointeditor_auto;
 float autocvar_skill_auto;
index 2a0d0c8503f005c17d2156fd2871ebf216ac932d..91b5c463d8fdcc007ff998480f7ecc93c92d8156 100644 (file)
@@ -18,8 +18,8 @@
 #include <common/items/_mod.qh>
 #include <common/wepent.qh>
 
-#include <common/triggers/teleporters.qh>
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/teleporters.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
 
 #include <lib/warpzone/common.qh>
 
@@ -109,7 +109,7 @@ void havocbot_ai(entity this)
                this.aistatus |= AI_STATUS_ATTACKING;
                this.aistatus &= ~AI_STATUS_ROAMING;
 
-               if(this.weapons)
+               if(STAT(WEAPONS, this))
                {
                        if (autocvar_bot_nofire || IS_INDEPENDENT_PLAYER(this))
                        {
@@ -204,7 +204,7 @@ void havocbot_ai(entity this)
                        if(this.(weaponentity).clip_load >= 0) // only if we're not reloading a weapon already
                        {
                                FOREACH(Weapons, it != WEP_Null, {
-                                       if((this.weapons & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
+                                       if((STAT(WEAPONS, this) & (it.m_wepset)) && (it.spawnflags & WEP_FLAG_RELOADABLE) && (this.(weaponentity).weapon_load[it.m_id] < it.reloading_ammo))
                                        {
                                                this.(weaponentity).m_switchweapon = it;
                                                break;
@@ -885,17 +885,17 @@ void havocbot_movetogoal(entity this)
 
        diff = destorg - this.origin;
 
-       if (fabs(diff.x) < 10 && fabs(diff.y) < 10
-               && this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout)
+       // 1. stop if too close to target player (even if frozen)
+       // 2. stop if the locked goal has been reached
+       if ((IS_PLAYER(this.goalcurrent) && vdist(diff, <, 80))
+               || (this.goalcurrent == this.goalentity && time < this.goalentity_lock_timeout && vdist(diff, <, 10)))
        {
                destorg = this.origin;
-               diff.x = 0;
-               diff.y = 0;
+               diff = '0 0 0';
        }
 
        dir = normalize(diff);
-       flatdir = diff;flatdir.z = 0;
-       flatdir = normalize(flatdir);
+       flatdir = (diff.z == 0) ? dir : normalize(vec2(diff));
 
        //if (this.bot_dodgevector_time < time)
        {
@@ -1238,7 +1238,7 @@ LABEL(scan_targets)
 
                // I want to do a second scan if no enemy was found or I don't have weapons
                // TODO: Perform the scan when using the rifle (requires changes on the rifle code)
-               if(best || this.weapons) // || this.weapon == WEP_RIFLE.m_id
+               if(best || STAT(WEAPONS, this)) // || this.weapon == WEP_RIFLE.m_id
                        break;
                if(scan_transparent)
                        break;
index e469436014e1e030cc7dd1fc3bad16e61ad9fb11..2aa11b52ca45c3df0e2df3e0c807f1be346c1f01 100644 (file)
@@ -3,6 +3,7 @@
 #include <server/defs.qh>
 #include <server/miscfunctions.qh>
 #include <server/items.qh>
+#include <server/resources.qh>
 #include "havocbot.qh"
 
 #include "../cvars.qh"
@@ -51,12 +52,12 @@ bool havocbot_goalrating_item_can_be_left_to_teammate(entity this, entity player
 {
        if (item.health && player.health <= this.health) {return true;}
        if (item.armorvalue && player.armorvalue <= this.armorvalue) {return true;}
-       if (item.weapons && !(player.weapons & item.weapons)) {return true;}
-       if (item.ammo_shells && player.ammo_shells <= this.ammo_shells) {return true;}
-       if (item.ammo_nails && player.ammo_nails <= this.ammo_nails) {return true;}
-       if (item.ammo_rockets && player.ammo_rockets <= this.ammo_rockets) {return true;}
-       if (item.ammo_cells && player.ammo_cells <= this.ammo_cells) {return true;}
-       if (item.ammo_plasma && player.ammo_plasma <= this.ammo_plasma) {return true;}
+       if (STAT(WEAPONS, item) && !(STAT(WEAPONS, player) & STAT(WEAPONS, item))) {return true;}
+       if (item.ammo_shells && GetResourceAmount(player, RESOURCE_SHELLS) <= GetResourceAmount(this, RESOURCE_SHELLS)) {return true;}
+       if (item.ammo_nails && GetResourceAmount(player, RESOURCE_BULLETS) <= GetResourceAmount(this, RESOURCE_BULLETS)) {return true;}
+       if (item.ammo_rockets && GetResourceAmount(player, RESOURCE_ROCKETS) <= GetResourceAmount(this, RESOURCE_ROCKETS)) {return true;}
+       if (item.ammo_cells && GetResourceAmount(player, RESOURCE_CELLS) <= GetResourceAmount(this, RESOURCE_CELLS)) {return true;}
+       if (item.ammo_plasma && GetResourceAmount(player, RESOURCE_PLASMA) <= GetResourceAmount(this, RESOURCE_PLASMA)) {return true;}
        if (item.itemdef.instanceOfPowerup) {return true;}
 
        return false;
index 7b80a1a6f27cfd790fb59f325f8eda9404dfbcf9..9c3bae8e7992f37c5ce9157bfdd7d688808346a8 100644 (file)
@@ -13,7 +13,7 @@
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
 
 .float speed;
 
@@ -246,6 +246,7 @@ vector resurface_limited(vector org, float lim, vector m1)
 // rough simulation of walking from one point to another to test if a path
 // can be traveled, used for waypoint linking and havocbot
 // if end_height is > 0 destination is any point in the vertical segment [end, end + end_height * eZ]
+// INFO: the command sv_cmd trace walk is useful to test this function in game
 bool tracewalk(entity e, vector start, vector m1, vector m2, vector end, float end_height, float movemode)
 {
        if(autocvar_bot_debug_tracewalk)
@@ -1256,7 +1257,6 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
        //print("routerating ", etos(e), " = ", ftos(f), " - ", ftos(rangebias), "\n");
 
        // Evaluate path using jetpack
-       if(g_jetpack)
        if(this.items & IT_JETPACK)
        if(autocvar_bot_ai_navigation_jetpack)
        if(vdist(this.origin - goal_org, >, autocvar_bot_ai_navigation_jetpack_mindistance))
@@ -1318,7 +1318,7 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                        LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
 
                        // enough fuel ?
-                       if(this.ammo_fuel>fuel)
+                       if(this.ammo_fuel>fuel || (this.items & IT_UNLIMITED_WEAPON_AMMO))
                        {
                                // Estimate cost
                                // (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
@@ -1573,7 +1573,7 @@ void navigation_shortenpath(entity this)
                if (trace_ent == this || tracewalk(this, this.origin, this.mins, this.maxs,
                        tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
                {
-                       LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue"); 
+                       LOG_DEBUG("path optimized for ", this.netname, ", removed a goal from the queue");
                        navigation_poproute(this);
                }
        }
@@ -1839,7 +1839,7 @@ void navigation_unstuck(entity this)
                float d = vlen2(this.origin - bot_waypoint_queue_goal.origin);
                LOG_DEBUG(this.netname, " evaluating ", bot_waypoint_queue_goal.classname, " with distance ", ftos(d));
                set_tracewalk_dest(bot_waypoint_queue_goal, this.origin, false);
-               if (tracewalk(bot_waypoint_queue_goal, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
+               if (tracewalk(this, this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this),
                        tracewalk_dest, tracewalk_dest_height, bot_navigation_movemode))
                {
                        if( d > bot_waypoint_queue_bestgoalrating)
index e69050beb84d16e438e12f5849184139f792195c..82d82cb590f3835dbc0691ae7b17840176adfd00 100644 (file)
@@ -308,9 +308,7 @@ float bot_decodecommand(string cmdstring)
                                bot_cmd.bot_cmd_parm_float = stof(parm);
                                break;
                        case BOT_CMD_PARAMETER_STRING:
-                               if(bot_cmd.bot_cmd_parm_string)
-                                       strunzone(bot_cmd.bot_cmd_parm_string);
-                               bot_cmd.bot_cmd_parm_string = strzone(parm);
+                               strcpy(bot_cmd.bot_cmd_parm_string, parm);
                                break;
                        case BOT_CMD_PARAMETER_VECTOR:
                                if(substring(parm, 0, 1) != "\'")
@@ -1170,8 +1168,7 @@ void bot_resetqueues()
                it.bot_barrier = 0;
                for(int i = 0; i < it.bot_places_count; ++i)
                {
-                       strunzone(it.(bot_placenames[i]));
-                       it.(bot_placenames[i]) = string_null;
+                       strfree(it.(bot_placenames[i]));
                }
                it.bot_places_count = 0;
        });
index fa82d926b63e92776cfd293dbebccf15ba20ad04..674ab634a1c768889ff3ac4025ea07008221b813 100644 (file)
@@ -141,8 +141,8 @@ vector waypoint_getSymmetricalOrigin(vector org, int ctf_flags)
        }
        else if (fabs(autocvar_g_waypointeditor_symmetrical) == 2)
        {
-               float m = havocbot_symmetryaxis_equation.x;
-               float q = havocbot_symmetryaxis_equation.y;
+               float m = havocbot_symmetry_axis_m;
+               float q = havocbot_symmetry_axis_q;
                if (autocvar_g_waypointeditor_symmetrical == -2)
                {
                        m = autocvar_g_waypointeditor_symmetrical_axis.x;
@@ -190,6 +190,16 @@ entity waypoint_spawn(vector m1, vector m2, float f)
                        return it;
                });
        }
+       // spawn only one destination waypoint for teleports teleporting player to the exact same spot
+       // otherwise links loaded from file would be applied only to the first destination
+       // waypoint since link format doesn't specify waypoint entities but just positions
+       if((f & WAYPOINTFLAG_GENERATED) && !(f & WAYPOINTFLAG_NORELINK) && m1 == m2)
+       {
+               IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
+               {
+                       return it;
+               });
+       }
 
        entity w = new(waypoint);
        IL_PUSH(g_waypoints, w);
@@ -236,15 +246,12 @@ void waypoint_spawn_fromeditor(entity pl)
 {
        entity e;
        vector org = pl.origin;
-       int ctf_flags = havocbot_symmetryaxis_equation.z;
+       int ctf_flags = havocbot_symmetry_origin_order;
        bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
                   || (autocvar_g_waypointeditor_symmetrical < 0));
-       int order = ctf_flags;
        if(autocvar_g_waypointeditor_symmetrical_order >= 2)
-       {
-               order = autocvar_g_waypointeditor_symmetrical_order;
-               ctf_flags = order;
-       }
+               ctf_flags = autocvar_g_waypointeditor_symmetrical_order;
+       int wp_num = ctf_flags;
 
        if(!PHYS_INPUT_BUTTON_CROUCH(pl))
        {
@@ -275,8 +282,8 @@ void waypoint_spawn_fromeditor(entity pl)
                org = waypoint_getSymmetricalOrigin(e.origin, ctf_flags);
                if (vdist(org - pl.origin, >, 32))
                {
-                       if(order > 2)
-                               order--;
+                       if(wp_num > 2)
+                               wp_num--;
                        else
                                sym = false;
                        goto add_wp;
@@ -299,15 +306,12 @@ void waypoint_remove_fromeditor(entity pl)
 {
        entity e = navigation_findnearestwaypoint(pl, false);
 
-       int ctf_flags = havocbot_symmetryaxis_equation.z;
+       int ctf_flags = havocbot_symmetry_origin_order;
        bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
                   || (autocvar_g_waypointeditor_symmetrical < 0));
-       int order = ctf_flags;
        if(autocvar_g_waypointeditor_symmetrical_order >= 2)
-       {
-               order = autocvar_g_waypointeditor_symmetrical_order;
-               ctf_flags = order;
-       }
+               ctf_flags = autocvar_g_waypointeditor_symmetrical_order;
+       int wp_num = ctf_flags;
 
        LABEL(remove_wp);
        if (!e) return;
@@ -338,8 +342,8 @@ void waypoint_remove_fromeditor(entity pl)
        if (sym && wp_sym)
        {
                e = wp_sym;
-               if(order > 2)
-                       order--;
+               if(wp_num > 2)
+                       wp_num--;
                else
                        sym = false;
                goto remove_wp;
@@ -446,7 +450,7 @@ float waypoint_getlinearcost(float dist)
 }
 float waypoint_getlinearcost_underwater(float dist)
 {
-       // NOTE: this value is hardcoded on the engine too, see SV_WaterMove
+       // NOTE: underwater speed factor is hardcoded in the engine too, see SV_WaterMove
        return dist / (autocvar_sv_maxspeed * 0.7);
 }
 
@@ -557,6 +561,9 @@ void waypoint_think(entity this)
 
        bot_calculate_stepheightvec();
 
+       int dphitcontentsmask_save = this.dphitcontentsmask;
+       this.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+
        bot_navigation_movemode = ((autocvar_bot_navigation_ignoreplayers) ? MOVE_NOMONSTERS : MOVE_NORMAL);
 
        //dprint("waypoint_think wpisbox = ", ftos(this.wpisbox), "\n");
@@ -609,7 +616,7 @@ void waypoint_think(entity this)
                                relink_walkculled += 0.5;
                        else
                        {
-                               if (tracewalk(it, ev, PL_MIN_CONST, PL_MAX_CONST, sv2, sv2_height, MOVE_NOMONSTERS))
+                               if (tracewalk(this, ev, PL_MIN_CONST, PL_MAX_CONST, sv2, sv2_height, MOVE_NOMONSTERS))
                                        waypoint_addlink(it, this);
                                else
                                        relink_walkculled += 0.5;
@@ -618,6 +625,7 @@ void waypoint_think(entity this)
        });
        navigation_testtracewalk = 0;
        this.wplinked = true;
+       this.dphitcontentsmask = dphitcontentsmask_save;
 }
 
 void waypoint_clearlinks(entity wp)
@@ -1028,10 +1036,33 @@ void waypoint_saveall()
                return;
        }
 
-       // add 3 comments to not break compatibility with older Xonotic versions
+       float sym = autocvar_g_waypointeditor_symmetrical;
+       string sym_str = ftos(sym);
+       if (sym == -1 || (sym == 1 && autocvar_g_waypointeditor_symmetrical_order >= 2))
+       {
+               if (sym == 1)
+               {
+                       sym_str = cons(sym_str, "-");
+                       sym_str = cons(sym_str, "-");
+               }
+               else
+               {
+                       sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_origin.x));
+                       sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_origin.y));
+               }
+               if (autocvar_g_waypointeditor_symmetrical_order >= 2)
+                       sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_order));
+       }
+       else if (autocvar_g_waypointeditor_symmetrical == -2)
+       {
+               sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_axis.x));
+               sym_str = cons(sym_str, ftos(autocvar_g_waypointeditor_symmetrical_axis.y));
+       }
+
+       // a group of 3 comments doesn't break compatibility with older Xonotic versions
        // (they are read as a waypoint with origin '0 0 0' and flag 0 though)
        fputs(file, strcat("//", "WAYPOINT_VERSION ", ftos_decimals(WAYPOINT_VERSION, 2), "\n"));
-       fputs(file, strcat("//", "\n"));
+       fputs(file, strcat("//", "WAYPOINT_SYMMETRY ", sym_str, "\n"));
        fputs(file, strcat("//", "\n"));
 
        int c = 0;
@@ -1085,6 +1116,8 @@ float waypoint_loadall()
 
        bool parse_comments = true;
        float ver = 0;
+       float sym = 0;
+       float sym_param1 = 0, sym_param2 = 0, sym_param3 = 0;
 
        while ((s = fgets(file)))
        {
@@ -1094,6 +1127,14 @@ float waypoint_loadall()
                        {
                                if(substring(s, 2, 17) == "WAYPOINT_VERSION ")
                                        ver = stof(substring(s, 19, -1));
+                               else if(substring(s, 2, 18) == "WAYPOINT_SYMMETRY ")
+                               {
+                                       int tokens = tokenizebyseparator(substring(s, 20, -1), " ");
+                                       if (tokens) { sym = stof(argv(0)); }
+                                       if (tokens > 1) { sym_param1 = stof(argv(1)); }
+                                       if (tokens > 2) { sym_param2 = stof(argv(2)); }
+                                       if (tokens > 3) { sym_param3 = stof(argv(3)); }
+                               }
                                continue;
                        }
                        else
@@ -1124,6 +1165,35 @@ float waypoint_loadall()
        fclose(file);
        LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints");
 
+       if (autocvar_g_waypointeditor && autocvar_g_waypointeditor_symmetrical_allowload)
+       {
+               cvar_set("g_waypointeditor_symmetrical", ftos(sym));
+               if (sym == 1 && sym_param3 < 2)
+                       cvar_set("g_waypointeditor_symmetrical_order", "0"); // make sure this is reset if not loaded
+               if (sym == -1 || (sym == 1 && sym_param3 >= 2))
+               {
+                       string params;
+                       if (sym == 1)
+                               params = cons("-", "-");
+                       else
+                       {
+                               params = cons(ftos(sym_param1), ftos(sym_param2));
+                               cvar_set("g_waypointeditor_symmetrical_origin", params);
+                       }
+                       cvar_set("g_waypointeditor_symmetrical_order", ftos(sym_param3));
+                       LOG_INFO("Waypoint editor: loaded symmetry ", ftos(sym), " with origin ", params, " and order ", ftos(sym_param3));
+               }
+               else if (sym == -2)
+               {
+                       string params = strcat(ftos(sym_param1), " ", ftos(sym_param2));
+                       cvar_set("g_waypointeditor_symmetrical_axis", params);
+                       LOG_INFO("Waypoint editor: loaded symmetry ", ftos(sym), " with axis ", params);
+               }
+               else
+                       LOG_INFO("Waypoint editor: loaded symmetry ", ftos(sym));
+               LOG_INFO(strcat("g_waypointeditor_symmetrical", " has been set to ", cvar_string("g_waypointeditor_symmetrical")));
+       }
+
        return cwp + cwb;
 }
 
@@ -1283,6 +1353,8 @@ void botframe_showwaypointlinks()
        {
                int display_type = 0;
                entity head = navigation_findnearestwaypoint(it, false);
+               it.nearestwaypoint = head; // mainly useful for debug
+               it.nearestwaypointtimeout = time + 2; // while I'm at it...
                if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE)
                        display_type = 1; // default
                else if(head && (head.wphardwired))
index bea11e9299986ce180765f09a520e37c8295f6de..595c2d058fcc1cd82fa1a082ffd29096f90adc3b 100644 (file)
@@ -6,7 +6,7 @@
 // increase by 0.01 when changes require only waypoint relinking
 // increase by 1 when changes require to manually edit waypoints
 // max 2 decimal places, always specified
-#define WAYPOINT_VERSION 1.00
+#define WAYPOINT_VERSION 1.01
 
 // fields you can query using prvm_global server to get some statistics about waypoint linking culling
 float relink_total, relink_walkculled, relink_pvsculled, relink_lengthculled;
index e80769cc2783edabcca7b1952aafbb5f9b06a256..e90d6660352a28d0f62415cdd2d769110e8495d7 100644 (file)
@@ -52,8 +52,7 @@ void cvar_set_campaignwrapper(string theCvar, string theValue)
 {
        if(cvar_string_campaignwrapper(theCvar) == theValue)
                return;
-       string s;
-       s = cvar_campaignwrapper_list;
+       string s = cvar_campaignwrapper_list;
        cvar_campaignwrapper_list = strzone(strcat("; ", theCvar, " ", theValue, s));
        strunzone(s);
        //print(cvar_campaignwrapper_list, "\n");
index 976d5a7b94d6e4caa2ca7982529cde04b88e5a80..1dcdab7381af4f18bb37ee3f9d55194ee443b767 100644 (file)
@@ -3,12 +3,14 @@
 #include <server/defs.qh>
 #include <server/miscfunctions.qh>
 #include <common/effects/all.qh>
+#include <server/resources.qh>
 
 #include "g_damage.qh"
+#include "player.qh"
 #include "race.qh"
-#include "../common/triggers/teleporters.qh"
+#include "../common/mapobjects/teleporters.qh"
 
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 
 #include "weapons/tracing.qh"
 
 
 #include <common/weapons/_all.qh>
 
-#include "../common/triggers/subs.qh"
+#include "../common/mapobjects/subs.qh"
+#include <common/mapobjects/triggers.qh>
 
-#include "../common/triggers/func/breakable.qh"
+#include "../common/mapobjects/func/breakable.qh"
 
 #include "../lib/csqcmodel/sv_model.qh"
 
 #include "../lib/warpzone/anglestransform.qh"
 #include "../lib/warpzone/util_server.qh"
 
-void CopyBody(entity this, float keepvelocity);
-
 #ifdef NOCHEATS
 
 float CheatImpulse(entity this, int imp) { return 0; }
@@ -151,15 +152,15 @@ float CheatImpulse(entity this, int imp)
                        this.personal.origin = this.origin;
                        this.personal.v_angle = this.v_angle;
                        this.personal.velocity = this.velocity;
-                       this.personal.ammo_rockets = this.ammo_rockets;
-                       this.personal.ammo_nails = this.ammo_nails;
-                       this.personal.ammo_cells = this.ammo_cells;
-                       this.personal.ammo_plasma = this.ammo_plasma;
-                       this.personal.ammo_shells = this.ammo_shells;
-                       this.personal.ammo_fuel = this.ammo_fuel;
+                       SetResourceAmount(this.personal, RESOURCE_ROCKETS, GetResourceAmount(this, RESOURCE_ROCKETS));
+                       SetResourceAmount(this.personal, RESOURCE_BULLETS, GetResourceAmount(this, RESOURCE_BULLETS));
+                       SetResourceAmount(this.personal, RESOURCE_CELLS, GetResourceAmount(this, RESOURCE_CELLS));
+                       SetResourceAmount(this.personal, RESOURCE_PLASMA, GetResourceAmount(this, RESOURCE_PLASMA));
+                       SetResourceAmount(this.personal, RESOURCE_SHELLS, GetResourceAmount(this, RESOURCE_SHELLS));
+                       SetResourceAmount(this.personal, RESOURCE_FUEL, GetResourceAmount(this, RESOURCE_FUEL));
                        this.personal.health = max(1, this.health);
                        this.personal.armorvalue = this.armorvalue;
-                       this.personal.weapons = this.weapons;
+                       STAT(WEAPONS, this.personal) = STAT(WEAPONS, this);
                        this.personal.items = this.items;
                        this.personal.pauserotarmor_finished = this.pauserotarmor_finished;
                        this.personal.pauserothealth_finished = this.pauserothealth_finished;
@@ -210,15 +211,15 @@ float CheatImpulse(entity this, int imp)
                                        MUTATOR_CALLHOOK(AbortSpeedrun, this);
                                }
 
-                               this.ammo_rockets = this.personal.ammo_rockets;
-                               this.ammo_nails = this.personal.ammo_nails;
-                               this.ammo_cells = this.personal.ammo_cells;
-                               this.ammo_plasma = this.personal.ammo_plasma;
-                               this.ammo_shells = this.personal.ammo_shells;
-                               this.ammo_fuel = this.personal.ammo_fuel;
+                               SetResourceAmount(this, RESOURCE_ROCKETS, GetResourceAmount(this.personal, RESOURCE_ROCKETS));
+                               SetResourceAmount(this, RESOURCE_BULLETS, GetResourceAmount(this.personal, RESOURCE_BULLETS));
+                               SetResourceAmount(this, RESOURCE_CELLS, GetResourceAmount(this.personal, RESOURCE_CELLS));
+                               SetResourceAmount(this, RESOURCE_PLASMA, GetResourceAmount(this.personal, RESOURCE_PLASMA));
+                               SetResourceAmount(this, RESOURCE_SHELLS, GetResourceAmount(this.personal, RESOURCE_SHELLS));
+                               SetResourceAmount(this, RESOURCE_FUEL, GetResourceAmount(this.personal, RESOURCE_FUEL));
                                this.health = this.personal.health;
                                this.armorvalue = this.personal.armorvalue;
-                               this.weapons = this.personal.weapons;
+                               STAT(WEAPONS, this) = STAT(WEAPONS, this.personal);
                                this.items = this.personal.items;
                                this.pauserotarmor_finished = time + this.personal.pauserotarmor_finished - this.personal.teleport_time;
                                this.pauserothealth_finished = time + this.personal.pauserothealth_finished - this.personal.teleport_time;
@@ -290,7 +291,6 @@ float CheatImpulse(entity this, int imp)
        END_CHEAT_FUNCTION();
 }
 
-void DragBox_Think(entity this);
 float drag_lastcnt;
 float CheatCommand(entity this, int argc)
 {
@@ -710,18 +710,6 @@ float CheatCommand(entity this, int argc)
        END_CHEAT_FUNCTION();
 }
 
-float Drag(entity this, float force_allow_pick, float ischeat);
-void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
-void Drag_Finish(entity dragger);
-float Drag_IsDraggable(entity draggee);
-float Drag_MayChangeAngles(entity draggee);
-void Drag_MoveForward(entity dragger);
-void Drag_SetSpeed(entity dragger, float s);
-void Drag_MoveBackward(entity dragger);
-void Drag_Update(entity dragger);
-float Drag_CanDrag(entity dragger);
-float Drag_IsDragging(entity dragger);
-void Drag_MoveDrag(entity from, entity to);
 .entity dragentity;
 
 float CheatFrame(entity this)
index 1bf08064106c410874df00f9607d9222929ab1c0..0dc6a92d9c45b5f103e432fabaa59f8c3db45bb1 100644 (file)
@@ -15,3 +15,16 @@ float CheatFrame(entity this);
 const float CHRAME_DRAG = 8;
 
 void Drag_MoveDrag(entity from, entity to); // call this from CopyBody
+void DragBox_Think(entity this);
+float Drag(entity this, float force_allow_pick, float ischeat);
+void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
+void Drag_Finish(entity dragger);
+float Drag_IsDraggable(entity draggee);
+float Drag_MayChangeAngles(entity draggee);
+void Drag_MoveForward(entity dragger);
+void Drag_SetSpeed(entity dragger, float s);
+void Drag_MoveBackward(entity dragger);
+void Drag_Update(entity dragger);
+float Drag_CanDrag(entity dragger);
+float Drag_IsDragging(entity dragger);
+void Drag_MoveDrag(entity from, entity to);
index 5a199e06dc3396c61b7de4b0ff5e24bf112bcbb8..93d037aadae46bf43d0d2495291a4fba603bbea1 100644 (file)
@@ -17,6 +17,7 @@
 #include "handicap.qh"
 #include "g_hook.qh"
 #include "command/common.qh"
+#include "command/vote.qh"
 #include "cheats.qh"
 #include "g_world.qh"
 #include "race.qh"
@@ -33,9 +34,9 @@
 
 #include <common/effects/qc/globalsound.qh>
 
-#include "../common/triggers/func/conveyor.qh"
-#include "../common/triggers/teleporters.qh"
-#include "../common/triggers/target/spawnpoint.qh"
+#include "../common/mapobjects/func/conveyor.qh"
+#include "../common/mapobjects/teleporters.qh"
+#include "../common/mapobjects/target/spawnpoint.qh"
 
 #include "../common/vehicles/all.qh"
 
 #include "../common/net_linked.qh"
 #include "../common/physics/player.qh"
 
+#include <common/vehicles/sv_vehicles.qh>
+
 #include "../common/items/_mod.qh"
 
 #include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include <common/gamemodes/_mod.qh>
 
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/triggers.qh"
-#include "../common/triggers/trigger/secret.qh"
+#include "../common/mapobjects/subs.qh"
+#include "../common/mapobjects/triggers.qh"
+#include "../common/mapobjects/trigger/secret.qh"
 
 #include "../common/minigames/sv_minigames.qh"
 
@@ -62,6 +67,8 @@
 
 #include "../lib/warpzone/server.qh"
 
+#include <common/mutators/mutator/overkill/oknex.qh>
+
 STATIC_METHOD(Client, Add, void(Client this, int _team))
 {
     ClientConnect(this);
@@ -71,8 +78,6 @@ STATIC_METHOD(Client, Add, void(Client this, int _team))
     PutClientInServer(this);
 }
 
-void PutObserverInServer(entity this);
-
 STATIC_METHOD(Client, Remove, void(Client this))
 {
     TRANSMUTE(Observer, this);
@@ -152,15 +157,17 @@ void ClientData_Detach(entity this)
 
 void ClientData_Touch(entity e)
 {
-       CS(e).clientdata.SendFlags = 1;
+       entity cd = CS(e).clientdata;
+       if (cd) { cd.SendFlags = 1; }
 
        // make it spectatable
-       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e, { CS(it).clientdata.SendFlags = 1; });
+       FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != e && IS_SPEC(it) && it.enemy == e,
+       {
+               entity cd = CS(it).clientdata;
+               if (cd) { cd.SendFlags = 1; }
+       });
 }
 
-void SetSpectatee(entity this, entity spectatee);
-void SetSpectatee_status(entity this, int spectatee_num);
-
 
 /*
 =============
@@ -214,7 +221,6 @@ void setplayermodel(entity e, string modelname)
                UpdatePlayerSounds(e);
 }
 
-void FixPlayermodel(entity player);
 /** putting a client as observer in the server */
 void PutObserverInServer(entity this)
 {
@@ -308,6 +314,9 @@ void PutObserverInServer(entity this)
        if(this.bot_attack)
                IL_REMOVE(g_bot_targets, this);
        this.bot_attack = false;
+       if(this.monster_attack)
+               IL_REMOVE(g_monster_targets, this);
+       this.monster_attack = false;
     STAT(HUD, this) = HUD_NORMAL;
        TRANSMUTE(Observer, this);
        this.iscreature = false;
@@ -340,6 +349,7 @@ void PutObserverInServer(entity this)
        this.strength_finished = 0;
        this.invincible_finished = 0;
        this.superweapons_finished = 0;
+       this.dphitcontentsmask = 0;
        this.pushltime = 0;
        this.istypefrag = 0;
        setthink(this, func_null);
@@ -350,7 +360,7 @@ void PutObserverInServer(entity this)
        this.revival_time = 0;
 
        this.items = 0;
-       this.weapons = '0 0 0';
+       STAT(WEAPONS, this) = '0 0 0';
        this.drawonlytoclient = this;
 
        this.viewloc = NULL;
@@ -544,25 +554,25 @@ void PutPlayerInServer(entity this)
        this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
 
        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;
+               SetResourceAmount(this, RESOURCE_SHELLS, warmup_start_ammo_shells);
+               SetResourceAmount(this, RESOURCE_BULLETS, warmup_start_ammo_nails);
+               SetResourceAmount(this, RESOURCE_ROCKETS, warmup_start_ammo_rockets);
+               SetResourceAmount(this, RESOURCE_CELLS, warmup_start_ammo_cells);
+               SetResourceAmount(this, RESOURCE_PLASMA, warmup_start_ammo_plasma);
+               SetResourceAmount(this, RESOURCE_FUEL, warmup_start_ammo_fuel);
                this.health = warmup_start_health;
                this.armorvalue = warmup_start_armorvalue;
-               this.weapons = WARMUP_START_WEAPONS;
+               STAT(WEAPONS, this) = 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;
+               SetResourceAmount(this, RESOURCE_SHELLS, start_ammo_shells);
+               SetResourceAmount(this, RESOURCE_BULLETS, start_ammo_nails);
+               SetResourceAmount(this, RESOURCE_ROCKETS, start_ammo_rockets);
+               SetResourceAmount(this, RESOURCE_CELLS, start_ammo_cells);
+               SetResourceAmount(this, RESOURCE_PLASMA, start_ammo_plasma);
+               SetResourceAmount(this, RESOURCE_FUEL, start_ammo_fuel);
                this.health = start_health;
                this.armorvalue = start_armorvalue;
-               this.weapons = start_weapons;
+               STAT(WEAPONS, this) = start_weapons;
                if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
                {
                        GiveRandomWeapons(this, random_start_weapons_count,
@@ -573,7 +583,7 @@ void PutPlayerInServer(entity this)
 
        PS(this).dual_weapons = '0 0 0';
 
-       this.superweapons_finished = (this.weapons & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
+       this.superweapons_finished = (STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS) ? time + autocvar_g_balance_superweapons_time : 0;
 
        this.items = start_items;
 
@@ -778,8 +788,6 @@ void PutClientInServer(entity this)
        }
 }
 
-void ClientInit_misc(entity this);
-
 // 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)
@@ -1215,16 +1223,7 @@ void ClientConnect(entity this)
        JoinBestTeam(this, false); // if the team number is valid, keep it
        this.playerid = playerid_save;
 
-       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
-               }
-       }
+       TRANSMUTE(Observer, this);
 
        PlayerStats_GameReport_AddEvent(sprintf("kills-%d", this.playerid));
 
@@ -1328,7 +1327,6 @@ Called when a client disconnects from the server
 =============
 */
 .entity chatbubbleentity;
-void ReadyCount();
 void ClientDisconnect(entity this)
 {
        assert(IS_CLIENT(this), return);
@@ -1348,8 +1346,8 @@ void ClientDisconnect(entity this)
 
     MUTATOR_CALLHOOK(ClientDisconnect, this);
 
-       if (CS(this).netname_previous) strunzone(CS(this).netname_previous); // needs to be before the CS entity is removed!
-       if (CS(this).weaponorder_byimpulse) strunzone(CS(this).weaponorder_byimpulse);
+       strfree(CS(this).netname_previous); // needs to be before the CS entity is removed!
+       strfree(CS(this).weaponorder_byimpulse);
        ClientState_detach(this);
 
        Portal_ClearAll(this);
@@ -1369,7 +1367,7 @@ void ClientDisconnect(entity this)
 
        bot_relinkplayerlist();
 
-       if (this.clientstatus) strunzone(this.clientstatus);
+       strfree(this.clientstatus);
        if (this.personal) delete(this.personal);
 
        this.playerid = 0;
@@ -1465,6 +1463,54 @@ void respawn(entity this)
        PutClientInServer(this);
 }
 
+void PrintToChat(entity client, string text)
+{
+       text = strcat("\{1}^7", text, "\n");
+       sprint(client, text);
+}
+
+void DebugPrintToChat(entity client, string text)
+{
+       if (autocvar_developer)
+       {
+               PrintToChat(client, text);
+       }
+}
+
+void PrintToChatAll(string text)
+{
+       text = strcat("\{1}^7", text, "\n");
+       bprint(text);
+}
+
+void DebugPrintToChatAll(string text)
+{
+       if (autocvar_developer)
+       {
+               PrintToChatAll(text);
+       }
+}
+
+void PrintToChatTeam(int team_num, string text)
+{
+       text = strcat("\{1}^7", text, "\n");
+       FOREACH_CLIENT(IS_REAL_CLIENT(it),
+       {
+               if (it.team == team_num)
+               {
+                       sprint(it, text);
+               }
+       });
+}
+
+void DebugPrintToChatTeam(int team_num, string text)
+{
+       if (autocvar_developer)
+       {
+               PrintToChatTeam(team_num, text);
+       }
+}
+
 void play_countdown(entity this, float finished, Sound samp)
 {
     TC(Sound, samp);
@@ -1492,7 +1538,7 @@ void player_powerups(entity this)
        Fire_ApplyDamage(this);
        Fire_ApplyEffect(this);
 
-       if (!g_instagib)
+       if (!MUTATOR_IS_ENABLED(mutator_instagib))
        {
                if (this.items & ITEM_Strength.m_itemid)
                {
@@ -1538,7 +1584,7 @@ void player_powerups(entity this)
                }
                if (this.items & IT_SUPERWEAPON)
                {
-                       if (!(this.weapons & WEPSET_SUPERWEAPONS))
+                       if (!(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS))
                        {
                                this.superweapons_finished = 0;
                                this.items = this.items - (this.items & IT_SUPERWEAPON);
@@ -1555,13 +1601,13 @@ void player_powerups(entity this)
                                if (time > this.superweapons_finished)
                                {
                                        this.items = this.items - (this.items & IT_SUPERWEAPON);
-                                       this.weapons &= ~WEPSET_SUPERWEAPONS;
+                                       STAT(WEAPONS, this) &= ~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)
+               else if(STAT(WEAPONS, this) & WEPSET_SUPERWEAPONS)
                {
                        if (time < this.superweapons_finished || (this.items & IT_UNLIMITED_SUPERWEAPONS))
                        {
@@ -1573,7 +1619,7 @@ void player_powerups(entity this)
                        else
                        {
                                this.superweapons_finished = 0;
-                               this.weapons &= ~WEPSET_SUPERWEAPONS;
+                               STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
                        }
                }
                else
@@ -1759,7 +1805,7 @@ void SpectateCopy(entity this, entity spectatee)
        PS(this) = PS(spectatee);
        this.armortype = spectatee.armortype;
        this.armorvalue = spectatee.armorvalue;
-       this.ammo_cells = spectatee.ammo_cells;
+       this.ammo_cells = spectatee.ammo_cells; // TODO: these will be a part of inventory, so no need to worry about setting them later!
        this.ammo_plasma = spectatee.ammo_plasma;
        this.ammo_shells = spectatee.ammo_shells;
        this.ammo_nails = spectatee.ammo_nails;
@@ -1775,7 +1821,7 @@ void SpectateCopy(entity this, entity spectatee)
        this.invincible_finished = spectatee.invincible_finished;
        this.superweapons_finished = spectatee.superweapons_finished;
        STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
-       this.weapons = spectatee.weapons;
+       STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
        this.punchangle = spectatee.punchangle;
        this.view_ofs = spectatee.view_ofs;
        this.velocity = spectatee.velocity;
@@ -2135,13 +2181,15 @@ void PrintWelcomeMessage(entity this)
        }
 }
 
+const int MIN_SPEC_TIME = 1;
 bool joinAllowed(entity this)
 {
        if (CS(this).version_mismatch) return false;
+       if (time < CS(this).jointime + MIN_SPEC_TIME) return false;
        if (!nJoinAllowed(this, this)) return false;
        if (teamplay && lockteams) return false;
-       if (ShowTeamSelection(this)) return false;
        if (MUTATOR_CALLHOOK(ForbidSpawn, this)) return false;
+       if (ShowTeamSelection(this)) return false;
        return true;
 }
 
@@ -2242,43 +2290,6 @@ bool PlayerThink(entity this)
                return false;
        }
 
-       bool have_hook = false;
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-       {
-               .entity weaponentity = weaponentities[slot];
-               if(this.(weaponentity).hook.state)
-               {
-                       have_hook = true;
-                       break;
-               }
-       }
-       bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
-       if (have_hook) {
-               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);
 
        if (this.shootfromfixedorigin != autocvar_g_shootfromfixedorigin) {
@@ -2328,6 +2339,7 @@ bool PlayerThink(entity this)
        return true;
 }
 
+.bool would_spectate;
 void ObserverThink(entity this)
 {
        if ( CS(this).impulse )
@@ -2340,7 +2352,7 @@ void ObserverThink(entity this)
                if (PHYS_INPUT_BUTTON_JUMP(this) && joinAllowed(this)) {
                        this.flags &= ~FL_JUMPRELEASED;
                        this.flags |= FL_SPAWNING;
-               } else if(PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch) {
+               } else if(PHYS_INPUT_BUTTON_ATCK(this) && !CS(this).version_mismatch || this.would_spectate) {
                        this.flags &= ~FL_JUMPRELEASED;
                        if(SpectateNext(this)) {
                                TRANSMUTE(Spectator, this);
@@ -2400,12 +2412,19 @@ void SpectatorThink(entity this)
                        }
                        CS(this).impulse = 0;
                } else if (PHYS_INPUT_BUTTON_ATCK2(this)) {
+                       this.would_spectate = false;
                        this.flags &= ~FL_JUMPRELEASED;
                        TRANSMUTE(Observer, this);
                        PutClientInServer(this);
                } else {
                        if(!SpectateUpdate(this))
-                               PutObserverInServer(this);
+                       {
+                               if(!SpectateNext(this))
+                               {
+                                       PutObserverInServer(this);
+                                       this.would_spectate = true;
+                               }
+                       }
                }
        } else {
                if (!(PHYS_INPUT_BUTTON_ATCK(this) || PHYS_INPUT_BUTTON_ATCK2(this))) {
@@ -2424,7 +2443,6 @@ void SpectatorThink(entity this)
        this.flags |= FL_CLIENT | FL_NOTARGET;
 }
 
-void vehicles_enter (entity pl, entity veh);
 void PlayerUseKey(entity this)
 {
        if (!IS_PLAYER(this))
@@ -2514,8 +2532,7 @@ void PlayerPreThink (entity this)
                }
                if (!assume_unchanged && autocvar_sv_eventlog)
                        GameLogEcho(strcat(":name:", ftos(this.playerid), ":", playername(this, false)));
-               if (CS(this).netname_previous) strunzone(CS(this).netname_previous);
-               CS(this).netname_previous = strzone(this.netname);
+               strcpy(CS(this).netname_previous, this.netname);
        }
 
        // version nagging
@@ -2606,6 +2623,8 @@ void PlayerPreThink (entity this)
                PrintWelcomeMessage(this);
 
        if (IS_PLAYER(this)) {
+               if (IS_REAL_CLIENT(this) && time < CS(this).jointime + MIN_SPEC_TIME)
+                       error("Client can't be spawned as player on connection!");
                if(!PlayerThink(this))
                        return;
        }
@@ -2614,6 +2633,20 @@ void PlayerPreThink (entity this)
                        IntermissionThink(this);
                return;
        }
+       else if (IS_REAL_CLIENT(this) && !CS(this).autojoin_checked && time >= CS(this).jointime + MIN_SPEC_TIME)
+       {
+               CS(this).autojoin_checked = true;
+               // don't do this in ClientConnect
+               // many things can go wrong if a client is spawned as player on connection
+               if (MUTATOR_CALLHOOK(AutoJoinOnConnection, this)
+                       || (!(autocvar_sv_spectate || autocvar_g_campaign || this.team_forced < 0)
+                               && (!teamplay || autocvar_g_balance_teams)))
+               {
+                       campaign_bots_may_start = true;
+                       Join(this);
+                       return;
+               }
+       }
        else if (IS_OBSERVER(this)) {
                ObserverThink(this);
        }
@@ -2801,11 +2834,14 @@ void PM_UpdateButtons(entity this, entity store)
                store.impulse = this.impulse;
        this.impulse = 0;
 
-       store.button0 = this.button0;
-       store.button2 = this.button2;
-       store.button3 = this.button3;
+       bool typing = this.buttonchat;
+
+       store.button0 = (typing) ? 0 : this.button0;
+       //button1?!
+       store.button2 = (typing) ? 0 : this.button2;
+       store.button3 = (typing) ? 0 : this.button3;
        store.button4 = this.button4;
-       store.button5 = this.button5;
+       store.button5 = (typing) ? 0 : this.button5;
        store.button6 = this.button6;
        store.button7 = this.button7;
        store.button8 = this.button8;
@@ -2831,5 +2867,12 @@ void PM_UpdateButtons(entity this, entity store)
        store.ping_movementloss = this.ping_movementloss;
 
        store.v_angle = this.v_angle;
-       store.movement = this.movement;
+       store.movement = (typing) ? '0 0 0' : this.movement;
+}
+
+NET_HANDLE(fpsreport, bool)
+{
+       int fps = ReadShort();
+       PlayerScore_Set(sender, SP_FPS, fps);
+       return true;
 }
index 48d42da0092d2f8cf059d1f2037e8aace3bbc372..2d3a099b3988bc715589d9f5018fd310be1fc7f6 100644 (file)
@@ -114,6 +114,7 @@ CLASS(Client, Object)
     ATTRIB(Client, cmd_floodtime, float, this.cmd_floodtime);
     ATTRIB(Client, wasplayer, bool, this.wasplayer);
     ATTRIB(Client, weaponorder_byimpulse, string, this.weaponorder_byimpulse);
+    ATTRIB(Client, autojoin_checked, bool, this.wasplayer);
 
     // networked cvars
 
@@ -225,11 +226,58 @@ METHOD(Client, m_unwind, bool(Client this))
     return false;
 }
 
+/// \brief Print the string to the client's chat.
+/// \param[in] client Client to print to.
+/// \param[in] text Text to print.
+void PrintToChat(entity client, string text);
+
+/// \brief Print the string to the client's chat if the server cvar "developer"
+/// is not 0.
+/// \param[in] client Client to print to.
+/// \param[in] text Text to print.
+void DebugPrintToChat(entity client, string text);
+
+/// \brief Prints the string to all clients' chat.
+/// \param[in] text Text to print.
+void PrintToChatAll(string text);
+
+/// \brief Prints the string to all clients' chat if the server cvar "developer"
+/// is not 0.
+/// \param[in] text Text to print.
+void DebugPrintToChatAll(string text);
+
+/// \brief Print the string to chat of all clients of the specified team.
+/// \param[in] team_num Team to print to. See NUM_TEAM constants.
+/// \param[in] text Text to print.
+void PrintToChatTeam(int team_num, string text);
+
+/// \brief Print the string to chat of all clients of the specified team if the
+/// server cvar "developer" is not 0.
+/// \param[in] team_num Team to print to. See NUM_TEAM constants.
+/// \param[in] text Text to print.
+void DebugPrintToChatTeam(int team_num, string text);
+
 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)
+void ClientInit_Spawn();
+
+void PutObserverInServer(entity this);
+
+void SetSpectatee(entity this, entity spectatee);
+void SetSpectatee_status(entity this, int spectatee_num);
+
+void FixPlayermodel(entity player);
+
+void ClientInit_misc(entity this);
+
+void ClientKill_TeamChange(entity this, float targetteam);  // 0 = don't change, -1 = auto, -2 = spec
+
+bool joinAllowed(entity this);
+void Join(entity this);
+
+#define SPECTATE_COPY() ACCUMULATE void SpectateCopy(entity this, entity spectatee)
 #define SPECTATE_COPYFIELD(fld) SPECTATE_COPY() { this.(fld) = spectatee.(fld); }
index d6b1ae60f0f779511ca65dd6830323c134c91fe3..3cbaaf978e2950d7ad241a4147fab59953db3c11 100644 (file)
@@ -8,11 +8,6 @@
 #define GET_BAN_ARG(v, d) if (argc > reason_arg) { if ((v = stof(argv(reason_arg))) != 0) ++reason_arg; else v = d; } else { v = d; }
 #define GET_BAN_REASON(v, d) if (argc > reason_arg) v = substring(command, argv_start_index(reason_arg), strlen(command) - argv_start_index(reason_arg)); else v = d;
 
-void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
-void Ban_View();
-float Ban_Insert(string ip, float bantime, string reason, float dosync);
-float Ban_Delete(float i);
-
 // used by common/command/generic.qc:GenericCommand_dumpcommands to list all commands into a .txt file
 void BanCommand_macro_write_aliases(float fh);
 
index 088925f100f2f3f47499a4be5a72bcac7861bf15..9b7a0f6574fb78cf3636d8325b4bb7479f59ae47 100644 (file)
 
 #include "../campaign.qh"
 #include "../cheats.qh"
+#include "../client.qh"
 #include "../player.qh"
 #include "../ipban.qh"
 #include "../mapvoting.qh"
 #include "../scores.qh"
 #include "../teamplay.qh"
 
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
+#include <common/gamemodes/_mod.qh>
 
 #ifdef SVQC
        #include <common/vehicles/all.qh>
@@ -30,7 +32,7 @@
 #include <common/physics/player.qh>
 #include <common/teams.qh>
 #include <common/util.qh>
-#include <common/triggers/triggers.qh>
+#include <common/mapobjects/triggers.qh>
 
 #include <common/minigames/sv_minigames.qh>
 
@@ -40,8 +42,6 @@
 
 #include <lib/warpzone/common.qh>
 
-void ClientKill_TeamChange(entity this, float targetteam);  // 0 = don't change, -1 = auto, -2 = spec
-
 // =========================================================
 //  Server side networked commands code, reworked by Samual
 //  Last updated: December 28th, 2011
@@ -165,8 +165,6 @@ void ClientCommand_mv_getpicture(entity caller, float request, float argc)  // i
        }
 }
 
-bool joinAllowed(entity this);
-void Join(entity this);
 void ClientCommand_join(entity caller, float request)
 {
        switch (request)
@@ -248,12 +246,14 @@ void ClientCommand_ready(entity caller, float request)  // todo: anti-spam for t
                                                if (caller.ready)            // toggle
                                                {
                                                        caller.ready = false;
-                                                       bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
+                                                       if(IS_PLAYER(caller) || caller.caplayer == 1)
+                                                               bprint(playername(caller, false), "^2 is ^1NOT^2 ready\n");
                                                }
                                                else
                                                {
                                                        caller.ready = true;
-                                                       bprint(playername(caller, false), "^2 is ready\n");
+                                                       if(IS_PLAYER(caller) || caller.caplayer == 1)
+                                                               bprint(playername(caller, false), "^2 is ready\n");
                                                }
 
                                                // cannot reset the game while a timeout is active!
@@ -614,8 +614,10 @@ void ClientCommand_voice(entity caller, float request, float argc, string comman
                                        sprint(caller, sprintf("Invalid voice. Use one of: %s\n", allvoicesamples));
                                        return;
                                }
-                               if (argc >= 3) VoiceMessage(caller, e, substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));
-                               else VoiceMessage(caller, e, "");
+                               string msg = "";
+                               if (argc >= 3)
+                                       msg = substring(command, argv_start_index(2), argv_end_index(-1) - argv_start_index(2));
+                               VoiceMessage(caller, e, msg);
 
                                return;
                        }
index 2f7467eab7bac87ff6191a004bac3c568d4efa70..db822eb71f7ea45e2536677da8f50aab4d071bcf 100644 (file)
@@ -391,7 +391,7 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                                                break;
                                        });
 
-                                       if (!found && arg_lower != "random") { print_to(caller, "Invalid monster"); return; }
+                                       if (!found && arg_lower != "random" && arg_lower != "anyrandom") { print_to(caller, "Invalid monster"); return; }
 
                                        totalspawned += 1;
                                        WarpZone_TraceBox(CENTER_OR_VIEWOFS(caller), caller.mins, caller.maxs, CENTER_OR_VIEWOFS(caller) + v_forward * 150, true, caller);
index 6c31af72c853d54cdef08fd5d723940efe6baecf..87bcef82f7124e1f001603129320b0684d46af5f 100644 (file)
@@ -4,7 +4,6 @@
 #include <common/command/_mod.qh>
 
 #include "../g_world.qh"
-#include "../g_subs.qh"
 
 #include <common/util.qh>
 
index 6de4507b1708ef54516d9d5db859bdb960a37457..2903f553543cf582c23eed087951ca29498010e5 100644 (file)
@@ -20,7 +20,8 @@
 
 #include "../bot/api.qh"
 
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
+#include <common/gamemodes/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
 
 #include <common/monsters/sv_monsters.qh>
 
-
-void PutObserverInServer(entity this);
-
-// =====================================================
-//  Server side game commands code, reworked by Samual
-// =====================================================
-
 //  used by GameCommand_make_mapinfo()
 void make_mapinfo_Think(entity this)
 {
@@ -1577,10 +1571,13 @@ void GameCommand_trace(float request, float argc)
                                        if (argc == 4 || argc == 5)
                                        {
                                                e = nextent(NULL);
+                                               int dphitcontentsmask_save = e.dphitcontentsmask;
+                                               e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
                                                if (tracewalk(e, stov(argv(2)), e.mins, e.maxs, stov(argv(3)), stof(argv(4)), MOVE_NORMAL))
                                                        LOG_INFO("can walk");
                                                else
                                                        LOG_INFO("cannot walk");
+                                               e.dphitcontentsmask = dphitcontentsmask_save;
                                                return;
                                        }
                                }
index 6d037473dd39907726f7eca7615610838f6b4f19..5f034f12f88534e9f644eeba88bed1351246ecb2 100644 (file)
@@ -14,7 +14,8 @@
 #include "../round_handler.qh"
 #include "../scores.qh"
 
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
+#include <common/gamemodes/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/net_linked.qh>
@@ -128,19 +129,15 @@ void VoteReset()
 
        if (vote_called)
        {
-               strunzone(vote_called_command);
-               strunzone(vote_called_display);
-               strunzone(vote_caller_name);
+               strfree(vote_called_command);
+               strfree(vote_called_display);
+               strfree(vote_caller_name);
        }
 
        vote_called = VOTE_NULL;
        vote_caller = NULL;
-       vote_caller_name = string_null;
        vote_endtime = 0;
 
-       vote_called_command = string_null;
-       vote_called_display = string_null;
-
        vote_parsed_command = string_null;
        vote_parsed_display = string_null;
 
@@ -660,6 +657,14 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
 
        if (!VoteCommand_checkargs(startpos, argc)) return 0;
 
+       switch (MUTATOR_CALLHOOK(VoteCommand_Parse, caller, first_command, vote_command, startpos, argc))
+       {
+               case MUT_VOTEPARSE_CONTINUE: { break; }
+               case MUT_VOTEPARSE_SUCCESS: { return 1; }
+               case MUT_VOTEPARSE_INVALID: { return -1; }
+               case MUT_VOTEPARSE_UNACCEPTABLE: { return 0; }
+       }
+
        switch (first_command) // now go through and parse the proper commands to adjust as needed.
        {
                case "kick":
index 7b10b37eb70bcf2a0e50a45fb105b14846d7b59c..d5c3bc0ad0e937d9569d1ec95cc539cd09c78897 100644 (file)
@@ -54,3 +54,4 @@ void reset_map(float dorespawn);
 void ReadyCount();
 void ReadyRestart_force();
 void VoteCount(float first_count);
+void Nagger_Init();
index a1e1294027e5adb10ba52117a407ff95983cfa67..85b063a68233d14afb17e33db69a658253125ddf 100644 (file)
@@ -4,10 +4,10 @@
 #include <server/miscfunctions.qh>
 #include <server/items.qh>
 #include <server/resources.qh>
+#include <common/t_items.qh>
+#include <common/mapobjects/triggers.qh>
 #include <common/weapons/_all.qh>
 
-spawnfunc(target_items);
-
 //***********************
 //QUAKE 3 ENTITIES - So people can play quake3 maps with the xonotic weapons
 //***********************
@@ -107,7 +107,7 @@ void target_init_use(entity this, entity actor, entity trigger)
                SetResourceAmount(actor, RESOURCE_PLASMA, start_ammo_plasma);
                SetResourceAmount(actor, RESOURCE_FUEL, start_ammo_fuel);
 
-               actor.weapons = start_weapons;
+               STAT(WEAPONS, actor) = start_weapons;
                if (this.spawnflags & 32)
                {
                        // TODO
index 6f70f09beec2219624baeca92e2cd7deaa104fb4..342a829a187b12daa84a0b532bc0269aca79c16b 100644 (file)
@@ -1 +1,3 @@
 #pragma once
+
+bool DoesQ3ARemoveThisEntity(entity this);
index 86ed86da1d9e7b73f77e2baa77a9f69a87265b40..f98d586fb504cf389b764fb704360713d5a2148f 100644 (file)
@@ -17,5 +17,3 @@ const int RESPAWN_DENY = 4;
 #define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT)
 
 const int NUM_PLAYERSKINS_TEAMPLAY = 3;
-
-const int ASSAULT_VALUE_INACTIVE = 1000;
index 4b600e3fceeab8743b14388eae44ba48c55c0d09..1db5dd0c5b637244ef97e3a68271975bd393b8d0 100644 (file)
@@ -7,7 +7,7 @@
 
 // Globals
 
-float g_footsteps, g_grappling_hook, g_instagib;
+float g_footsteps, g_grappling_hook;
 float g_warmup_allguns;
 float g_warmup_allow_timeout;
 float warmup_stage;
@@ -182,8 +182,6 @@ float default_weapon_alpha;
 
 string gamemode_name;
 
-float startitem_failed;
-
 string W_Apply_Weaponreplace(string in);
 
 void FixIntermissionClient(entity e);
@@ -192,8 +190,6 @@ void FixClientCvars(entity e);
 // WEAPONTODO: remove this
 //WepSet weaponsInMap;
 
-#define weapons _STAT(WEAPONS)
-
 .float respawn_countdown; // next number to count
 
 float bot_waypoints_for_items;
@@ -281,9 +277,6 @@ void W_Porto_Remove (entity p);
 // Nexball
 float g_nexball_meter_period;
 
-void SUB_DontUseTargets(entity this, entity actor, entity trigger);
-void SUB_UseTargets(entity this, entity actor, entity trigger);
-
 .void(entity this) reset; // if set, an entity is reset using this
 .void(entity this) reset2; // if set, an entity is reset using this (after calling ALL the reset functions for other entities)
 
@@ -325,6 +318,9 @@ float client_cefc_accumulatortime;
 .float vortex_charge;
 .float vortex_charge_rottime;
 .float vortex_chargepool_ammo;
+.float oknex_charge;
+.float oknex_charge_rottime;
+.float oknex_chargepool_ammo;
 .int hagar_load;
 
 .int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
@@ -408,67 +404,43 @@ const int MIF_GUIDED_CONFUSABLE = MIF_GUIDED_HEAT | MIF_GUIDED_AI;
 .WepSet dual_weapons;
 
 IntrusiveList g_monsters;
-STATIC_INIT(g_monsters) { g_monsters = IL_NEW(); }
-
 IntrusiveList g_waypoints;
-STATIC_INIT(g_waypoints) { g_waypoints = IL_NEW(); }
-
 IntrusiveList g_vehicles;
-STATIC_INIT(g_vehicles) { g_vehicles = IL_NEW(); }
-
 IntrusiveList g_turrets;
-STATIC_INIT(g_turrets) { g_turrets = IL_NEW(); }
-
 IntrusiveList g_mines;
-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(); }
-
 IntrusiveList g_damagedbycontents;
-STATIC_INIT(g_damagedbycontents) { g_damagedbycontents = IL_NEW(); }
-
 IntrusiveList g_railgunhit;
-STATIC_INIT(g_railgunhit) { g_railgunhit = IL_NEW(); }
-
 IntrusiveList g_ladders;
-STATIC_INIT(g_ladders) { g_ladders = IL_NEW(); }
-
 IntrusiveList g_locations;
-STATIC_INIT(g_locations) { g_locations = IL_NEW(); }
-
 IntrusiveList g_saved_team;
-STATIC_INIT(g_saved_team) { g_saved_team = IL_NEW(); }
-
 IntrusiveList g_monster_targets;
-STATIC_INIT(g_monster_targets) { g_monster_targets = IL_NEW(); }
-
 IntrusiveList g_pathlib_nodes;
-STATIC_INIT(g_pathlib_nodes) { g_pathlib_nodes = IL_NEW(); }
+STATIC_INIT(defs)
+{
+       g_monsters = IL_NEW();
+       g_waypoints = IL_NEW();
+       g_vehicles = IL_NEW();
+       g_turrets = IL_NEW();
+       g_mines = IL_NEW();
+       g_projectiles = IL_NEW();
+       g_items = IL_NEW();
+       g_initforplayer = IL_NEW();
+       g_clones = IL_NEW();
+       g_spawnpoints = IL_NEW();
+       g_bot_targets = IL_NEW();
+       g_bot_dodge = IL_NEW();
+       g_damagedbycontents = IL_NEW();
+       g_railgunhit = IL_NEW();
+       g_ladders = IL_NEW();
+       g_locations = IL_NEW();
+       g_saved_team = IL_NEW();
+       g_monster_targets = IL_NEW();
+       g_pathlib_nodes = IL_NEW();
+}
index c7a6f2cfb3b179d1452e9f0e88300192f61d722e..c2db32650dd851c363ca44ed123641dcdbf8d5d6 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/effects/all.qh>
 #include "bot/api.qh"
 #include "g_hook.qh"
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "scores.qh"
 #include "spawnpoints.qh"
 #include "../common/state.qh"
@@ -13,6 +13,8 @@
 #include "../common/vehicles/all.qh"
 #include "../common/items/_mod.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include "../common/mutators/mutator/buffs/buffs.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
@@ -23,6 +25,7 @@
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
 #include "../common/util.qh"
+#include <common/gamemodes/rules.qh>
 #include <common/weapons/_all.qh>
 #include "../lib/csqcmodel/sv_model.qh"
 #include "../lib/warpzone/common.qh"
@@ -60,51 +63,8 @@ void GiveFrags(entity attacker, entity targ, float f, int deathtype, .entity wea
 
        GameRules_scoring_add(targ, DEATHS, 1);
 
-       if(targ != attacker) // not for suicides
-       if(g_weaponarena_random)
-       {
-               // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon
-               Weapon culprit = DEATH_WEAPONOF(deathtype);
-               if(!culprit) culprit = attacker.(weaponentity).m_weapon;
-               else if(!(attacker.weapons & (culprit.m_wepset))) culprit = attacker.(weaponentity).m_weapon;
-
-               if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER) // WEAPONTODO: Shouldn't this be in a mutator?
-               {
-                       // no exchange
-               }
-               else
-               {
-                       if(!GiveFrags_randomweapons)
-                       {
-                               GiveFrags_randomweapons = new(GiveFrags_randomweapons);
-                       }
-
-                       if(warmup_stage)
-                               GiveFrags_randomweapons.weapons = WARMUP_START_WEAPONS;
-                       else
-                               GiveFrags_randomweapons.weapons = start_weapons;
-
-                       // all others (including the culprit): remove
-                       GiveFrags_randomweapons.weapons &= ~attacker.weapons;
-                       GiveFrags_randomweapons.weapons &= ~(culprit.m_wepset);
-
-                       // among the remaining ones, choose one by random
-                       W_RandomWeapons(GiveFrags_randomweapons, 1);
-
-                       if(GiveFrags_randomweapons.weapons)
-                       {
-                               attacker.weapons |= GiveFrags_randomweapons.weapons;
-                               attacker.weapons &= ~(culprit.m_wepset);
-                       }
-               }
-
-               // after a frag, choose another random weapon set
-               if (!(attacker.weapons & WepSet_FromWeapon(attacker.(weaponentity).m_weapon)))
-                       W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker, weaponentity), weaponentity);
-       }
-
        // FIXME fix the mess this is (we have REAL points now!)
-       if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f))
+       if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f, deathtype, attacker.(weaponentity)))
                f = M_ARGV(2, float);
 
        attacker.totalfrags += f;
@@ -262,7 +222,6 @@ bool frag_centermessage_override(entity attacker, entity targ, int deathtype, in
        return MUTATOR_CALLHOOK(FragCenterMessage, attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target);
 }
 
-entity buff_FirstFromFlags(int _buffs);
 void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity)
 {
        // Sanity check
@@ -713,7 +672,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                }
 
                // should this be changed at all? If so, in what way?
-               MUTATOR_CALLHOOK(Damage_Calculate, inflictor, attacker, targ, deathtype, damage, mirrordamage, force);
+               MUTATOR_CALLHOOK(Damage_Calculate, inflictor, attacker, targ, deathtype, damage, mirrordamage, force, attacker.(weaponentity));
                damage = M_ARGV(4, float);
                mirrordamage = M_ARGV(5, float);
                force = M_ARGV(6, vector);
@@ -779,7 +738,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
                        }
                }
 
-               if(!g_instagib)
+               if(!MUTATOR_IS_ENABLED(mutator_instagib))
                {
                        // apply strength multiplier
                        if (attacker.items & ITEM_Strength.m_itemid)
@@ -907,7 +866,7 @@ void Damage(entity targ, entity inflictor, entity attacker, float damage, int de
        }
 }
 
-float RadiusDamageForSource(entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
                                                                float inflictorselfdamage, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
        // Returns total damage applies to creatures
 {
index 4f68c2ea00a4d55ff06fa50c6a3d71e8df6c863e..9ab817853b0754a5ead77fccd73ff8cd16624eb0 100644 (file)
@@ -19,7 +19,7 @@
     #include "defs.qh"
     #include <common/notifications/all.qh>
     #include <common/deathtypes/all.qh>
-    #include "mutators/_mod.qh"
+    #include <server/mutators/_mod.qh>
     #include <common/turrets/sv_turrets.qh>
     #include <common/vehicles/all.qh>
     #include <lib/csqcmodel/sv_model.qh>
@@ -58,7 +58,6 @@ void UpdateFrags(entity player, int f);
 
 // NOTE: f=0 means still count as a (positive) kill, but count no frags for it
 void W_SwitchWeapon_Force(Player this, Weapon w, .entity weaponentity);
-entity GiveFrags_randomweapons;
 void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity);
 
 string AppendItemcodes(string s, entity player);
index 0d732e0ca4b6daba40fc5b33db54ade2db1c7501..09135d4827913c2f13229356f9f6bba604cb486f 100644 (file)
@@ -110,7 +110,6 @@ void GrapplingHookReset(entity this)
        RemoveHook(this);
 }
 
-void GrapplingHookThink(entity this);
 void GrapplingHook_Stop(entity this)
 {
        Send_Effect(EFFECT_HOOK_IMPACT, this.origin, '0 0 0', 1);
index 719bf5b605bdbfc1832761610f0f0ac8a3c88670..c0df31662a7d5cea6c95584dd7a13bfd7d969dad 100644 (file)
@@ -2,6 +2,7 @@
 
 // Wazat's grappling hook
 .entity                hook;
+void GrapplingHookThink(entity this);
 void RemoveGrapplingHooks(entity pl);
 void RemoveHook(entity this);
 // (note: you can change the hook impulse #'s to whatever you please)
diff --git a/qcsrc/server/g_lights.qc b/qcsrc/server/g_lights.qc
deleted file mode 100644 (file)
index 852f1ef..0000000
+++ /dev/null
@@ -1,135 +0,0 @@
-#include "g_lights.qh"
-
-#include <server/defs.qh>
-#include <server/miscfunctions.qh>
-
-void train_next(entity this);
-
-const float LOOP = 1;
-
-.float speed;
-
-const float DNOSHADOW = 2;
-const float DFOLLOW = 4;
-.float light_lev;
-.float lefty;
-.vector color;
-.string dtagname;
-
-/*QUAKED dynlight (0 1 0) (-8 -8 -8) (8 8 8) START_OFF NOSHADOW FOLLOW
-Dynamic spawnfunc_light.
-Can do one of these things: sit still and be just a silly spawnfunc_light, travel along a path, follow an entity around, attach to a tag on an entity.
-It can spin around it's own axis in all the above cases.
-If targeted, it will toggle between on or off.
-keys:
-"light_lev" spawnfunc_light radius, default 200
-"color" spawnfunc_light color in rgb and brightness, 1 1 1 produces bright white, up to 255 255 255 (nuclear blast), recommended values up to 1 1 1, default 1 1 1
-"style" lightstyle, same as for static lights
-"angles" initial orientation
-"avelocity" a vector value, the direction and speed it rotates in
-"skin" cubemap number, must be 16 or above
-"dtagname" will attach to this tag on the entity which "targetname" matches "target". If the "target" is either not an md3 model or is missing tags, it will attach to the targets origin. Note that the "target" must be visible to the spawnfunc_light
-"targetname" will toggle on and off when triggered
-"target" if issued with a target, preferrably spawnfunc_path_corner, it will move along the path. If also issued with the FOLLOW spawnflag, then this is the entity it will follow. If issued with the "tagname" key it will attach it to this targets tag called "tagname", does not work together with FOLLOW or path movement
-"speed" the speed it will travel along the path, default 100
-flags:
-"START_OFF" spawnfunc_light will be in off state until targeted
-"NOSHADOW" will not cast shadows in realtime lighting mode
-"FOLLOW" will follow the entity which "targetname" matches "target"
-*/
-void dynlight_think(entity this)
-{
-       if(!this.owner)
-               delete(this);
-
-       this.nextthink = time + 0.1;
-}
-void dynlight_find_aiment(entity this)
-{
-       entity targ;
-       if (!this.target)
-               objerror (this, "dynlight: no target to follow");
-
-       targ = find(NULL, targetname, this.target);
-       set_movetype(this, MOVETYPE_FOLLOW);
-       this.aiment = targ;
-       this.owner = targ;
-       this.punchangle = targ.angles;
-       this.view_ofs = this.origin - targ.origin;
-       this.v_angle = this.angles - targ.angles;
-       setthink(this, dynlight_think);
-       this.nextthink = time + 0.1;
-}
-void dynlight_find_path(entity this)
-{
-       entity targ;
-       if (!this.target)
-               objerror (this, "dynlight: no target to follow");
-
-       targ = find(NULL, targetname, this.target);
-       this.target = targ.target;
-       setorigin(this, targ.origin);
-       setthink(this, train_next);
-       this.nextthink = time + 0.1;
-}
-void dynlight_find_target(entity this)
-{
-       entity targ;
-       if (!this.target)
-               objerror (this, "dynlight: no target to follow");
-
-       targ = find(NULL, targetname, this.target);
-       setattachment(this, targ, this.dtagname);
-       this.owner = targ;
-       setthink(this, dynlight_think);
-       this.nextthink = time + 0.1;
-}
-void dynlight_use(entity this, entity actor, entity trigger)
-{
-       if (this.light_lev == 0)
-               this.light_lev = this.lefty;
-       else
-               this.light_lev = 0;
-}
-spawnfunc(dynlight)
-{
-       if (!this.light_lev)
-               this.light_lev = 200;
-       if (!this.color)
-               this.color = '1 1 1';
-       this.lefty = this.light_lev;
-       this.use = dynlight_use;
-       setsize (this, '0 0 0', '0 0 0');
-       setorigin(this, this.origin);
-       //this.pflags = PFLAGS_FULLDYNAMIC;
-       this.solid = SOLID_NOT;
-       //this.blocked = func_null;
-       //if (this.spawnflags & DNOSHADOW)
-       //      this.pflags = this.pflags + PFLAGS_NOSHADOW;
-       //if (this.spawnflags & START_OFF)
-       //      this.light_lev = 0;
-
-//tag attaching
-       if (this.dtagname)
-       {
-               InitializeEntity(this, dynlight_find_target, INITPRIO_FINDTARGET);
-               return;
-       }
-
-// entity following
-       if (this.spawnflags & DFOLLOW)
-       {
-               InitializeEntity(this, dynlight_find_aiment, INITPRIO_FINDTARGET);
-               return;
-       }
-// path following
-       if (this.target)
-//     if (!(this.spawnflags & DFOLLOW))
-       {
-               set_movetype(this, MOVETYPE_NOCLIP);
-               if (!this.speed)
-                       this.speed = 100;
-               InitializeEntity(this, dynlight_find_path, INITPRIO_FINDTARGET);
-               return;
-       }
-}
diff --git a/qcsrc/server/g_lights.qh b/qcsrc/server/g_lights.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/server/g_models.qc b/qcsrc/server/g_models.qc
deleted file mode 100644 (file)
index 1026e3a..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-#include "g_models.qh"
-
-#include <server/defs.qh>
-#include <server/miscfunctions.qh>
-#include "g_subs.qh"
-#include <common/net_linked.qh>
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/triggers.qh"
-
-entityclass(BGMScript);
-class(BGMScript) .string bgmscript;
-class(BGMScript) .float bgmscriptattack;
-class(BGMScript) .float bgmscriptdecay;
-class(BGMScript) .float bgmscriptsustain;
-class(BGMScript) .float bgmscriptrelease;
-
-#include "../common/constants.qh"
-#include "../lib/csqcmodel/sv_model.qh"
-
-.float modelscale;
-
-void g_model_setcolormaptoactivator(entity this, entity actor, entity trigger)
-{
-       if(teamplay)
-       {
-               if(actor.team)
-                       this.colormap = (actor.team - 1) * 0x11;
-               else
-                       this.colormap = 0x00;
-       }
-       else
-               this.colormap = floor(random() * 256);
-       this.colormap |= BIT(10); // RENDER_COLORMAPPED
-}
-
-void g_clientmodel_setcolormaptoactivator(entity this, entity actor, entity trigger)
-{
-       g_model_setcolormaptoactivator(this, actor, trigger);
-       this.SendFlags |= (BIT(3) | BIT(0));
-}
-
-void g_clientmodel_use(entity this, entity actor, entity trigger)
-{
-       if (this.antiwall_flag == 1)
-       {
-               this.inactive = 1;
-               this.solid = SOLID_NOT;
-       }
-       else if (this.antiwall_flag == 2)
-       {
-               this.inactive = 0;
-               this.solid = this.default_solid;
-       }
-       g_clientmodel_setcolormaptoactivator(this, actor, trigger);
-}
-
-void g_model_dropbyspawnflags(entity this)
-{
-       if((this.spawnflags & 3) == 1) // ALIGN_ORIGIN
-       {
-               traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
-               setorigin(this, trace_endpos);
-       }
-       else if((this.spawnflags & 3) == 2) // ALIGN_BOTTOM
-       {
-               tracebox(this.origin, this.mins, this.maxs, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
-               setorigin(this, trace_endpos);
-       }
-       else if((this.spawnflags & 3) == 3) // ALIGN_ORIGIN | ALIGN_BOTTOM
-       {
-               traceline(this.origin, this.origin - '0 0 4096', MOVE_NOMONSTERS, this);
-               setorigin(this, trace_endpos - '0 0 1' * this.mins.z);
-       }
-}
-
-void g_clientmodel_dropbyspawnflags(entity this)
-{
-       vector o0;
-       o0 = this.origin;
-       g_model_dropbyspawnflags(this);
-       if(this.origin != o0)
-               this.SendFlags |= 2;
-}
-
-bool g_clientmodel_genericsendentity(entity this, entity to, int sf)
-{
-       sf = sf & 0x0F;
-       if(this.angles != '0 0 0')
-               sf |= 0x10;
-       if(this.mins != '0 0 0' || this.maxs != '0 0 0')
-               sf |= 0x20;
-       if(this.colormap != 0)
-               sf |= 0x40;
-       if(this.lodmodelindex1)
-               sf |= 0x80;
-
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_WALL);
-       WriteByte(MSG_ENTITY, sf);
-
-       if(sf & BIT(0))
-       {
-               if(sf & 0x40)
-                       WriteShort(MSG_ENTITY, this.colormap);
-               WriteByte(MSG_ENTITY, this.skin);
-       }
-
-       if(sf & BIT(1))
-       {
-               WriteVector(MSG_ENTITY, this.origin);
-       }
-
-       if(sf & BIT(2))
-       {
-               if(sf & 0x10)
-               {
-                       WriteAngle(MSG_ENTITY, this.angles.x);
-                       WriteAngle(MSG_ENTITY, this.angles.y);
-                       WriteAngle(MSG_ENTITY, this.angles.z);
-               }
-       }
-
-       if(sf & BIT(3))
-       {
-               if(sf & 0x80)
-               {
-                       WriteShort(MSG_ENTITY, this.lodmodelindex0);
-                       WriteShort(MSG_ENTITY, bound(0, this.loddistance1, 65535));
-                       WriteShort(MSG_ENTITY, this.lodmodelindex1);
-                       WriteShort(MSG_ENTITY, bound(0, this.loddistance2, 65535));
-                       WriteShort(MSG_ENTITY, this.lodmodelindex2);
-               }
-               else
-                       WriteShort(MSG_ENTITY, this.modelindex);
-               WriteByte(MSG_ENTITY, this.solid);
-               WriteShort(MSG_ENTITY, floor(this.scale * 256));
-               if(sf & 0x20)
-               {
-                       WriteVector(MSG_ENTITY, this.mins);
-                       WriteVector(MSG_ENTITY, this.maxs);
-               }
-               WriteString(MSG_ENTITY, this.bgmscript);
-               if(this.bgmscript != "")
-               {
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
-                       WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
-                       WriteVector(MSG_ENTITY, this.movedir);
-                       WriteByte(MSG_ENTITY, floor(this.lip * 255));
-               }
-               WriteByte(MSG_ENTITY, this.fade_start);
-               WriteByte(MSG_ENTITY, this.fade_end);
-               WriteByte(MSG_ENTITY, this.alpha_max);
-               WriteByte(MSG_ENTITY, this.alpha_min);
-               WriteByte(MSG_ENTITY, this.inactive);
-               WriteShort(MSG_ENTITY, this.fade_vertical_offset);
-       }
-
-       return true;
-}
-
-
-#define G_MODEL_INIT(ent,sol) \
-       if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
-       if(!ent.scale) ent.scale = ent.modelscale; \
-       SetBrushEntityModel(ent); \
-       ent.use = g_model_setcolormaptoactivator; \
-       InitializeEntity(ent, g_model_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
-       if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT;
-
-#define G_CLIENTMODEL_INIT(ent,sol) \
-       if(ent.geomtype) if(autocvar_physics_ode && checkextension("DP_PHYSICS_ODE")) set_movetype(ent, MOVETYPE_PHYSICS); \
-       if(!ent.scale) ent.scale = ent.modelscale; \
-       SetBrushEntityModel(ent); \
-       ent.use = g_clientmodel_use; \
-       InitializeEntity(ent, g_clientmodel_dropbyspawnflags, INITPRIO_DROPTOFLOOR); \
-       if(!ent.solid) ent.solid = (sol); else if(ent.solid < 0) ent.solid = SOLID_NOT; \
-       if(!ent.bgmscriptsustain) ent.bgmscriptsustain = 1; else if(ent.bgmscriptsustain < 0) ent.bgmscriptsustain = 0; \
-       Net_LinkEntity(ent, true, 0, g_clientmodel_genericsendentity); \
-       ent.default_solid = sol;
-
-// non-solid model entities:
-spawnfunc(misc_gamemodel)         { this.angles_x = -this.angles.x; G_MODEL_INIT      (this, SOLID_NOT) } // model entity
-spawnfunc(misc_clientmodel)       { this.angles_x = -this.angles.x; G_CLIENTMODEL_INIT(this, SOLID_NOT) } // model entity
-spawnfunc(misc_models)            { this.angles_x = -this.angles.x; G_MODEL_INIT      (this, SOLID_NOT) } // DEPRECATED old compat entity with confusing name, do not use
-
-// non-solid brush entities:
-spawnfunc(func_illusionary)       { G_MODEL_INIT      (this, SOLID_NOT) } // Q1 name (WARNING: MISPREDICTED)
-spawnfunc(func_clientillusionary) { G_CLIENTMODEL_INIT(this, SOLID_NOT) } // brush entity
-spawnfunc(func_static)            { G_MODEL_INIT      (this, SOLID_NOT) } // DEPRECATED old alias name from some other game
-
-// solid brush entities
-spawnfunc(func_wall)              { G_MODEL_INIT      (this, SOLID_BSP) } // Q1 name
-spawnfunc(func_clientwall)        { G_CLIENTMODEL_INIT(this, SOLID_BSP) } // brush entity (WARNING: MISPREDICTED)
diff --git a/qcsrc/server/g_models.qh b/qcsrc/server/g_models.qh
deleted file mode 100644 (file)
index 6f70f09..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#pragma once
diff --git a/qcsrc/server/g_subs.qc b/qcsrc/server/g_subs.qc
deleted file mode 100644 (file)
index d9372e0..0000000
+++ /dev/null
@@ -1,439 +0,0 @@
-#include "g_subs.qh"
-
-#include <server/defs.qh>
-#include <server/miscfunctions.qh>
-#include "antilag.qh"
-#include "command/common.qh"
-#include "../common/state.qh"
-#include "../lib/warpzone/common.qh"
-#include "../common/triggers/subs.qh"
-
-spawnfunc(info_null)
-{
-       delete(this);
-       // if anything breaks, tell the mapper to fix his map! info_null is meant to remove itself immediately.
-}
-
-/*
-==================
-main
-
-unused but required by the engine
-==================
-*/
-void main ()
-{
-
-}
-
-// Misc
-
-/*
-==================
-traceline_antilag
-
-A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
-Additionally it moves players back into the past before the trace and restores them afterward.
-==================
-*/
-void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz)
-{
-       // check whether antilagged traces are enabled
-       if (lag < 0.001)
-               lag = 0;
-       if (!IS_REAL_CLIENT(forent))
-               lag = 0; // only antilag for clients
-
-       // change shooter to SOLID_BBOX so the shot can hit corpses
-       int oldsolid = source.dphitcontentsmask;
-       if(source)
-               source.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
-
-       if (lag)
-               antilag_takeback_all(forent, lag);
-
-       // do the trace
-       if(wz)
-               WarpZone_TraceBox (v1, mi, ma, v2, nomonst, forent);
-       else
-               tracebox (v1, mi, ma, v2, nomonst, forent);
-
-       // restore players to current positions
-       if (lag)
-               antilag_restore_all(forent);
-
-       // restore shooter solid type
-       if(source)
-               source.dphitcontentsmask = oldsolid;
-}
-void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
-{
-       tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, false);
-}
-void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
-{
-       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
-       if (autocvar_g_antilag != 2 || noantilag)
-               lag = 0;
-       traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
-}
-void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
-{
-       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
-       if (autocvar_g_antilag != 2 || noantilag)
-               lag = 0;
-       tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, false);
-}
-void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
-{
-       tracebox_antilag_force_wz(source, v1, '0 0 0', '0 0 0', v2, nomonst, forent, lag, true);
-}
-void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag)
-{
-       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
-       if (autocvar_g_antilag != 2 || noantilag)
-               lag = 0;
-       WarpZone_traceline_antilag_force(source, v1, v2, nomonst, forent, lag);
-}
-void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag)
-{
-       bool noantilag = ((IS_CLIENT(source)) ? CS(source).cvar_cl_noantilag : false);
-       if (autocvar_g_antilag != 2 || noantilag)
-               lag = 0;
-       tracebox_antilag_force_wz(source, v1, mi, ma, v2, nomonst, forent, lag, true);
-}
-
-float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity) // returns the number of traces done, for benchmarking
-{
-       vector pos, dir, t;
-       float nudge;
-       entity stopentity;
-
-       //nudge = 2 * cvar("collision_impactnudge"); // why not?
-       nudge = 0.5;
-
-       dir = normalize(v2 - v1);
-
-       pos = v1 + dir * nudge;
-
-       float c;
-       c = 0;
-
-       for (;;)
-       {
-               if(pos * dir >= v2 * dir)
-               {
-                       // went too far
-                       trace_fraction = 1;
-                       trace_endpos = v2;
-                       return c;
-               }
-
-               tracebox(pos, mi, ma, v2, nomonsters, forent);
-               ++c;
-
-               if(c == 50)
-               {
-                       LOG_TRACE("HOLY SHIT! When tracing from ", vtos(v1), " to ", vtos(v2));
-                       LOG_TRACE("  Nudging gets us nowhere at ", vtos(pos));
-                       LOG_TRACE("  trace_endpos is ", vtos(trace_endpos));
-                       LOG_TRACE("  trace distance is ", ftos(vlen(pos - trace_endpos)));
-               }
-
-               stopentity = trace_ent;
-
-               if(trace_startsolid)
-               {
-                       // we started inside solid.
-                       // then trace from endpos to pos
-                       t = trace_endpos;
-                       tracebox(t, mi, ma, pos, nomonsters, forent);
-                       ++c;
-                       if(trace_startsolid)
-                       {
-                               // t is still inside solid? bad
-                               // force advance, then, and retry
-                               pos = t + dir * nudge;
-
-                               // but if we hit an entity, stop RIGHT before it
-                               if(stopatentity && stopentity && stopentity != ignorestopatentity)
-                               {
-                                       trace_ent = stopentity;
-                                       trace_endpos = t;
-                                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
-                                       return c;
-                               }
-                       }
-                       else
-                       {
-                               // we actually LEFT solid!
-                               trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
-                               return c;
-                       }
-               }
-               else
-               {
-                       // pos is outside solid?!? but why?!? never mind, just return it.
-                       trace_endpos = pos;
-                       trace_fraction = ((trace_endpos - v1) * dir) / ((v2 - v1) * dir);
-                       return c;
-               }
-       }
-}
-
-void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity)
-{
-       tracebox_inverted(v1, '0 0 0', '0 0 0', v2, nomonsters, forent, stopatentity, ignorestopatentity);
-}
-
-/*
-==================
-findbetterlocation
-
-Returns a point at least 12 units away from walls
-(useful for explosion animations, although the blast is performed where it really happened)
-Ripped from DPMod
-==================
-*/
-vector findbetterlocation (vector org, float mindist)
-{
-       vector vec = mindist * '1 0 0';
-       int c = 0;
-       while (c < 6)
-       {
-               traceline (org, org + vec, true, NULL);
-               vec = vec * -1;
-               if (trace_fraction < 1)
-               {
-                       vector loc = trace_endpos;
-                       traceline (loc, loc + vec, true, NULL);
-                       if (trace_fraction >= 1)
-                               org = loc + vec;
-               }
-               if (c & 1)
-               {
-                       float h = vec.y;
-                       vec.y = vec.x;
-                       vec.x = vec.z;
-                       vec.z = h;
-               }
-               c = c + 1;
-       }
-
-       return org;
-}
-
-bool LOD_customize(entity this, entity client)
-{
-       if(autocvar_loddebug)
-       {
-               int d = autocvar_loddebug;
-               if(d == 1)
-                       this.modelindex = this.lodmodelindex0;
-               else if(d == 2 || !this.lodmodelindex2)
-                       this.modelindex = this.lodmodelindex1;
-               else // if(d == 3)
-                       this.modelindex = this.lodmodelindex2;
-               return true;
-       }
-
-       // TODO csqc network this so it only gets sent once
-       vector near_point = NearestPointOnBox(this, client.origin);
-       if(vdist(near_point - client.origin, <, this.loddistance1))
-               this.modelindex = this.lodmodelindex0;
-       else if(!this.lodmodelindex2 || vdist(near_point - client.origin, <, this.loddistance2))
-               this.modelindex = this.lodmodelindex1;
-       else
-               this.modelindex = this.lodmodelindex2;
-
-       return true;
-}
-
-void LOD_uncustomize(entity this)
-{
-       this.modelindex = this.lodmodelindex0;
-}
-
-void LODmodel_attach(entity this)
-{
-       entity e;
-
-       if(!this.loddistance1)
-               this.loddistance1 = 1000;
-       if(!this.loddistance2)
-               this.loddistance2 = 2000;
-       this.lodmodelindex0 = this.modelindex;
-
-       if(this.lodtarget1 != "")
-       {
-               e = find(NULL, targetname, this.lodtarget1);
-               if(e)
-               {
-                       this.lodmodel1 = e.model;
-                       delete(e);
-               }
-       }
-       if(this.lodtarget2 != "")
-       {
-               e = find(NULL, targetname, this.lodtarget2);
-               if(e)
-               {
-                       this.lodmodel2 = e.model;
-                       delete(e);
-               }
-       }
-
-       if(autocvar_loddebug < 0)
-       {
-               this.lodmodel1 = this.lodmodel2 = ""; // don't even initialize
-       }
-
-       if(this.lodmodel1 != "")
-       {
-               vector mi, ma;
-               mi = this.mins;
-               ma = this.maxs;
-
-               precache_model(this.lodmodel1);
-               _setmodel(this, this.lodmodel1);
-               this.lodmodelindex1 = this.modelindex;
-
-               if(this.lodmodel2 != "")
-               {
-                       precache_model(this.lodmodel2);
-                       _setmodel(this, this.lodmodel2);
-                       this.lodmodelindex2 = this.modelindex;
-               }
-
-               this.modelindex = this.lodmodelindex0;
-               setsize(this, mi, ma);
-       }
-
-       if(this.lodmodelindex1)
-               if (!getSendEntity(this))
-                       SetCustomizer(this, LOD_customize, LOD_uncustomize);
-}
-
-void ApplyMinMaxScaleAngles(entity e)
-{
-       if(e.angles.x != 0 || e.angles.z != 0 || e.avelocity.x != 0 || e.avelocity.z != 0) // "weird" rotation
-       {
-               e.maxs = '1 1 1' * vlen(
-                       '1 0 0' * max(-e.mins.x, e.maxs.x) +
-                       '0 1 0' * max(-e.mins.y, e.maxs.y) +
-                       '0 0 1' * max(-e.mins.z, e.maxs.z)
-               );
-               e.mins = -e.maxs;
-       }
-       else if(e.angles.y != 0 || e.avelocity.y != 0) // yaw only is a bit better
-       {
-               e.maxs_x = vlen(
-                       '1 0 0' * max(-e.mins.x, e.maxs.x) +
-                       '0 1 0' * max(-e.mins.y, e.maxs.y)
-               );
-               e.maxs_y = e.maxs.x;
-               e.mins_x = -e.maxs.x;
-               e.mins_y = -e.maxs.x;
-       }
-       if(e.scale)
-               setsize(e, e.mins * e.scale, e.maxs * e.scale);
-       else
-               setsize(e, e.mins, e.maxs);
-}
-
-void SetBrushEntityModel(entity this)
-{
-       if(this.model != "")
-       {
-               precache_model(this.model);
-               if(this.mins != '0 0 0' || this.maxs != '0 0 0')
-               {
-                       vector mi = this.mins;
-                       vector ma = this.maxs;
-                       _setmodel(this, this.model); // no precision needed
-                       setsize(this, mi, ma);
-               }
-               else
-                       _setmodel(this, this.model); // no precision needed
-               InitializeEntity(this, LODmodel_attach, INITPRIO_FINDTARGET);
-       }
-       setorigin(this, this.origin);
-       ApplyMinMaxScaleAngles(this);
-}
-
-void SetBrushEntityModelNoLOD(entity this)
-{
-       if(this.model != "")
-       {
-               precache_model(this.model);
-               if(this.mins != '0 0 0' || this.maxs != '0 0 0')
-               {
-                       vector mi = this.mins;
-                       vector ma = this.maxs;
-                       _setmodel(this, this.model); // no precision needed
-                       setsize(this, mi, ma);
-               }
-               else
-                       _setmodel(this, this.model); // no precision needed
-       }
-       setorigin(this, this.origin);
-       ApplyMinMaxScaleAngles(this);
-}
-
-/*
-================
-InitTrigger
-================
-*/
-
-void SetMovedir(entity this)
-{
-       if(this.movedir != '0 0 0')
-               this.movedir = normalize(this.movedir);
-       else
-       {
-               makevectors(this.angles);
-               this.movedir = v_forward;
-       }
-
-       this.angles = '0 0 0';
-}
-
-void InitTrigger(entity this)
-{
-// trigger angles are used for one-way touches.  An angle of 0 is assumed
-// to mean no restrictions, so use a yaw of 360 instead.
-       SetMovedir(this);
-       this.solid = SOLID_TRIGGER;
-       SetBrushEntityModel(this);
-       set_movetype(this, MOVETYPE_NONE);
-       this.modelindex = 0;
-       this.model = "";
-}
-
-void InitSolidBSPTrigger(entity this)
-{
-// trigger angles are used for one-way touches.  An angle of 0 is assumed
-// to mean no restrictions, so use a yaw of 360 instead.
-       SetMovedir(this);
-       this.solid = SOLID_BSP;
-       SetBrushEntityModel(this);
-       set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
-//     this.modelindex = 0;
-       this.model = "";
-}
-
-bool InitMovingBrushTrigger(entity this)
-{
-// trigger angles are used for one-way touches.  An angle of 0 is assumed
-// to mean no restrictions, so use a yaw of 360 instead.
-       this.solid = SOLID_BSP;
-       SetBrushEntityModel(this);
-       set_movetype(this, MOVETYPE_PUSH);
-       if(this.modelindex == 0)
-       {
-               objerror(this, "InitMovingBrushTrigger: no brushes found!");
-               return false;
-       }
-       return true;
-}
diff --git a/qcsrc/server/g_subs.qh b/qcsrc/server/g_subs.qh
deleted file mode 100644 (file)
index 1f5537c..0000000
+++ /dev/null
@@ -1,165 +0,0 @@
-#pragma once
-
-void SUB_NullThink(entity this);
-
-void SUB_CalcMoveDone(entity this);
-void SUB_CalcAngleMoveDone(entity this);
-
-spawnfunc(info_null);
-
-/*
-==================
-SUB_Friction
-
-Applies some friction to this
-==================
-*/
-.float friction;
-void SUB_Friction (entity this);
-
-/*
-==================
-SUB_VanishOrRemove
-
-Makes client invisible or removes non-client
-==================
-*/
-void SUB_VanishOrRemove (entity ent);
-
-void SUB_SetFade_Think (entity this);
-
-/*
-==================
-SUB_SetFade
-
-Fade 'ent' out when time >= 'when'
-==================
-*/
-void SUB_SetFade (entity ent, float when, float fadetime);
-
-/*
-=============
-SUB_CalcMove
-
-calculate this.velocity and this.nextthink to reach dest from
-this.origin traveling at speed
-===============
-*/
-void SUB_CalcMoveDone(entity this);
-
-.float platmovetype_turn;
-void SUB_CalcMove_controller_think (entity this);
-
-void SUB_CalcMove_controller_setbezier (entity controller, vector org, vector control, vector dest);
-
-void SUB_CalcMove_controller_setlinear (entity controller, vector org, vector dest);
-
-void SUB_CalcMove_Bezier (entity this, vector tcontrol, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
-
-void SUB_CalcMove (entity this, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
-
-void SUB_CalcMoveEnt (entity ent, vector tdest, float tspeedtype, float tspeed, void(entity this) func);
-
-/*
-=============
-SUB_CalcAngleMove
-
-calculate this.avelocity and this.nextthink to reach destangle from
-this.angles rotating
-
-The calling function should make sure this.think is valid
-===============
-*/
-void SUB_CalcAngleMoveDone (entity this);
-
-// FIXME: I fixed this function only for rotation around the main axes
-void SUB_CalcAngleMove (entity this, vector destangle, float tspeedtype, float tspeed, void(entity this) func);
-
-void SUB_CalcAngleMoveEnt (entity ent, vector destangle, float tspeedtype, float tspeed, void(entity this) func);
-
-/*
-==================
-main
-
-unused but required by the engine
-==================
-*/
-void main ();
-
-// Misc
-
-/*
-==================
-traceline_antilag
-
-A version of traceline that must be used by SOLID_SLIDEBOX things that want to hit SOLID_CORPSE things with a trace attack
-Additionally it moves players back into the past before the trace and restores them afterward.
-==================
-*/
-void tracebox_antilag_force_wz (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag, float wz);
-void traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
-void traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
-void tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag);
-void WarpZone_traceline_antilag_force (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
-void WarpZone_traceline_antilag (entity source, vector v1, vector v2, float nomonst, entity forent, float lag);
-void WarpZone_tracebox_antilag (entity source, vector v1, vector mi, vector ma, vector v2, float nomonst, entity forent, float lag);
-
-float tracebox_inverted (vector v1, vector mi, vector ma, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity); // returns the number of traces done, for benchmarking
-
-void traceline_inverted (vector v1, vector v2, float nomonsters, entity forent, float stopatentity, entity ignorestopatentity);
-
-/*
-==================
-findbetterlocation
-
-Returns a point at least 12 units away from walls
-(useful for explosion animations, although the blast is performed where it really happened)
-Ripped from DPMod
-==================
-*/
-vector findbetterlocation (vector org, float mindist);
-
-/*
-==================
-Angc used for animations
-==================
-*/
-
-
-float angc (float a1, float a2);
-
-.string lodtarget1;
-.string lodtarget2;
-.string lodmodel1;
-.string lodmodel2;
-.float lodmodelindex0;
-.float lodmodelindex1;
-.float lodmodelindex2;
-.float loddistance1;
-.float loddistance2;
-
-bool LOD_customize(entity this, entity client);
-
-void LOD_uncustomize(entity this);
-
-void LODmodel_attach(entity this);
-
-void ApplyMinMaxScaleAngles(entity e);
-
-void SetBrushEntityModel(entity this);
-
-void SetBrushEntityModelNoLOD(entity this);
-
-/*
-================
-InitTrigger
-================
-*/
-
-void SetMovedir(entity this);
-
-void InitTrigger(entity this);
-
-void InitSolidBSPTrigger(entity this);
-
-bool InitMovingBrushTrigger(entity this);
index a3bb6eb216e8677b4ae7add94f76dbee46188034..0b800946813cd26f8a33ad1319897cfda8c4c3af 100644 (file)
@@ -13,7 +13,7 @@
 #include "g_hook.qh"
 #include "ipban.qh"
 #include "mapvoting.qh"
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "race.qh"
 #include "scores.qh"
 #include "teamplay.qh"
@@ -21,6 +21,7 @@
 #include "../common/constants.qh"
 #include <common/net_linked.qh>
 #include "../common/deathtypes/all.qh"
+#include "../common/gamemodes/sv_rules.qh"
 #include "../common/mapinfo.qh"
 #include "../common/monsters/_mod.qh"
 #include "../common/monsters/sv_monsters.qh"
@@ -30,8 +31,8 @@
 #include "../common/playerstats.qh"
 #include "../common/stats.qh"
 #include "../common/teams.qh"
-#include "../common/triggers/trigger/secret.qh"
-#include "../common/triggers/target/music.qh"
+#include "../common/mapobjects/trigger/secret.qh"
+#include "../common/mapobjects/target/music.qh"
 #include "../common/util.qh"
 #include "../common/items/_mod.qh"
 #include <common/weapons/_all.qh>
@@ -91,9 +92,6 @@ const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS = 1;
 string redirection_target;
 float world_initialized;
 
-string GetGametype();
-void ShuffleMaplist();
-
 void SetDefaultAlpha()
 {
        if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
@@ -145,12 +143,8 @@ void cvar_changes_init()
        string k, v, d;
        float n, i, adding, pureadding;
 
-       if(cvar_changes)
-               strunzone(cvar_changes);
-       cvar_changes = string_null;
-       if(cvar_purechanges)
-               strunzone(cvar_purechanges);
-       cvar_purechanges = string_null;
+       strfree(cvar_changes);
+       strfree(cvar_purechanges);
        cvar_purechanges_count = 0;
 
        h = buf_create();
@@ -253,6 +247,7 @@ void cvar_changes_init()
                // these can contain player IDs, so better hide
                BADPREFIX("g_forced_team_");
                BADCVAR("sv_muteban_list");
+               BADCVAR("sv_voteban_list");
                BADCVAR("sv_allow_customplayermodels_idlist");
                BADCVAR("sv_allow_customplayermodels_speciallist");
 
@@ -365,6 +360,7 @@ void cvar_changes_init()
                BADPREFIX("gameversion_");
                BADPREFIX("g_chat_");
                BADPREFIX("g_ctf_captimerecord_");
+               BADPREFIX("g_hats_");
                BADPREFIX("g_maplist_");
                BADPREFIX("g_mod_");
                BADPREFIX("g_respawn_");
@@ -508,38 +504,6 @@ void cvar_changes_init()
        cvar_purechanges = strzone(cvar_purechanges);
 }
 
-void detect_maptype()
-{
-#if 0
-       vector o, v;
-       float i;
-
-       for (;;)
-       {
-               o = world.mins;
-               o.x += random() * (world.maxs.x - world.mins.x);
-               o.y += random() * (world.maxs.y - world.mins.y);
-               o.z += random() * (world.maxs.z - world.mins.z);
-
-               tracebox(o, STAT(PL_MIN), STAT(PL_MAX), o - '0 0 32768', MOVE_WORLDONLY, NULL);
-               if(trace_fraction == 1)
-                       continue;
-
-               v = trace_endpos;
-
-               for(i = 0; i < 64; i += 4)
-               {
-                       tracebox(o, '-1 -1 -1' * i, '1 1 1' * i, o - '0 0 32768', MOVE_WORLDONLY, NULL);
-       if(trace_fraction == 1)
-               continue;
-                       LOG_INFO(ftos(i), " -> ", vtos(trace_endpos));
-               }
-
-               break;
-       }
-#endif
-}
-
 entity randomseed;
 bool RandomSeed_Send(entity this, entity to, int sf)
 {
@@ -613,12 +577,7 @@ STATIC_INIT_EARLY(maxclients)
        }
 }
 
-void Map_MarkAsRecent(string m);
 float world_already_spawned;
-void Nagger_Init();
-void ClientInit_Spawn();
-void WeaponStats_Init();
-void WeaponStats_Shutdown();
 spawnfunc(worldspawn)
 {
        server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated")));
@@ -872,8 +831,6 @@ spawnfunc(worldspawn)
 
        next_pingtime = time + 5;
 
-       detect_maptype();
-
        // set up information replies for clients and server to use
        maplist_reply = strzone(getmaplist());
        lsmaps_reply = strzone(getlsmaps());
@@ -1094,7 +1051,7 @@ void Map_Goto(float reinit)
 // return codes of map selectors:
 //   -1 = temporary failure (that is, try some method that is guaranteed to succeed)
 //   -2 = permanent failure
-float() MaplistMethod_Iterate = // usual method
+float MaplistMethod_Iterate() // usual method
 {
        float pass, i;
 
@@ -1113,7 +1070,7 @@ float() MaplistMethod_Iterate = // usual method
        return -1;
 }
 
-float() MaplistMethod_Repeat = // fallback method
+float MaplistMethod_Repeat() // fallback method
 {
        LOG_TRACE("Trying MaplistMethod_Repeat");
 
@@ -1122,7 +1079,7 @@ float() MaplistMethod_Repeat = // fallback method
        return -2;
 }
 
-float() MaplistMethod_Random = // random map selection
+float MaplistMethod_Random() // random map selection
 {
        float i, imax;
 
@@ -1140,7 +1097,7 @@ float() MaplistMethod_Random = // random map selection
        return -1;
 }
 
-float(float exponent) MaplistMethod_Shuffle = // more clever shuffling
+float MaplistMethod_Shuffle(float exponent) // more clever shuffling
 // the exponent sets a bias on the map selection:
 // the higher the exponent, the less likely "shortly repeated" same maps are
 {
@@ -1199,9 +1156,7 @@ void Maplist_Init()
                error("empty maplist, cannot select a new map");
        Map_Current = bound(0, GetMaplistPosition(), Map_Count - 1);
 
-       if(Map_Current_Name)
-               strunzone(Map_Current_Name);
-       Map_Current_Name = strzone(argv(Map_Current)); // will be automatically freed on exit thanks to DP
+       strcpy(Map_Current_Name, argv(Map_Current)); // will be automatically freed on exit thanks to DP
        // this may or may not be correct, but who cares, in the worst case a map
        // isn't chosen in the first pass that should have been
 }
@@ -2147,7 +2102,6 @@ float RedirectionThink()
        return true;
 }
 
-void TargetMusic_RestoreGame();
 void RestoreGame()
 {
        // Loaded from a save game
index 034407bc1f0f135722602b3ba8224e70ca98ea00..c0c35589a865f476ea08d006f5f43c2ab7996ac6 100644 (file)
@@ -16,11 +16,15 @@ void IntermissionThink(entity this);
 void GotoNextMap(float reinit);
 void ReadyRestart();
 
+string GetGametype();
+
 void DumpStats(float final);
 float Map_IsRecent(string m);
 string GetNextMap();
 void ShuffleMaplist();
 void Map_Goto_SetStr(string nextmapname);
 void Map_Goto(float reinit);
+void Map_MarkAsRecent(string m);
 float DoNextMapOverride(float reinit);
 void CheckRules_World();
+float RedirectionThink();
index 98dbf5c55b748d5a4d106f8dadec8fc3e29b412f..2c0af1c8f2ac12ab4d214bfc84e51dbc94388158 100644 (file)
@@ -31,8 +31,6 @@
 
 #define MAX_IPBAN_URIS (URI_GET_IPBAN_END - URI_GET_IPBAN + 1)
 
-float Ban_Insert(string ip, float bantime, string reason, float dosync);
-
 void OnlineBanList_SendBan(string ip, float bantime, string reason)
 {
        string uri;
@@ -211,12 +209,8 @@ void OnlineBanList_Think(entity this)
        if(argc == 0)
                goto killme;
 
-       if(OnlineBanList_Servers)
-               strunzone(OnlineBanList_Servers);
-       OnlineBanList_Servers = argv(0);
-       for(i = 1; i < argc; ++i)
-               OnlineBanList_Servers = strcat(OnlineBanList_Servers, ";", argv(i));
-       OnlineBanList_Servers = strzone(OnlineBanList_Servers);
+       string s = argv(0); for(i = 1; i < argc; ++i) s = strcat(s, ";", argv(i));
+       strcpy(OnlineBanList_Servers, s);
 
        uri = strcat(     "action=list&hostname=", uri_escape(autocvar_hostname));
        uri = strcat(uri, "&servers=", uri_escape(OnlineBanList_Servers));
index 946f44f9351a14b3be143cadf3bdecf5da0dc38f..330d8b7dff1e8c509ee6b419fddc14442423ec2e 100644 (file)
@@ -6,4 +6,9 @@ float Ban_MaybeEnforceBan(entity client);
 float Ban_MaybeEnforceBanOnce(entity client);
 float BanCommand(string command);
 
+float Ban_Insert(string ip, float bantime, string reason, float dosync);
+void Ban_KickBanClient(entity client, float bantime, float masksize, string reason);
+void Ban_View();
+float Ban_Delete(float i);
+
 void OnlineBanList_URI_Get_Callback(float id, float status, string data);
index c645c7facdce7515e3021c441bb586fdbfd1375a..2bfdc49b767b626aa66e778174914c54ddda9565 100644 (file)
@@ -1,6 +1,7 @@
 #include "item_key.qh"
 
-#include "../common/triggers/subs.qh"
+#include "../common/mapobjects/subs.qh"
+#include <common/mapobjects/triggers.qh>
 #include "../common/monsters/_mod.qh"
 #include "../common/notifications/all.qh"
 #include "../common/util.qh"
@@ -86,7 +87,7 @@ void item_key_touch(entity this, entity toucher)
        this.message = "";
        SUB_UseTargets(this, toucher, toucher); // TODO: should we be using toucher for the trigger here?
        this.message = oldmsg;
-};
+}
 
 /**
  * Spawn a key with given model, key code and color.
@@ -123,7 +124,7 @@ void spawn_item_key(entity this)
        }
 
        settouch(this, item_key_touch);
-};
+}
 
 
 /*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
@@ -264,7 +265,7 @@ spawnfunc(item_key1)
        this.classname = "item_key";
        this.itemkeys = ITEM_KEY_BIT(1);
        spawnfunc_item_key(this);
-};
+}
 
 /*QUAKED item_key2 (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
 GOLD key.
@@ -283,4 +284,4 @@ spawnfunc(item_key2)
        this.classname = "item_key";
        this.itemkeys = ITEM_KEY_BIT(0);
        spawnfunc_item_key(this);
-};
+}
index 7d248834f72566af97313317a42a3a50c226f637..b21df78e3f247cb53b809446f95a555c25c86bcb 100644 (file)
@@ -5,14 +5,43 @@
 /// game items.
 /// \copyright GNU GPLv2 or any later version.
 
-#include "g_subs.qh"
+#include <server/mutators/_mod.qh>
 #include <common/weapons/all.qh>
+#include <common/mapobjects/subs.qh>
 
 .bool m_isloot; ///< Holds whether item is loot.
 /// \brief Holds whether strength, shield or superweapon timers expire while
 /// this item is on the ground.
 .bool m_isexpiring;
 
+entity Item_FindDefinition(string class_name)
+{
+       FOREACH(Items, it.m_canonical_spawnfunc == class_name,
+       {
+               return it;
+       });
+       FOREACH(Weapons, it.m_canonical_spawnfunc == class_name,
+       {
+               return it.m_pickup;
+       });
+       return NULL;
+}
+
+bool Item_IsAllowed(string class_name)
+{
+       entity definition = Item_FindDefinition(class_name);
+       if (definition == NULL)
+       {
+               return false;
+       }
+       return Item_IsDefinitionAllowed(definition);
+}
+
+bool Item_IsDefinitionAllowed(entity definition)
+{
+       return !MUTATOR_CALLHOOK(FilterItemDefinition, definition);
+}
+
 entity Item_Create(string class_name, vector position, bool no_align)
 {
        entity item = spawn();
index 1abcf64e0879442a3b8ade446bc724ca8250e503..b52449e7158dffab62269d6b17d32a6a7cdcc439 100644 (file)
@@ -4,6 +4,28 @@
 /// \brief Header file that describes the functions related to game items.
 /// \copyright GNU GPLv2 or any later version.
 
+bool startitem_failed;
+
+/// \brief Returns the item definition corresponding to the given class name.
+/// \param[in] class_name Class name to search for.
+/// \return Item definition corresponding to the given class name or NULL is not
+/// found.
+entity Item_FindDefinition(string class_name);
+
+/// \brief Checks whether the items with the specified class name are allowed to
+/// spawn.
+/// \param[in] class_name Item class name to check.
+/// \return True items with the specified class name are allowed to spawn, false
+/// otherwise.
+bool Item_IsAllowed(string class_name);
+
+/// \brief Checks whether the items with the specified definition are allowed to
+/// spawn.
+/// \param[in] definition Item definition to check.
+/// \return True items with the specified definition are allowed to spawn, false
+/// otherwise.
+bool Item_IsDefinitionAllowed(entity definition);
+
 /// \brief Creates a new item.
 /// \param[in] class_name Class name of the item.
 /// \param[in] position Position of the item.
@@ -12,7 +34,7 @@
 /// \return Item on success, NULL otherwise.
 entity Item_Create(string class_name, vector position, bool no_align);
 
-/// \brief Initializes the item according to classname.
+/// \brief Initializes the item according to class name.
 /// \param[in,out] item Item to initialize.
 /// \param[in] class_name Class name to use.
 /// \return No return.
index 209ac7af98085daf7bdffed0fc335eacba721141..816945d2ab0bc9bbdcb50ef78f11b6f813a50597 100644 (file)
@@ -109,16 +109,8 @@ void MapVote_UnzoneStrings()
 {
        for(int j = 0; j < mapvote_count; ++j)
        {
-               if ( mapvote_maps[j] )
-               {
-                       strunzone(mapvote_maps[j]);
-                       mapvote_maps[j] = string_null;
-               }
-               if ( mapvote_maps_pakfile[j] )
-               {
-                       strunzone(mapvote_maps_pakfile[j]);
-                       mapvote_maps_pakfile[j] = string_null;
-               }
+               strfree(mapvote_maps[j]);
+               strfree(mapvote_maps_pakfile[j]);
        }
 }
 
index ff762e9046fd51d89046dbb196a258d3ef02acec..ecaf2faab1ba1e1bd0cd3e11e74984b73af71085 100644 (file)
@@ -5,22 +5,24 @@
 #include "constants.qh"
 #include "g_hook.qh"
 #include "ipban.qh"
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "../common/t_items.qh"
 #include "resources.qh"
 #include "items.qh"
+#include "player.qh"
 #include "weapons/accuracy.qh"
 #include "weapons/csqcprojectile.qh"
 #include "weapons/selection.qh"
 #include "../common/command/_mod.qh"
 #include "../common/constants.qh"
 #include <common/net_linked.qh>
+#include <common/weapons/weapon/crylink.qh>
 #include "../common/deathtypes/all.qh"
 #include "../common/mapinfo.qh"
 #include "../common/notifications/all.qh"
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
-#include "../common/triggers/subs.qh"
+#include "../common/mapobjects/subs.qh"
 #include "../common/util.qh"
 #include "../common/turrets/sv_turrets.qh"
 #include <common/weapons/_all.qh>
@@ -66,6 +68,10 @@ void WarpZone_crosshair_trace(entity pl)
        WarpZone_traceline_antilag(pl, CS(pl).cursor_trace_start, CS(pl).cursor_trace_start + normalize(CS(pl).cursor_trace_endpos - CS(pl).cursor_trace_start) * max_shot_distance, MOVE_NORMAL, pl, ANTILAG_LATENCY(pl));
 }
 
+void dedicated_print(string input)
+{
+       if (server_is_dedicated) print(input);
+}
 
 void GameLogEcho(string s)
 {
@@ -198,10 +204,10 @@ string NearestLocation(vector p)
     return ret;
 }
 
-string AmmoNameFromWeaponentity(entity wpn)
+string AmmoNameFromWeaponentity(Weapon wep)
 {
        string ammoitems = "batteries";
-       switch ((wpn.m_weapon).ammo_type)
+       switch (wep.ammo_type)
        {
                case RESOURCE_SHELLS:  ammoitems = ITEM_Shells.m_name;      break;
                case RESOURCE_BULLETS: ammoitems = ITEM_Bullets.m_name;     break;
@@ -266,7 +272,7 @@ string formatmessage(entity this, string msg)
                        case "y": replacement = NearestLocation(cursor); break;
                        case "d": replacement = NearestLocation(this.death_origin); break;
                        case "w": replacement = ((this.(weaponentity).m_weapon == WEP_Null) ? ((this.(weaponentity).m_switchweapon == WEP_Null) ? Weapons_from(this.(weaponentity).cnt) : this.(weaponentity).m_switchweapon) : this.(weaponentity).m_weapon).m_name; break;
-                       case "W": replacement = AmmoNameFromWeaponentity(this.(weaponentity)); break;
+                       case "W": replacement = AmmoNameFromWeaponentity(this.(weaponentity).m_weapon); break;
                        case "x": replacement = ((cursor_ent.netname == "" || !cursor_ent) ? "nothing" : cursor_ent.netname); break;
                        case "s": replacement = ftos(vlen(this.velocity - this.velocity_z * '0 0 1')); break;
                        case "S": replacement = ftos(vlen(this.velocity)); break;
@@ -298,17 +304,13 @@ void GetCvars_handleString(entity this, entity store, string thisname, float f,
 {
        if (f < 0)
        {
-               if (store.(field))
-                       strunzone(store.(field));
-               store.(field) = string_null;
+               strfree(store.(field));
        }
        else if (f > 0)
        {
                if (thisname == name)
                {
-                       if (store.(field))
-                               strunzone(store.(field));
-                       store.(field) = strzone(argv(f + 1));
+                       strcpy(store.(field), argv(f + 1));
                }
        }
        else
@@ -323,8 +325,7 @@ void GetCvars_handleString_Fixup(entity this, entity store, string thisname, flo
                        string s = func(this, strcat1(store.(field)));
                        if (s != store.(field))
                        {
-                               strunzone(store.(field));
-                               store.(field) = strzone(s);
+                               strcpy(store.(field), s);
                        }
                }
 }
@@ -366,14 +367,8 @@ void GetCvars_handleFloatOnce(entity this, entity store, string thisname, float
 }
 string W_FixWeaponOrder_ForceComplete_AndBuildImpulseList(entity this, string wo)
 {
-       string o;
-       o = W_FixWeaponOrder_ForceComplete(wo);
-       if(CS(this).weaponorder_byimpulse)
-       {
-               strunzone(CS(this).weaponorder_byimpulse);
-               CS(this).weaponorder_byimpulse = string_null;
-       }
-       CS(this).weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
+       string o = W_FixWeaponOrder_ForceComplete(wo);
+       strcpy(CS(this).weaponorder_byimpulse, W_FixWeaponOrder_BuildImpulseList(o));
        return o;
 }
 
@@ -603,12 +598,6 @@ void readplayerstartcvars()
                g_weaponarena_list = strzone(substring(g_weaponarena_list, 0, strlen(g_weaponarena_list) - 3));
        }
 
-       if(g_weaponarena)
-               g_weaponarena_random = cvar("g_weaponarena_random");
-       else
-               g_weaponarena_random = 0;
-       g_weaponarena_random_with_blaster = cvar("g_weaponarena_random_with_blaster");
-
        if (g_weaponarena)
        {
                g_weapon_stay = 0; // incompatible
@@ -1097,7 +1086,6 @@ bool SUB_NoImpactCheck(entity this, entity toucher)
 
 #define SUB_OwnerCheck(ent,oth) ((oth) && ((oth) == (ent).owner))
 
-void W_Crylink_Dequeue(entity e);
 bool WarpZone_Projectile_Touch_ImpactFilter_Callback(entity this, entity toucher)
 {
        if(SUB_OwnerCheck(this, toucher))
index 8a32b9b5bddf8c9ff71e031f6857fecbc86cb812..1455054d2c5cad597ec87e84412d45b74ea6dc00 100644 (file)
@@ -1,10 +1,11 @@
 #pragma once
 
 #include <server/defs.qh>
+#include <server/g_world.qh>
 
 #include <common/t_items.qh>
 
-#include "mutators/events.qh"
+#include <server/mutators/_mod.qh>
 
 #include <common/constants.qh>
 #include <common/mapinfo.qh>
@@ -29,7 +30,6 @@ float cvar_normal(string n)
 #define cvar_set_normal builtin_cvar_set
 
 .vector dropped_origin;
-.float nottargeted;
 
 entity eliminatedPlayers;
 void EliminatedPlayers_Init(float(entity) isEliminated_func);
@@ -69,6 +69,9 @@ void follow_sameorigin(entity e, entity to);
 
 string formatmessage(entity this, string msg);
 
+/** print(), but only print if the server is not local */
+void dedicated_print(string input);
+
 void GameLogEcho(string s);
 
 void GameLogInit();
@@ -169,8 +172,7 @@ float g_pickup_fuel_max;
 float g_pickup_weapons_anyway;
 float g_weaponarena;
 WepSet g_weaponarena_weapons;
-float g_weaponarena_random;
-float g_weaponarena_random_with_blaster;
+float g_weaponarena_random; // TODO
 string g_weaponarena_list;
 float g_weaponspeedfactor;
 float g_weaponratefactor;
@@ -217,14 +219,11 @@ void readplayerstartcvars();
 float sv_autotaunt;
 float sv_taunt;
 
-string GetGametype(); // g_world.qc
 void readlevelcvars()
 {
        if(cvar("sv_allow_fullbright"))
                serverflags |= SERVERFLAG_ALLOW_FULLBRIGHT;
 
-       g_instagib = cvar("g_instagib");
-
        sv_clones = cvar("sv_clones");
        sv_foginterval = cvar("sv_foginterval");
        g_footsteps = cvar("g_footsteps");
index f0108dec37f6f31717305564d5678040008018d4..7b7cdf33dffba200b23b9b5ebcfb4c5fb04803d6 100644 (file)
@@ -1,4 +1,3 @@
 // generated file; do not modify
+#include <server/mutators/events.qc>
 #include <server/mutators/loader.qc>
-
-#include <server/mutators/mutator/_mod.inc>
index 9888c94666bfd085a8abe873054f7de7563ea469..6adf8e0db57a092f1b5b74e1a14bc81d1702bd8d 100644 (file)
@@ -1,4 +1,3 @@
 // generated file; do not modify
+#include <server/mutators/events.qh>
 #include <server/mutators/loader.qh>
-
-#include <server/mutators/mutator/_mod.qh>
diff --git a/qcsrc/server/mutators/events.qc b/qcsrc/server/mutators/events.qc
new file mode 100644 (file)
index 0000000..c2dbb70
--- /dev/null
@@ -0,0 +1 @@
+#include "events.qh"
index 6853c04a15641dc69bd6e52f7da39615a41610a4..98db7219d2c1dde7bd18ba1223624991e08d4a96 100644 (file)
@@ -4,6 +4,9 @@
 
 // register all possible hooks here
 
+// to use a hook, first register your mutator using REGISTER_MUTATOR
+// then create your function using MUTATOR_HOOKFUNCTION
+
 /** called when a player becomes observer, after shared setup */
 #define EV_MakePlayerObserver(i, o) \
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
@@ -24,6 +27,12 @@ MUTATOR_HOOKABLE(PutClientInServer, EV_PutClientInServer);
     /**/
 MUTATOR_HOOKABLE(ForbidSpawn, EV_ForbidSpawn);
 
+/** returns true if client should be put as player on connection */
+#define EV_AutoJoinOnConnection(i, o) \
+    /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(AutoJoinOnConnection, EV_AutoJoinOnConnection);
+
 /** called when player spawns to determine whether to give them random start weapons. Return true to forbid giving them. */
 #define EV_ForbidRandomStartWeapons(i, o) \
        /** player */ i(entity, MUTATOR_ARGV_0_entity) \
@@ -120,6 +129,8 @@ MUTATOR_HOOKABLE(ItemSound, EV_ItemSound);
     /** target     */ i(entity, MUTATOR_ARGV_1_entity) \
     /** frag score */ i(float, MUTATOR_ARGV_2_float) \
     /**            */ o(float, MUTATOR_ARGV_2_float) \
+    /** deathtype  */ i(float, MUTATOR_ARGV_3_float) \
+    /** wep entity */ i(entity, MUTATOR_ARGV_4_entity) \
     /**/
 MUTATOR_HOOKABLE(GiveFragsForKill, EV_GiveFragsForKill);
 
@@ -229,8 +240,16 @@ MUTATOR_HOOKABLE(SetStartItems, EV_NO_ARGS);
     /**/
 MUTATOR_HOOKABLE(CustomizeWaypoint, EV_CustomizeWaypoint);
 
+/** Check if items having the given definition are allowed to spawn.
+ *  Return true to disallow spawning.
+ */
+#define EV_FilterItemDefinition(i, o) \
+    /** item        */ i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(FilterItemDefinition, EV_FilterItemDefinition);
+
 /**
- * checks if the current item may be spawned (.items and .weapons may be read and written to, as well as the ammo_ fields)
+ * checks if the current item may be spawned (.items may be read and written to, as well as the ammo_ fields)
  * return error to request removal
  */
 #define EV_FilterItem(i, o) \
@@ -400,7 +419,8 @@ MUTATOR_HOOKABLE(PlayerDamage_SplitHealthArmor, EV_PlayerDamage_SplitHealthArmor
     /** mirrordamage    */ i(float,  MUTATOR_ARGV_5_float) \
     /** mirrordamage   */ o(float,  MUTATOR_ARGV_5_float) \
     /** force           */ i(vector, MUTATOR_ARGV_6_vector) \
-    /** force                  */ o(vector, MUTATOR_ARGV_6_vector) \
+    /** force           */ o(vector, MUTATOR_ARGV_6_vector) \
+    /** weapon entity  */ i(entity, MUTATOR_ARGV_7_entity) \
     /**/
 MUTATOR_HOOKABLE(Damage_Calculate, EV_Damage_Calculate);
 
@@ -424,6 +444,8 @@ MUTATOR_HOOKABLE(PlayerDamaged, EV_PlayerDamaged);
 #define EV_W_DecreaseAmmo(i, o) \
     /** actor */            i(entity, MUTATOR_ARGV_0_entity) \
     /** weapon entity */    i(entity, MUTATOR_ARGV_1_entity) \
+    /** ammo to take */     i(float, MUTATOR_ARGV_2_float) \
+    /**/                    o(float, MUTATOR_ARGV_2_float) \
     /**/
 MUTATOR_HOOKABLE(W_DecreaseAmmo, EV_W_DecreaseAmmo);
 
@@ -679,6 +701,26 @@ constants for resource types. Return true to forbid the change. */
        /**/
 MUTATOR_HOOKABLE(SetResourceAmount, EV_SetResourceAmount);
 
+/** Called after the amount of resource of an entity has changed. See RESOURCE_*
+constants for resource types. Amount wasted is the amount of resource that is
+above resource limit so it was not given. */
+#define EV_ResourceAmountChanged(i, o) \
+       /** checked entity */ i(entity, MUTATOR_ARGV_0_entity) \
+       /** resource type */  i(int, MUTATOR_ARGV_1_int) \
+       /** amount */         i(float, MUTATOR_ARGV_2_float) \
+       /**/
+MUTATOR_HOOKABLE(ResourceAmountChanged, EV_ResourceAmountChanged);
+
+/** Called when there was an attempt to set entity resources higher than their
+limit. See RESOURCE_* constants for resource types. Amount wasted is the amount
+of resource that is above resource limit so it was not given. */
+#define EV_ResourceWasted(i, o) \
+       /** checked entity */ i(entity, MUTATOR_ARGV_0_entity) \
+       /** resource type */  i(int, MUTATOR_ARGV_1_int) \
+       /** amount wasted */  i(float, MUTATOR_ARGV_2_float) \
+       /**/
+MUTATOR_HOOKABLE(ResourceWasted, EV_ResourceWasted);
+
 /** Called when entity is being given some resource. See RESOURCE_* constants
 for resource types. Return true to forbid giving. */
 #define EV_GiveResource(i, o) \
@@ -690,6 +732,19 @@ for resource types. Return true to forbid giving. */
        /**/
 MUTATOR_HOOKABLE(GiveResource, EV_GiveResource);
 
+/** Called when entity is being given some resource with specified limit. See
+RESOURCE_* constants for resource types. Return true to forbid giving. */
+#define EV_GiveResourceWithLimit(i, o) \
+       /** receiver */      i(entity, MUTATOR_ARGV_0_entity) \
+       /** resource type */ i(int, MUTATOR_ARGV_1_int) \
+       /**/                 o(int, MUTATOR_ARGV_1_int) \
+       /** amount */        i(float, MUTATOR_ARGV_2_float) \
+       /**/                 o(float, MUTATOR_ARGV_2_float) \
+       /** limit */         i(float, MUTATOR_ARGV_3_float) \
+       /**/                 o(float, MUTATOR_ARGV_3_float) \
+       /**/
+MUTATOR_HOOKABLE(GiveResourceWithLimit, EV_GiveResourceWithLimit);
+
 /** called at when a player connect */
 #define EV_ClientConnect(i, o) \
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
@@ -1060,6 +1115,13 @@ MUTATOR_HOOKABLE(Item_ScheduleRespawn, EV_Item_ScheduleRespawn);
     /**/
 MUTATOR_HOOKABLE(PlayerPhysics_UpdateStats, EV_PlayerPhysics_UpdateStats);
 
+/** called after physics stats are set on a player, allows post-initialization modifications */
+#define EV_PlayerPhysics_PostUpdateStats(i, o) \
+    /** player */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** maxspeed_mod */       i(float, MUTATOR_ARGV_1_float) \
+    /**/
+MUTATOR_HOOKABLE(PlayerPhysics_PostUpdateStats, EV_PlayerPhysics_PostUpdateStats);
+
 /** return true to use your own aim target (or none at all) */
 #define EV_HavocBot_Aim(i, o) \
     /** bot */ i(entity, MUTATOR_ARGV_0_entity) \
@@ -1071,3 +1133,20 @@ MUTATOR_HOOKABLE(HavocBot_Aim, EV_HavocBot_Aim);
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
     /**/
 MUTATOR_HOOKABLE(CalculateRespawnTime, EV_CalculateRespawnTime);
+
+/** called when parsing a vote command. */
+#define EV_VoteCommand_Parse(i, o) \
+    /** caller */                           i(entity, MUTATOR_ARGV_0_entity) \
+    /** first command */                    i(string, MUTATOR_ARGV_1_string) \
+    /** vote command */                     i(string, MUTATOR_ARGV_2_string) \
+    /** start position of vote command */   i(float, MUTATOR_ARGV_3_float) \
+    /** argument count */                   i(float, MUTATOR_ARGV_4_float) \
+    /**/
+MUTATOR_HOOKABLE(VoteCommand_Parse, EV_VoteCommand_Parse);
+
+enum {
+    MUT_VOTEPARSE_CONTINUE, // return this flag to make the function continue as normal
+    MUT_VOTEPARSE_SUCCESS, // return 1 (vote parsed)
+    MUT_VOTEPARSE_INVALID, // return -1 (vote parsed but counted as invalid, no action or vote)
+    MUT_VOTEPARSE_UNACCEPTABLE // return 0 (vote parameter counted as unacceptable, warns caller)
+};
diff --git a/qcsrc/server/mutators/gamemode.qh b/qcsrc/server/mutators/gamemode.qh
deleted file mode 100644 (file)
index b0f42f5..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-#pragma once
-
-#include <server/miscfunctions.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 <common/gamemodes/rules.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/scores.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 <common/mutators/mutator/waypoints/waypointsprites.qh>
-
-#include <server/client.qh>
-#include <server/player.qh>
-#include <server/impulse.qh>
-#include <server/cheats.qh>
-#include <server/g_damage.qh>
-
-#include <server/bot/api.qh>
-
-#include <server/command/_mod.qh>
-
-#include <common/monsters/_mod.qh>
-
-#include <server/weapons/tracing.qh>
-#include <server/weapons/weaponsystem.qh>
-
-#include <common/physics/player.qh>
-#include <common/effects/qc/_mod.qh>
-#include <common/deathtypes/all.qh>
-#include <common/notifications/all.qh>
-#include <common/triggers/teleporters.qh>
-#include <common/triggers/subs.qh>
-#include <common/stats.qh>
-#include <common/teams.qh>
-
-#include <lib/warpzone/server.qh>
-#include <lib/warpzone/util_server.qh>
-
-.float lastground;
-float total_players;
-float redalive, bluealive, yellowalive, pinkalive;
diff --git a/qcsrc/server/mutators/mutator.qh b/qcsrc/server/mutators/mutator.qh
deleted file mode 100644 (file)
index e051cd6..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-#pragma once
-
-#include <common/mutators/base.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>
-#include <server/scores.qh>
-#include <server/scores_rules.qh>
-
-#include <server/bot/api.qh>
-
-#include <server/command/_mod.qh>
-
-#include <server/weapons/common.qh>
-#include <server/weapons/tracing.qh>
-#include <server/weapons/throwing.qh>
-#include <server/weapons/weaponsystem.qh>
-
-#include <common/deathtypes/all.qh>
-#include <common/notifications/all.qh>
-#include <common/triggers/teleporters.qh>
-#include <common/triggers/subs.qh>
-#include <common/stats.qh>
-#include <common/teams.qh>
-
-#include <common/monsters/_mod.qh>
-
-#include <lib/warpzone/anglestransform.qh>
-#include <lib/warpzone/server.qh>
-#include <lib/warpzone/util_server.qh>
diff --git a/qcsrc/server/mutators/mutator/_mod.inc b/qcsrc/server/mutators/mutator/_mod.inc
deleted file mode 100644 (file)
index 6835f5d..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// generated file; do not modify
-#include <server/mutators/mutator/gamemode_assault.qc>
-#include <server/mutators/mutator/gamemode_ca.qc>
-#include <server/mutators/mutator/gamemode_ctf.qc>
-#include <server/mutators/mutator/gamemode_cts.qc>
-#include <server/mutators/mutator/gamemode_deathmatch.qc>
-#include <server/mutators/mutator/gamemode_domination.qc>
-#include <server/mutators/mutator/gamemode_freezetag.qc>
-#include <server/mutators/mutator/gamemode_invasion.qc>
-#include <server/mutators/mutator/gamemode_keepaway.qc>
-#include <server/mutators/mutator/gamemode_keyhunt.qc>
-#include <server/mutators/mutator/gamemode_lms.qc>
-#include <server/mutators/mutator/gamemode_race.qc>
-#include <server/mutators/mutator/gamemode_tdm.qc>
diff --git a/qcsrc/server/mutators/mutator/_mod.qh b/qcsrc/server/mutators/mutator/_mod.qh
deleted file mode 100644 (file)
index aef0b33..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-// generated file; do not modify
-#include <server/mutators/mutator/gamemode_assault.qh>
-#include <server/mutators/mutator/gamemode_ca.qh>
-#include <server/mutators/mutator/gamemode_ctf.qh>
-#include <server/mutators/mutator/gamemode_cts.qh>
-#include <server/mutators/mutator/gamemode_deathmatch.qh>
-#include <server/mutators/mutator/gamemode_domination.qh>
-#include <server/mutators/mutator/gamemode_freezetag.qh>
-#include <server/mutators/mutator/gamemode_invasion.qh>
-#include <server/mutators/mutator/gamemode_keepaway.qh>
-#include <server/mutators/mutator/gamemode_keyhunt.qh>
-#include <server/mutators/mutator/gamemode_lms.qh>
-#include <server/mutators/mutator/gamemode_race.qh>
-#include <server/mutators/mutator/gamemode_tdm.qh>
diff --git a/qcsrc/server/mutators/mutator/gamemode_assault.qc b/qcsrc/server/mutators/mutator/gamemode_assault.qc
deleted file mode 100644 (file)
index 70e2669..0000000
+++ /dev/null
@@ -1,617 +0,0 @@
-#include "gamemode_assault.qh"
-
-#include <lib/float.qh>
-
-.entity sprite;
-#define AS_ROUND_DELAY 5
-
-// random functions
-void assault_objective_use(entity this, entity actor, entity trigger)
-{
-       // activate objective
-       this.health = 100;
-       //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
-       //print("Activator is ", actor.classname, "\n");
-
-       IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
-       {
-               target_objective_decrease_activate(it);
-       });
-}
-
-vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
-{
-       if(this.health < 0 || this.health >= ASSAULT_VALUE_INACTIVE)
-               return '-1 0 0';
-       return current;
-}
-
-// reset this objective. Used when spawning an objective
-// and when a new round starts
-void assault_objective_reset(entity this)
-{
-       this.health = ASSAULT_VALUE_INACTIVE;
-}
-
-// decrease the health of targeted objectives
-void assault_objective_decrease_use(entity this, entity actor, entity trigger)
-{
-       if(actor.team != assault_attacker_team)
-       {
-               // wrong team triggered decrease
-               return;
-       }
-
-       if(trigger.assault_sprite)
-       {
-               WaypointSprite_Disown(trigger.assault_sprite, waypointsprite_deadlifetime);
-               if(trigger.classname == "func_assault_destructible")
-                       trigger.sprite = NULL; // TODO: just unsetting it?!
-       }
-       else
-               return; // already activated! cannot activate again!
-
-       if(this.enemy.health < ASSAULT_VALUE_INACTIVE)
-       {
-               if(this.enemy.health - this.dmg > 0.5)
-               {
-                       GameRules_scoring_add_team(actor, SCORE, this.dmg);
-                       this.enemy.health = this.enemy.health - this.dmg;
-               }
-               else
-               {
-                       GameRules_scoring_add_team(actor, SCORE, this.enemy.health);
-                       GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
-                       this.enemy.health = -1;
-
-                       if(this.enemy.message)
-                               FOREACH_CLIENT(IS_PLAYER(it), { centerprint(it, this.enemy.message); });
-
-                       SUB_UseTargets(this.enemy, this, trigger);
-               }
-       }
-}
-
-void assault_setenemytoobjective(entity this)
-{
-       IL_EACH(g_assault_objectives, it.targetname == this.target,
-       {
-               if(this.enemy == NULL)
-                       this.enemy = it;
-               else
-                       objerror(this, "more than one objective as target - fix the map!");
-               break;
-       });
-
-       if(this.enemy == NULL)
-               objerror(this, "no objective as target - fix the map!");
-}
-
-bool assault_decreaser_sprite_visible(entity this, entity player, entity view)
-{
-       if(this.assault_decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
-               return false;
-
-       return true;
-}
-
-void target_objective_decrease_activate(entity this)
-{
-       entity spr;
-       this.owner = NULL;
-       FOREACH_ENTITY_STRING(target, this.targetname,
-       {
-               if(it.assault_sprite != NULL)
-               {
-                       WaypointSprite_Disown(it.assault_sprite, waypointsprite_deadlifetime);
-                       if(it.classname == "func_assault_destructible")
-                               it.sprite = NULL; // TODO: just unsetting it?!
-               }
-
-               spr = WaypointSprite_SpawnFixed(WP_AssaultDefend, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
-               spr.assault_decreaser = this;
-               spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
-               spr.classname = "sprite_waypoint";
-               WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
-               if(it.classname == "func_assault_destructible")
-               {
-                       WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
-                       WaypointSprite_UpdateMaxHealth(spr, it.max_health);
-                       WaypointSprite_UpdateHealth(spr, it.health);
-                       it.sprite = spr;
-               }
-               else
-                       WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultPush, WP_AssaultPush);
-       });
-}
-
-void target_objective_decrease_findtarget(entity this)
-{
-       assault_setenemytoobjective(this);
-}
-
-void target_assault_roundend_reset(entity this)
-{
-       //print("round end reset\n");
-       ++this.cnt; // up round counter
-       this.winning = false; // up round
-}
-
-void target_assault_roundend_use(entity this, entity actor, entity trigger)
-{
-       this.winning = 1; // round has been won by attackers
-}
-
-void assault_roundstart_use(entity this, entity actor, entity trigger)
-{
-       SUB_UseTargets(this, this, trigger);
-
-       //(Re)spawn all turrets
-       IL_EACH(g_turrets, true,
-       {
-               // Swap turret teams
-               if(it.team == NUM_TEAM_1)
-                       it.team = NUM_TEAM_2;
-               else
-                       it.team = NUM_TEAM_1;
-
-               // Doubles as teamchange
-               turret_respawn(it);
-       });
-}
-void assault_roundstart_use_this(entity this)
-{
-       assault_roundstart_use(this, NULL, NULL);
-}
-
-void assault_wall_think(entity this)
-{
-       if(this.enemy.health < 0)
-       {
-               this.model = "";
-               this.solid = SOLID_NOT;
-       }
-       else
-       {
-               this.model = this.mdl;
-               this.solid = SOLID_BSP;
-       }
-
-       this.nextthink = time + 0.2;
-}
-
-// trigger new round
-// reset objectives, toggle spawnpoints, reset triggers, ...
-void assault_new_round(entity this)
-{
-       //bprint("ASSAULT: new round\n");
-
-       // up round counter
-       this.winning = this.winning + 1;
-
-       // swap attacker/defender roles
-       if(assault_attacker_team == NUM_TEAM_1)
-               assault_attacker_team = NUM_TEAM_2;
-       else
-               assault_attacker_team = NUM_TEAM_1;
-
-       IL_EACH(g_saved_team, !IS_CLIENT(it),
-       {
-               if(it.team_saved == NUM_TEAM_1)
-                       it.team_saved = NUM_TEAM_2;
-               else if(it.team_saved == NUM_TEAM_2)
-                       it.team_saved = NUM_TEAM_1;
-       });
-
-       // reset the level with a countdown
-       cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
-       ReadyRestart_force(); // sets game_starttime
-}
-
-entity as_round;
-.entity ent_winning;
-void as_round_think()
-{
-       game_stopped = false;
-       assault_new_round(as_round.ent_winning);
-       delete(as_round);
-       as_round = NULL;
-}
-
-// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
-// they win. Otherwise the defending team wins once the timelimit passes.
-int WinningCondition_Assault()
-{
-       if(as_round)
-               return WINNING_NO;
-
-       WinningConditionHelper(NULL); // set worldstatus
-
-       int status = WINNING_NO;
-       // as the timelimit has not yet passed just assume the defending team will win
-       if(assault_attacker_team == NUM_TEAM_1)
-       {
-               SetWinners(team, NUM_TEAM_2);
-       }
-       else
-       {
-               SetWinners(team, NUM_TEAM_1);
-       }
-
-       entity ent;
-       ent = find(NULL, classname, "target_assault_roundend");
-       if(ent)
-       {
-               if(ent.winning) // round end has been triggered by attacking team
-               {
-                       bprint("Assault: round completed.\n");
-                       SetWinners(team, assault_attacker_team);
-
-                       TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
-
-                       if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round
-                       {
-                               status = WINNING_YES;
-                       }
-                       else
-                       {
-                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
-                               as_round = new(as_round);
-                               as_round.think = as_round_think;
-                               as_round.ent_winning = ent;
-                               as_round.nextthink = time + AS_ROUND_DELAY;
-                               game_stopped = true;
-
-                               // make sure timelimit isn't hit while the game is blocked
-                               if(autocvar_timelimit > 0)
-                               if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
-                                       cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
-                       }
-               }
-       }
-
-       return status;
-}
-
-// spawnfuncs
-spawnfunc(info_player_attacker)
-{
-       if (!g_assault) { delete(this); return; }
-
-       this.team = NUM_TEAM_1; // red, gets swapped every round
-       spawnfunc_info_player_deathmatch(this);
-}
-
-spawnfunc(info_player_defender)
-{
-       if (!g_assault) { delete(this); return; }
-
-       this.team = NUM_TEAM_2; // blue, gets swapped every round
-       spawnfunc_info_player_deathmatch(this);
-}
-
-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);
-       this.spawn_evalfunc = target_objective_spawn_evalfunc;
-}
-
-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;
-
-       this.use = assault_objective_decrease_use;
-       this.health = ASSAULT_VALUE_INACTIVE;
-       this.max_health = ASSAULT_VALUE_INACTIVE;
-       this.enemy = NULL;
-
-       InitializeEntity(this, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-spawnfunc(func_breakable);
-spawnfunc(func_assault_destructible)
-{
-       if (!g_assault) { delete(this); return; }
-
-       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;
-       else
-               this.team = NUM_TEAM_1;
-
-       spawnfunc_func_breakable(this);
-}
-
-spawnfunc(func_assault_wall)
-{
-       if (!g_assault) { delete(this); return; }
-
-       this.classname = "func_assault_wall";
-       this.mdl = this.model;
-       _setmodel(this, this.mdl);
-       this.solid = SOLID_BSP;
-       setthink(this, assault_wall_think);
-       this.nextthink = time;
-       InitializeEntity(this, assault_setenemytoobjective, INITPRIO_FINDTARGET);
-}
-
-spawnfunc(target_assault_roundend)
-{
-       if (!g_assault) { delete(this); return; }
-
-       this.winning = 0; // round not yet won by attackers
-       this.classname = "target_assault_roundend";
-       this.use = target_assault_roundend_use;
-       this.cnt = 0; // first round
-       this.reset = target_assault_roundend_reset;
-}
-
-spawnfunc(target_assault_roundstart)
-{
-       if (!g_assault) { delete(this); return; }
-
-       assault_attacker_team = NUM_TEAM_1;
-       this.classname = "target_assault_roundstart";
-       this.use = assault_roundstart_use;
-       this.reset2 = assault_roundstart_use_this;
-       InitializeEntity(this, assault_roundstart_use_this, INITPRIO_FINDTARGET);
-}
-
-// legacy bot code
-void havocbot_goalrating_ast_targets(entity this, float ratingscale)
-{
-       IL_EACH(g_assault_destructibles, it.bot_attack,
-       {
-               if (it.target == "")
-                       continue;
-
-               bool found = false;
-               entity destr = it;
-               IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
-               {
-                       if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
-                       {
-                               found = true;
-                               break;
-                       }
-               });
-
-               if(!found)
-                       continue;
-
-               vector p = 0.5 * (it.absmin + it.absmax);
-
-               // Find and rate waypoints around it
-               found = false;
-               entity best = NULL;
-               float bestvalue = 99999999999;
-               entity des = it;
-               for(float radius = 0; radius < 1500 && !found; radius += 500)
-               {
-                       FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
-                       {
-                               if(checkpvs(it.origin, des))
-                               {
-                                       found = true;
-                                       if(it.cnt < bestvalue)
-                                       {
-                                               best = it;
-                                               bestvalue = it.cnt;
-                                       }
-                               }
-                       });
-               }
-
-               if(best)
-               {
-               ///     dprint("waypoints around target were found\n");
-               //      te_lightning2(NULL, '0 0 0', best.origin);
-               //      te_knightspike(best.origin);
-
-                       navigation_routerating(this, best, ratingscale, 4000);
-                       best.cnt += 1;
-
-                       this.havocbot_attack_time = 0;
-
-                       if(checkpvs(this.origin + this.view_ofs, it))
-                       if(checkpvs(this.origin + this.view_ofs, best))
-                       {
-                       //      dprint("increasing attack time for this target\n");
-                               this.havocbot_attack_time = time + 2;
-                       }
-               }
-       });
-}
-
-void havocbot_role_ast_offense(entity this)
-{
-       if(IS_DEAD(this))
-       {
-               this.havocbot_attack_time = 0;
-               havocbot_ast_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_ast_reset_role(this);
-               return;
-       }
-
-       if(this.havocbot_attack_time>time)
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
-               havocbot_goalrating_ast_targets(this, 20000);
-               havocbot_goalrating_items(this, 15000, this.origin, 10000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ast_defense(entity this)
-{
-       if(IS_DEAD(this))
-       {
-               this.havocbot_attack_time = 0;
-               havocbot_ast_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_ast_reset_role(this);
-               return;
-       }
-
-       if(this.havocbot_attack_time>time)
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 3000);
-               havocbot_goalrating_ast_targets(this, 20000);
-               havocbot_goalrating_items(this, 15000, this.origin, 10000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ast_setrole(entity this, float role)
-{
-       switch(role)
-       {
-               case HAVOCBOT_AST_ROLE_DEFENSE:
-                       this.havocbot_role = havocbot_role_ast_defense;
-                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
-                       this.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_AST_ROLE_OFFENSE:
-                       this.havocbot_role = havocbot_role_ast_offense;
-                       this.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
-                       this.havocbot_role_timeout = 0;
-                       break;
-       }
-}
-
-void havocbot_ast_reset_role(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if(this.team == assault_attacker_team)
-               havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_OFFENSE);
-       else
-               havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_DEFENSE);
-}
-
-// mutator hooks
-MUTATOR_HOOKFUNCTION(as, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.team == assault_attacker_team)
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
-       else
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
-}
-
-MUTATOR_HOOKFUNCTION(as, TurretSpawn)
-{
-       entity turret = M_ARGV(0, entity);
-
-       if(!turret.team || turret.team == FLOAT_MAX)
-               turret.team = 5; // this gets reversed when match starts?
-}
-
-MUTATOR_HOOKFUNCTION(as, VehicleInit)
-{
-       entity veh = M_ARGV(0, entity);
-
-       veh.nextthink = time + 0.5;
-}
-
-MUTATOR_HOOKFUNCTION(as, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       havocbot_ast_reset_role(bot);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(as, PlayHitsound)
-{
-       entity frag_victim = M_ARGV(0, entity);
-
-       return (frag_victim.classname == "func_assault_destructible");
-}
-
-MUTATOR_HOOKFUNCTION(as, CheckAllowedTeams)
-{
-       // assault always has 2 teams
-       c1 = c2 = 0;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(as, CheckRules_World)
-{
-       M_ARGV(0, float) = WinningCondition_Assault();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(as, ReadLevelCvars)
-{
-       // incompatible
-       warmup_stage = 0;
-       sv_ready_restart_after_countdown = 0;
-}
-
-MUTATOR_HOOKFUNCTION(as, OnEntityPreSpawn)
-{
-    entity ent = M_ARGV(0, entity);
-
-       switch(ent.classname)
-       {
-               case "info_player_team1":
-               case "info_player_team2":
-               case "info_player_team3":
-               case "info_player_team4":
-                       return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
-{
-       // readyrestart not supported (yet)
-       return true;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_assault.qh b/qcsrc/server/mutators/mutator/gamemode_assault.qh
deleted file mode 100644 (file)
index ea714e6..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-const int ST_ASSAULT_OBJECTIVES = 1;
-
-REGISTER_MUTATOR(as, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-        GameRules_teams(true);
-        int teams = BITS(2); // always red vs blue
-        GameRules_scoring(teams, SFL_SORT_PRIO_SECONDARY, SFL_SORT_PRIO_SECONDARY, {
-            field_team(ST_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
-            field(SP_ASSAULT_OBJECTIVES, "objectives", SFL_SORT_PRIO_PRIMARY);
-        });
-       }
-       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_ast_defense;
-void(entity this) havocbot_role_ast_offense;
-
-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;
-
-// predefined spawnfuncs
-void target_objective_decrease_activate(entity this);
diff --git a/qcsrc/server/mutators/mutator/gamemode_ca.qc b/qcsrc/server/mutators/mutator/gamemode_ca.qc
deleted file mode 100644 (file)
index 43ed39a..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-#include "gamemode_ca.qh"
-
-float autocvar_g_ca_damage2score_multiplier;
-bool autocvar_g_ca_spectate_enemies;
-
-void CA_count_alive_players()
-{
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               switch(it.team)
-               {
-                       case NUM_TEAM_1: ++total_players; if(!IS_DEAD(it)) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(!IS_DEAD(it)) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(!IS_DEAD(it)) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(!IS_DEAD(it)) ++pinkalive; break;
-               }
-       });
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               STAT(REDALIVE, it) = redalive;
-               STAT(BLUEALIVE, it) = bluealive;
-               STAT(YELLOWALIVE, it) = yellowalive;
-               STAT(PINKALIVE, it) = pinkalive;
-       });
-}
-
-float CA_GetWinnerTeam()
-{
-       float winner_team = 0;
-       if(redalive >= 1)
-               winner_team = NUM_TEAM_1;
-       if(bluealive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
-       }
-       if(yellowalive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
-       }
-       if(pinkalive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
-               return winner_team;
-       return -1; // no player left
-}
-
-void nades_Clear(entity player);
-
-#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
-float CA_CheckWinner()
-{
-       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
-               FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
-
-               allowed_to_spawn = false;
-               game_stopped = true;
-               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-               return 1;
-       }
-
-       CA_count_alive_players();
-       if(CA_ALIVE_TEAMS() > 1)
-               return 0;
-
-       int winner_team = CA_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_CA_ROUNDS, +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);
-       }
-
-       allowed_to_spawn = false;
-       game_stopped = true;
-       round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-
-       FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
-
-       return 1;
-}
-
-void CA_RoundStart()
-{
-    allowed_to_spawn = boolean(warmup_stage);
-}
-
-bool CA_CheckTeams()
-{
-       static int prev_missing_teams_mask;
-       allowed_to_spawn = true;
-       CA_count_alive_players();
-       if(CA_ALIVE_TEAMS_OK())
-       {
-               if(prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               return true;
-       }
-       if(total_players == 0)
-       {
-               if(prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               return false;
-       }
-       int missing_teams_mask = 0;
-       if(ca_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(ca_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(ca_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(ca_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
-       if(prev_missing_teams_mask != missing_teams_mask)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
-               prev_missing_teams_mask = missing_teams_mask;
-       }
-       return false;
-}
-
-bool ca_isEliminated(entity e)
-{
-       if(e.caplayer == 1 && (IS_DEAD(e) || e.frags == FRAGS_LMS_LOSER))
-               return true;
-       if(e.caplayer == 0.5)
-               return true;
-       return false;
-}
-
-/** Returns next available player to spectate if g_ca_spectate_enemies == 0 */
-entity CA_SpectateNext(entity player, entity start)
-{
-       if (SAME_TEAM(start, player)) return start;
-       // continue from current player
-       for (entity e = start; (e = find(e, classname, STR_PLAYER)); )
-       {
-               if (SAME_TEAM(player, e)) return e;
-       }
-       // restart from begining
-       for (entity e = NULL; (e = find(e, classname, STR_PLAYER)); )
-       {
-               if (SAME_TEAM(player, e)) return e;
-       }
-       return start;
-}
-
-
-MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
-{
-    entity player = M_ARGV(0, entity);
-
-       player.caplayer = 1;
-       if (!warmup_stage)
-               eliminatedPlayers.SendFlags |= 1;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ForbidSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       // spectators / observers that weren't playing can join; they are
-       // immediately forced to observe in the PutClientInServer hook
-       // this way they are put in a team and can play in the next round
-       if (!allowed_to_spawn && player.caplayer)
-               return true;
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
-{
-       entity player = M_ARGV(0, entity);
-
-       if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
-       {
-               TRANSMUTE(Observer, player);
-               if (CS(player).jointime != time && !player.caplayer) // not when connecting
-               {
-                       player.caplayer = 0.5;
-                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ca, reset_map_players)
-{
-       FOREACH_CLIENT(true, {
-               CS(it).killcount = 0;
-               if (!it.caplayer && IS_BOT_CLIENT(it))
-               {
-                       it.team = -1;
-                       it.caplayer = 1;
-               }
-               if (it.caplayer)
-               {
-                       TRANSMUTE(Player, it);
-                       it.caplayer = 1;
-                       PutClientInServer(it);
-               }
-       });
-       bot_relinkplayerlist();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientConnect)
-{
-    entity player = M_ARGV(0, entity);
-
-       TRANSMUTE(Observer, player);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, reset_map_global)
-{
-       allowed_to_spawn = true;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(0, float) = ca_teams;
-}
-
-entity ca_LastPlayerForTeam(entity this)
-{
-       entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if (!IS_DEAD(it))
-               if (SAME_TEAM(this, it))
-               if (!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
-       });
-       return last_pl;
-}
-
-void ca_LastPlayerForTeam_Notify(entity this)
-{
-       if (round_handler_IsActive())
-       if (round_handler_IsRoundStarted())
-       {
-               entity pl = ca_LastPlayerForTeam(this);
-               if (pl)
-                       Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       ca_LastPlayerForTeam_Notify(frag_target);
-       if (!allowed_to_spawn)
-       {
-               frag_target.respawn_flags = RESPAWN_SILENT;
-               // prevent unwanted sudden rejoin as spectator and move of spectator camera
-               frag_target.respawn_time = time + 2;
-       }
-       if (!warmup_stage)
-               eliminatedPlayers.SendFlags |= 1;
-       if(IS_BOT_CLIENT(frag_target))
-               bot_clear(frag_target);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
-{
-    entity player = M_ARGV(0, entity);
-
-       if (player.caplayer == 1)
-               ca_LastPlayerForTeam_Notify(player);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
-{
-    entity player = M_ARGV(0, entity);
-
-       if (!IS_DEAD(player))
-               ca_LastPlayerForTeam_Notify(player);
-       if (player.killindicator_teamchange == -2) // player wants to spectate
-               player.caplayer = 0;
-       if (player.caplayer)
-               player.frags = FRAGS_LMS_LOSER;
-       if (!warmup_stage)
-               eliminatedPlayers.SendFlags |= 1;
-       if (!player.caplayer)
-               return false;  // allow team reset
-       return true;  // prevent team reset
-}
-
-MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST)
-{
-       M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SetStartItems)
-{
-       start_items       &= ~IT_UNLIMITED_AMMO;
-       start_health       = warmup_start_health       = cvar("g_lms_start_health");
-       start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
-       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
-       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
-       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
-       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
-}
-
-MUTATOR_HOOKFUNCTION(ca, Damage_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);
-
-       if (IS_PLAYER(frag_target))
-       if (!IS_DEAD(frag_target))
-       if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
-               frag_damage = 0;
-
-       frag_mirrordamage = 0;
-
-       M_ARGV(4, float) = frag_damage;
-       M_ARGV(5, float) = frag_mirrordamage;
-}
-
-MUTATOR_HOOKFUNCTION(ca, FilterItem)
-{
-    entity item = M_ARGV(0, entity);
-
-       if (autocvar_g_powerups <= 0)
-       if (item.flags & FL_POWERUP)
-               return true;
-
-       if (autocvar_g_pickup_items <= 0)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_damage = M_ARGV(7, float);
-       float damage_take = M_ARGV(4, float);
-       float damage_save = M_ARGV(5, float);
-
-       float excess = max(0, frag_damage - damage_take - damage_save);
-
-       if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
-               GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
-}
-
-MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
-{
-       // no respawn calculations needed, player is forced to spectate anyway
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
-{
-       // no regeneration in CA
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
-{
-       // announce remaining frags
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectateSet)
-{
-    entity client = M_ARGV(0, entity);
-    entity targ = M_ARGV(1, entity);
-
-       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
-       if (DIFF_TEAM(targ, client))
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectateNext)
-{
-    entity client = M_ARGV(0, entity);
-
-       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
-       {
-               entity targ = M_ARGV(1, entity);
-               M_ARGV(1, entity) = CA_SpectateNext(client, targ);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
-{
-    entity client = M_ARGV(0, entity);
-    entity targ = M_ARGV(1, entity);
-    entity first = M_ARGV(2, entity);
-
-       if (!autocvar_g_ca_spectate_enemies && client.caplayer)
-       {
-               do { targ = targ.chain; }
-               while(targ && DIFF_TEAM(targ, client));
-
-               if (!targ)
-               {
-                       for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain);
-
-                       if (targ == client.enemy)
-                               return MUT_SPECPREV_RETURN;
-               }
-       }
-
-       M_ARGV(1, entity) = targ;
-
-       return MUT_SPECPREV_FOUND;
-}
-
-MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
-{
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               if (IS_PLAYER(it) || it.caplayer == 1)
-                       ++M_ARGV(0, int);
-               ++M_ARGV(1, int);
-       });
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
-{
-    entity player = M_ARGV(0, entity);
-
-       if (player.caplayer)
-       {
-               // they're going to spec, we can do other checks
-               if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
-                       Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
-               return MUT_SPECCMD_FORCE;
-       }
-
-       return MUT_SPECCMD_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(ca, WantWeapon)
-{
-       M_ARGV(2, bool) = true; // all weapons
-}
-
-MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
-{
-       return true; // doesn't work well with the whole spectator as player thing
-}
-
-MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus)
-{
-       entity player = M_ARGV(0, entity);
-
-       return player.caplayer == 1;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
-{
-       // most weapons arena
-       if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_ca.qh b/qcsrc/server/mutators/mutator/gamemode_ca.qh
deleted file mode 100644 (file)
index 0982fcc..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-#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);
-
-REGISTER_MUTATOR(ca, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-               GameRules_teams(true);
-        GameRules_spawning_teams(autocvar_g_ca_team_spawns);
-        GameRules_limit_score(autocvar_g_ca_point_limit);
-        GameRules_limit_lead(autocvar_g_ca_point_leadlimit);
-
-               ca_teams = autocvar_g_ca_teams_override;
-               if (ca_teams < 2)
-                       ca_teams = cvar("g_ca_teams"); // read the cvar directly as it gets written earlier in the same frame
-
-               ca_teams = BITS(bound(2, ca_teams, 4));
-        GameRules_scoring(ca_teams, SFL_SORT_PRIO_PRIMARY, 0, {
-            field_team(ST_CA_ROUNDS, "rounds", SFL_SORT_PRIO_PRIMARY);
-        });
-
-               allowed_to_spawn = true;
-               round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, CA_RoundStart);
-               round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-               EliminatedPlayers_Init(ca_isEliminated);
-       }
-       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
diff --git a/qcsrc/server/mutators/mutator/gamemode_ctf.qc b/qcsrc/server/mutators/mutator/gamemode_ctf.qc
deleted file mode 100644 (file)
index b34e3f5..0000000
+++ /dev/null
@@ -1,2775 +0,0 @@
-#include "gamemode_ctf.qh"
-
-#include <common/effects/all.qh>
-#include <common/vehicles/all.qh>
-#include <server/teamplay.qh>
-
-#include <lib/warpzone/common.qh>
-
-bool autocvar_g_ctf_allow_vehicle_carry;
-bool autocvar_g_ctf_allow_vehicle_touch;
-bool autocvar_g_ctf_allow_monster_touch;
-bool autocvar_g_ctf_throw;
-float autocvar_g_ctf_throw_angle_max;
-float autocvar_g_ctf_throw_angle_min;
-int autocvar_g_ctf_throw_punish_count;
-float autocvar_g_ctf_throw_punish_delay;
-float autocvar_g_ctf_throw_punish_time;
-float autocvar_g_ctf_throw_strengthmultiplier;
-float autocvar_g_ctf_throw_velocity_forward;
-float autocvar_g_ctf_throw_velocity_up;
-float autocvar_g_ctf_drop_velocity_up;
-float autocvar_g_ctf_drop_velocity_side;
-bool autocvar_g_ctf_oneflag_reverse;
-bool autocvar_g_ctf_portalteleport;
-bool autocvar_g_ctf_pass;
-float autocvar_g_ctf_pass_arc;
-float autocvar_g_ctf_pass_arc_max;
-float autocvar_g_ctf_pass_directional_max;
-float autocvar_g_ctf_pass_directional_min;
-float autocvar_g_ctf_pass_radius;
-float autocvar_g_ctf_pass_wait;
-bool autocvar_g_ctf_pass_request;
-float autocvar_g_ctf_pass_turnrate;
-float autocvar_g_ctf_pass_timelimit;
-float autocvar_g_ctf_pass_velocity;
-bool autocvar_g_ctf_dynamiclights;
-float autocvar_g_ctf_flag_collect_delay;
-float autocvar_g_ctf_flag_damageforcescale;
-bool autocvar_g_ctf_flag_dropped_waypoint;
-bool autocvar_g_ctf_flag_dropped_floatinwater;
-bool autocvar_g_ctf_flag_glowtrails;
-int autocvar_g_ctf_flag_health;
-bool autocvar_g_ctf_flag_return;
-bool autocvar_g_ctf_flag_return_carrying;
-float autocvar_g_ctf_flag_return_carried_radius;
-float autocvar_g_ctf_flag_return_time;
-bool autocvar_g_ctf_flag_return_when_unreachable;
-float autocvar_g_ctf_flag_return_damage;
-float autocvar_g_ctf_flag_return_damage_delay;
-float autocvar_g_ctf_flag_return_dropped;
-float autocvar_g_ctf_flagcarrier_auto_helpme_damage;
-float autocvar_g_ctf_flagcarrier_auto_helpme_time;
-float autocvar_g_ctf_flagcarrier_selfdamagefactor;
-float autocvar_g_ctf_flagcarrier_selfforcefactor;
-float autocvar_g_ctf_flagcarrier_damagefactor;
-float autocvar_g_ctf_flagcarrier_forcefactor;
-//float autocvar_g_ctf_flagcarrier_waypointforenemy_spotting;
-bool autocvar_g_ctf_fullbrightflags;
-bool autocvar_g_ctf_ignore_frags;
-bool autocvar_g_ctf_score_ignore_fields;
-int autocvar_g_ctf_score_capture;
-int autocvar_g_ctf_score_capture_assist;
-int autocvar_g_ctf_score_kill;
-int autocvar_g_ctf_score_penalty_drop;
-int autocvar_g_ctf_score_penalty_returned;
-int autocvar_g_ctf_score_pickup_base;
-int autocvar_g_ctf_score_pickup_dropped_early;
-int autocvar_g_ctf_score_pickup_dropped_late;
-int autocvar_g_ctf_score_return;
-float autocvar_g_ctf_shield_force;
-float autocvar_g_ctf_shield_max_ratio;
-int autocvar_g_ctf_shield_min_negscore;
-bool autocvar_g_ctf_stalemate;
-int autocvar_g_ctf_stalemate_endcondition;
-float autocvar_g_ctf_stalemate_time;
-bool autocvar_g_ctf_reverse;
-float autocvar_g_ctf_dropped_capture_delay;
-float autocvar_g_ctf_dropped_capture_radius;
-
-void ctf_FakeTimeLimit(entity e, float t)
-{
-       msg_entity = e;
-       WriteByte(MSG_ONE, 3); // svc_updatestat
-       WriteByte(MSG_ONE, 236); // STAT_TIMELIMIT
-       if(t < 0)
-               WriteCoord(MSG_ONE, autocvar_timelimit);
-       else
-               WriteCoord(MSG_ONE, (t + 1) / 60);
-}
-
-void ctf_EventLog(string mode, int flagteam, entity actor) // use an alias for easy changing and quick editing later
-{
-       if(autocvar_sv_eventlog)
-               GameLogEcho(sprintf(":ctf:%s:%d:%d:%s", mode, flagteam, actor.team, ((actor != NULL) ? ftos(actor.playerid) : "")));
-               //GameLogEcho(strcat(":ctf:", mode, ":", ftos(flagteam), ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
-}
-
-void ctf_CaptureRecord(entity flag, entity player)
-{
-       float cap_record = ctf_captimerecord;
-       float cap_time = (time - flag.ctf_pickuptime);
-       string refername = db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"));
-
-       // notify about shit
-       if(ctf_oneflag)
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_CTF_CAPTURE_NEUTRAL, player.netname);
-       else if(!ctf_captimerecord)
-               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_TIME), player.netname, TIME_ENCODE(cap_time));
-       else if(cap_time < cap_record)
-               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_BROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
-       else
-               Send_Notification(NOTIF_ALL, NULL, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_CAPTURE_UNBROKEN), player.netname, refername, TIME_ENCODE(cap_time), TIME_ENCODE(cap_record));
-
-       // write that shit in the database
-       if(!ctf_oneflag) // but not in 1-flag mode
-       if((!ctf_captimerecord) || (cap_time < cap_record))
-       {
-               ctf_captimerecord = cap_time;
-               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time"), ftos(cap_time));
-               db_put(ServerProgsDB, strcat(GetMapname(), "/captimerecord/netname"), player.netname);
-               write_recordmarker(player, flag.ctf_pickuptime, cap_time);
-       }
-
-       if(autocvar_g_ctf_leaderboard && !ctf_oneflag)
-               race_setTime(GetMapname(), TIME_ENCODE(cap_time), player.crypto_idfp, player.netname, player, false);
-}
-
-bool ctf_Immediate_Return_Allowed(entity flag, entity toucher)
-{
-       int num_perteam = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(toucher, it), { ++num_perteam; });
-
-       // automatically return if there's only 1 player on the team
-       return ((autocvar_g_ctf_flag_return || num_perteam <= 1 || (autocvar_g_ctf_flag_return_carrying && toucher.flagcarried))
-               && flag.team);
-}
-
-bool ctf_Return_Customize(entity this, entity client)
-{
-       // only to the carrier
-       return boolean(client == this.owner);
-}
-
-void ctf_FlagcarrierWaypoints(entity player)
-{
-       WaypointSprite_Spawn(WP_FlagCarrier, 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_flagcarrier, true, RADARICON_FLAG);
-       WaypointSprite_UpdateMaxHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
-       WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
-       WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
-
-       if(player.flagcarried && CTF_SAMETEAM(player, player.flagcarried))
-       {
-               if(!player.wps_enemyflagcarrier)
-               {
-                       entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, 0, player, wps_enemyflagcarrier, true, RADARICON_FLAG);
-                       wp.colormod = WPCOLOR_ENEMYFC(player.team);
-                       setcefc(wp, ctf_Stalemate_Customize);
-
-                       if(IS_REAL_CLIENT(player) && !ctf_stalemate)
-                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_VISIBLE);
-               }
-
-               if(!player.wps_flagreturn)
-               {
-                       entity owp = WaypointSprite_SpawnFixed(WP_FlagReturn, player.flagcarried.ctf_spawnorigin + FLAG_WAYPOINT_OFFSET, player, wps_flagreturn, RADARICON_FLAG);
-                       owp.colormod = '0 0.8 0.8';
-                       //WaypointSprite_UpdateTeamRadar(player.wps_flagreturn, RADARICON_FLAG, ((player.team) ? colormapPaletteColor(player.team - 1, false) : '1 1 1'));
-                       setcefc(owp, ctf_Return_Customize);
-               }
-       }
-}
-
-void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
-{
-       float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
-       float initial_height = min(autocvar_g_ctf_pass_arc_max, (flag.pass_distance * tanh(autocvar_g_ctf_pass_arc)));
-       float current_height = (initial_height * min(1, (current_distance / flag.pass_distance)));
-       //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
-
-       vector targpos;
-       if(current_height) // make sure we can actually do this arcing path
-       {
-               targpos = (to + ('0 0 1' * current_height));
-               WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
-               if(trace_fraction < 1)
-               {
-                       //print("normal arc line failed, trying to find new pos...");
-                       WarpZone_TraceLine(to, targpos, MOVE_NOMONSTERS, flag);
-                       targpos = (trace_endpos + FLAG_PASS_ARC_OFFSET);
-                       WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
-                       if(trace_fraction < 1) { targpos = to; /* print(" ^1FAILURE^7, reverting to original direction.\n"); */ }
-                       /*else { print(" ^3SUCCESS^7, using new arc line.\n"); } */
-               }
-       }
-       else { targpos = to; }
-
-       //flag.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
-
-       vector desired_direction = normalize(targpos - from);
-       if(turnrate) { flag.velocity = (normalize(normalize(flag.velocity) + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); }
-       else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
-}
-
-bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
-{
-       if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
-       {
-               // directional tracing only
-               float spreadlimit;
-               makevectors(passer_angle);
-
-               // find the closest point on the enemy to the center of the attack
-               float h; // hypotenuse, which is the distance between attacker to head
-               float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
-
-               h = vlen(head_center - passer_center);
-               a = h * (normalize(head_center - passer_center) * v_forward);
-
-               vector nearest_on_line = (passer_center + a * v_forward);
-               float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
-
-               spreadlimit = (autocvar_g_ctf_pass_radius ? min(1, (vlen(passer_center - nearest_on_line) / autocvar_g_ctf_pass_radius)) : 1);
-               spreadlimit = (autocvar_g_ctf_pass_directional_min * (1 - spreadlimit) + autocvar_g_ctf_pass_directional_max * spreadlimit);
-
-               if(spreadlimit && (distance_from_line <= spreadlimit) && ((vlen(normalize(head_center - passer_center) - v_forward) * RAD2DEG) <= 90))
-                       { return true; }
-               else
-                       { return false; }
-       }
-       else { return true; }
-}
-
-
-// =======================
-// CaptureShield Functions
-// =======================
-
-bool ctf_CaptureShield_CheckStatus(entity p)
-{
-       int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
-       int players_worseeq, players_total;
-
-       if(ctf_captureshield_max_ratio <= 0)
-               return false;
-
-       s  = GameRules_scoring_add(p, CTF_CAPS, 0);
-       s2 = GameRules_scoring_add(p, CTF_PICKUPS, 0);
-       s3 = GameRules_scoring_add(p, CTF_RETURNS, 0);
-       s4 = GameRules_scoring_add(p, CTF_FCKILLS, 0);
-
-       sr = ((s - s2) + (s3 + s4));
-
-       if(sr >= -ctf_captureshield_min_negscore)
-               return false;
-
-       players_total = players_worseeq = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               if(DIFF_TEAM(it, p))
-                       continue;
-               se  = GameRules_scoring_add(it, CTF_CAPS, 0);
-               se2 = GameRules_scoring_add(it, CTF_PICKUPS, 0);
-               se3 = GameRules_scoring_add(it, CTF_RETURNS, 0);
-               se4 = GameRules_scoring_add(it, CTF_FCKILLS, 0);
-
-               ser = ((se - se2) + (se3 + se4));
-
-               if(ser <= sr)
-                       ++players_worseeq;
-               ++players_total;
-       });
-
-       // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
-       // use this rule here
-
-       if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
-               return false;
-
-       return true;
-}
-
-void ctf_CaptureShield_Update(entity player, bool wanted_status)
-{
-       bool updated_status = ctf_CaptureShield_CheckStatus(player);
-       if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
-       {
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
-               player.ctf_captureshielded = updated_status;
-       }
-}
-
-bool ctf_CaptureShield_Customize(entity this, entity client)
-{
-       if(!client.ctf_captureshielded) { return false; }
-       if(CTF_SAMETEAM(this, client)) { return false; }
-
-       return true;
-}
-
-void ctf_CaptureShield_Touch(entity this, entity toucher)
-{
-       if(!toucher.ctf_captureshielded) { return; }
-       if(CTF_SAMETEAM(this, toucher)) { 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, DMG_NOWEP, mymid, normalize(theirmid - mymid) * ctf_captureshield_force);
-       if(IS_REAL_CLIENT(toucher)) { Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
-}
-
-void ctf_CaptureShield_Spawn(entity flag)
-{
-       entity shield = new(ctf_captureshield);
-
-       shield.enemy = flag;
-       shield.team = flag.team;
-       settouch(shield, ctf_CaptureShield_Touch);
-       setcefc(shield, ctf_CaptureShield_Customize);
-       shield.effects = EF_ADDITIVE;
-       set_movetype(shield, MOVETYPE_NOCLIP);
-       shield.solid = SOLID_TRIGGER;
-       shield.avelocity = '7 0 11';
-       shield.scale = 0.5;
-
-       setorigin(shield, flag.origin);
-       setmodel(shield, MDL_CTF_SHIELD);
-       setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
-}
-
-
-// ====================
-// Drop/Pass/Throw Code
-// ====================
-
-void ctf_Handle_Drop(entity flag, entity player, int droptype)
-{
-       // declarations
-       player = (player ? player : flag.pass_sender);
-
-       // main
-       set_movetype(flag, MOVETYPE_TOSS);
-       flag.takedamage = DAMAGE_YES;
-       flag.angles = '0 0 0';
-       flag.health = flag.max_flag_health;
-       flag.ctf_droptime = time;
-       flag.ctf_dropper = player;
-       flag.ctf_status = FLAG_DROPPED;
-
-       // messages and sounds
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname);
-       _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
-       ctf_EventLog("dropped", player.team, player);
-
-       // scoring
-       GameRules_scoring_add_team(player, SCORE, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
-       GameRules_scoring_add(player, CTF_DROPS, 1);
-
-       // waypoints
-       if(autocvar_g_ctf_flag_dropped_waypoint) {
-               entity wp = WaypointSprite_Spawn(WP_FlagDropped, 0, 0, flag, FLAG_WAYPOINT_OFFSET, NULL, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG);
-               wp.colormod = WPCOLOR_DROPPEDFLAG(flag.team);
-       }
-
-       if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
-       {
-               WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
-               WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
-       }
-
-       player.throw_antispam = time + autocvar_g_ctf_pass_wait;
-
-       if(droptype == DROP_PASS)
-       {
-               flag.pass_distance = 0;
-               flag.pass_sender = NULL;
-               flag.pass_target = NULL;
-       }
-}
-
-void ctf_Handle_Retrieve(entity flag, entity player)
-{
-       entity sender = flag.pass_sender;
-
-       // transfer flag to player
-       flag.owner = player;
-       flag.owner.flagcarried = flag;
-       GameRules_scoring_vip(player, true);
-
-       // reset flag
-       if(player.vehicle)
-       {
-               setattachment(flag, player.vehicle, "");
-               setorigin(flag, VEHICLE_FLAG_OFFSET);
-               flag.scale = VEHICLE_FLAG_SCALE;
-       }
-       else
-       {
-               setattachment(flag, player, "");
-               setorigin(flag, FLAG_CARRY_OFFSET);
-       }
-       set_movetype(flag, MOVETYPE_NONE);
-       flag.takedamage = DAMAGE_NO;
-       flag.solid = SOLID_NOT;
-       flag.angles = '0 0 0';
-       flag.ctf_status = FLAG_CARRY;
-
-       // messages and sounds
-       _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
-       ctf_EventLog("receive", flag.team, player);
-
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-               if(it == sender)
-                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
-               else if(it == player)
-                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
-               else if(SAME_TEAM(it, sender))
-                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
-       });
-
-       // create new waypoint
-       ctf_FlagcarrierWaypoints(player);
-
-       sender.throw_antispam = time + autocvar_g_ctf_pass_wait;
-       player.throw_antispam = sender.throw_antispam;
-
-       flag.pass_distance = 0;
-       flag.pass_sender = NULL;
-       flag.pass_target = NULL;
-}
-
-void ctf_Handle_Throw(entity player, entity receiver, int droptype)
-{
-       entity flag = player.flagcarried;
-       vector targ_origin, flag_velocity;
-
-       if(!flag) { return; }
-       if((droptype == DROP_PASS) && !receiver) { return; }
-
-       if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
-
-       // reset the flag
-       setattachment(flag, NULL, "");
-       setorigin(flag, player.origin + FLAG_DROP_OFFSET);
-       flag.owner.flagcarried = NULL;
-       GameRules_scoring_vip(flag.owner, false);
-       flag.owner = NULL;
-       flag.solid = SOLID_TRIGGER;
-       flag.ctf_dropper = player;
-       flag.ctf_droptime = time;
-       navigation_dynamicgoal_set(flag);
-
-       flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
-
-       switch(droptype)
-       {
-               case DROP_PASS:
-               {
-                       // warpzone support:
-                       // for the examples, we assume player -> wz1 -> ... -> wzn -> receiver
-                       // findradius has already put wzn ... wz1 into receiver's warpzone parameters!
-                       WarpZone_RefSys_Copy(flag, receiver);
-                       WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
-                       targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
-
-                       flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' *  player.origin.x) + ('0 1 0' *  player.origin.y))); // for the sake of this check, exclude Z axis
-                       ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
-
-                       // main
-                       set_movetype(flag, MOVETYPE_FLY);
-                       flag.takedamage = DAMAGE_NO;
-                       flag.pass_sender = player;
-                       flag.pass_target = receiver;
-                       flag.ctf_status = FLAG_PASSING;
-
-                       // other
-                       _sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
-                       WarpZone_TrailParticles(NULL, _particleeffectnum(flag.passeffect), player.origin, targ_origin);
-                       ctf_EventLog("pass", flag.team, player);
-                       break;
-               }
-
-               case DROP_THROW:
-               {
-                       makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
-
-                       flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
-                       flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
-                       ctf_Handle_Drop(flag, player, droptype);
-                       break;
-               }
-
-               case DROP_RESET:
-               {
-                       flag.velocity = '0 0 0'; // do nothing
-                       break;
-               }
-
-               default:
-               case DROP_NORMAL:
-               {
-                       flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
-                       ctf_Handle_Drop(flag, player, droptype);
-                       break;
-               }
-       }
-
-       // kill old waypointsprite
-       WaypointSprite_Ping(player.wps_flagcarrier);
-       WaypointSprite_Kill(player.wps_flagcarrier);
-
-       if(player.wps_enemyflagcarrier)
-               WaypointSprite_Kill(player.wps_enemyflagcarrier);
-
-       if(player.wps_flagreturn)
-               WaypointSprite_Kill(player.wps_flagreturn);
-
-       // captureshield
-       ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
-}
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
-{
-       return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
-}
-
-// ==============
-// Event Handlers
-// ==============
-
-void nades_GiveBonus(entity player, float score);
-
-void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
-{
-       entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
-       entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
-       entity player_team_flag = NULL, tmp_entity;
-       float old_time, new_time;
-
-       if(!player) { return; } // without someone to give the reward to, we can't possibly cap
-       if(CTF_DIFFTEAM(player, flag)) { return; }
-       if((flag.cnt || enemy_flag.cnt) && flag.cnt != enemy_flag.cnt) { return; } // this should catch some edge cases (capturing grouped flag at ungrouped flag disallowed etc)
-
-       if (toucher.goalentity == flag.bot_basewaypoint)
-               toucher.goalentity_lock_timeout = 0;
-
-       if(ctf_oneflag)
-       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
-       if(SAME_TEAM(tmp_entity, player))
-       {
-               player_team_flag = tmp_entity;
-               break;
-       }
-
-       nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
-
-       player.throw_prevtime = time;
-       player.throw_count = 0;
-
-       // messages and sounds
-       Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE));
-       ctf_CaptureRecord(enemy_flag, player);
-       _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
-
-       switch(capturetype)
-       {
-               case CAPTURE_NORMAL: ctf_EventLog("capture", enemy_flag.team, player); break;
-               case CAPTURE_DROPPED: ctf_EventLog("droppedcapture", enemy_flag.team, player); break;
-               default: break;
-       }
-
-       // scoring
-       float pscore = 0;
-       if(enemy_flag.score_capture || flag.score_capture)
-               pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5);
-       GameRules_scoring_add_team(player, SCORE, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
-       float capscore = 0;
-       if(enemy_flag.score_team_capture || flag.score_team_capture)
-               capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5);
-       GameRules_scoring_add_team(player, CTF_CAPS, ((capscore) ? capscore : 1));
-
-       old_time = GameRules_scoring_add(player, CTF_CAPTIME, 0);
-       new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
-       if(!old_time || new_time < old_time)
-               GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
-
-       // effects
-       Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
-       //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
-
-       // other
-       if(capturetype == CAPTURE_NORMAL)
-       {
-               WaypointSprite_Kill(player.wps_flagcarrier);
-               if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
-
-               if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
-                       { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
-       }
-
-       flag.enemy = toucher;
-
-       // reset the flag
-       player.next_take_time = time + autocvar_g_ctf_flag_collect_delay;
-       ctf_RespawnFlag(enemy_flag);
-}
-
-void ctf_Handle_Return(entity flag, entity player)
-{
-       // messages and sounds
-       if(IS_MONSTER(player))
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name);
-       }
-       else if(flag.team)
-       {
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
-       }
-       _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
-       ctf_EventLog("return", flag.team, player);
-
-       // scoring
-       if(IS_PLAYER(player))
-       {
-               GameRules_scoring_add_team(player, SCORE, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
-               GameRules_scoring_add(player, CTF_RETURNS, 1); // add to count of returns
-
-               nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
-       }
-
-       TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
-
-       if(flag.ctf_dropper)
-       {
-               GameRules_scoring_add(flag.ctf_dropper, SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
-               ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag
-               flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
-       }
-
-       // other
-       if(player.flagcarried == flag)
-               WaypointSprite_Kill(player.wps_flagcarrier);
-
-       flag.enemy = player;
-
-       // reset the flag
-       ctf_RespawnFlag(flag);
-}
-
-void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
-{
-       // declarations
-       float pickup_dropped_score; // used to calculate dropped pickup score
-
-       // attach the flag to the player
-       flag.owner = player;
-       player.flagcarried = flag;
-       GameRules_scoring_vip(player, true);
-       if(player.vehicle)
-       {
-               setattachment(flag, player.vehicle, "");
-               setorigin(flag, VEHICLE_FLAG_OFFSET);
-               flag.scale = VEHICLE_FLAG_SCALE;
-       }
-       else
-       {
-               setattachment(flag, player, "");
-               setorigin(flag, FLAG_CARRY_OFFSET);
-       }
-
-       // flag setup
-       set_movetype(flag, MOVETYPE_NONE);
-       flag.takedamage = DAMAGE_NO;
-       flag.solid = SOLID_NOT;
-       flag.angles = '0 0 0';
-       flag.ctf_status = FLAG_CARRY;
-
-       switch(pickuptype)
-       {
-               case PICKUP_BASE: flag.ctf_pickuptime = time; break; // used for timing runs
-               case PICKUP_DROPPED: flag.health = flag.max_flag_health; break; // reset health/return timelimit
-               default: break;
-       }
-
-       // messages and sounds
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
-       if(ctf_stalemate)
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
-       if(!flag.team)
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
-       else if(CTF_DIFFTEAM(player, flag))
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
-       else
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
-
-       Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
-
-       if(!flag.team)
-               FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
-
-       if(flag.team)
-               FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
-                       if(CTF_SAMETEAM(flag, it))
-                       if(SAME_TEAM(player, it))
-                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
-                       else
-                               Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
-               });
-
-       _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
-
-       // scoring
-       GameRules_scoring_add(player, CTF_PICKUPS, 1);
-       nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
-       switch(pickuptype)
-       {
-               case PICKUP_BASE:
-               {
-                       GameRules_scoring_add_team(player, SCORE, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
-                       ctf_EventLog("steal", flag.team, player);
-                       break;
-               }
-
-               case PICKUP_DROPPED:
-               {
-                       pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
-                       pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
-                       LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
-                       GameRules_scoring_add_team(player, SCORE, pickup_dropped_score);
-                       ctf_EventLog("pickup", flag.team, player);
-                       break;
-               }
-
-               default: break;
-       }
-
-       // speedrunning
-       if(pickuptype == PICKUP_BASE)
-       {
-               flag.speedrunning = player.speedrunning; // if speedrunning, flag will flag-return and teleport the owner back after the record
-               if((player.speedrunning) && (ctf_captimerecord))
-                       ctf_FakeTimeLimit(player, time + ctf_captimerecord);
-       }
-
-       // effects
-       Send_Effect_(flag.toucheffect, player.origin, '0 0 0', 1);
-
-       // waypoints
-       if(pickuptype == PICKUP_DROPPED) { WaypointSprite_Kill(flag.wps_flagdropped); }
-       ctf_FlagcarrierWaypoints(player);
-       WaypointSprite_Ping(player.wps_flagcarrier);
-}
-
-
-// ===================
-// Main Flag Functions
-// ===================
-
-void ctf_CheckFlagReturn(entity flag, int returntype)
-{
-       if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
-       {
-               if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
-
-               if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
-               {
-                       switch(returntype)
-                       {
-                               case RETURN_DROPPED:
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break;
-                               case RETURN_DAMAGE:
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
-                               case RETURN_SPEEDRUN:
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), TIME_ENCODE(ctf_captimerecord)); break;
-                               case RETURN_NEEDKILL:
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
-                               default:
-                               case RETURN_TIMEOUT:
-                                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break;
-                       }
-                       _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
-                       ctf_EventLog("returned", flag.team, NULL);
-                       flag.enemy = NULL;
-                       ctf_RespawnFlag(flag);
-               }
-       }
-}
-
-bool ctf_Stalemate_Customize(entity this, entity client)
-{
-       // make spectators see what the player would see
-       entity e = WaypointSprite_getviewentity(client);
-       entity wp_owner = this.owner;
-
-       // team waypoints
-       //if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
-       if(SAME_TEAM(wp_owner, e)) { return false; }
-       if(!IS_PLAYER(e)) { return false; }
-
-       return true;
-}
-
-void ctf_CheckStalemate()
-{
-       // declarations
-       int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
-       entity tmp_entity;
-
-       entity ctf_staleflaglist = NULL; // reset the list, we need to build the list each time this function runs
-
-       // build list of stale flags
-       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
-       {
-               if(autocvar_g_ctf_stalemate)
-               if(tmp_entity.ctf_status != FLAG_BASE)
-               if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time || !tmp_entity.team) // instant stalemate in oneflag
-               {
-                       tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist
-                       ctf_staleflaglist = tmp_entity;
-
-                       switch(tmp_entity.team)
-                       {
-                               case NUM_TEAM_1: ++stale_red_flags; break;
-                               case NUM_TEAM_2: ++stale_blue_flags; break;
-                               case NUM_TEAM_3: ++stale_yellow_flags; break;
-                               case NUM_TEAM_4: ++stale_pink_flags; break;
-                               default: ++stale_neutral_flags; break;
-                       }
-               }
-       }
-
-       if(ctf_oneflag)
-               stale_flags = (stale_neutral_flags >= 1);
-       else
-               stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
-
-       if(ctf_oneflag && stale_flags == 1)
-               ctf_stalemate = true;
-       else if(stale_flags >= 2)
-               ctf_stalemate = true;
-       else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
-               { ctf_stalemate = false; wpforenemy_announced = false; }
-       else if(stale_flags < 2 && autocvar_g_ctf_stalemate_endcondition == 1)
-               { ctf_stalemate = false; wpforenemy_announced = false; }
-
-       // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
-       if(ctf_stalemate)
-       {
-               for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
-               {
-                       if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
-                       {
-                               entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, NULL, 0, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG);
-                               wp.colormod = WPCOLOR_ENEMYFC(tmp_entity.owner.team);
-                               setcefc(tmp_entity.owner.wps_enemyflagcarrier, ctf_Stalemate_Customize);
-                       }
-               }
-
-               if (!wpforenemy_announced)
-               {
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); });
-
-                       wpforenemy_announced = true;
-               }
-       }
-}
-
-void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(ITEM_DAMAGE_NEEDKILL(deathtype))
-       {
-               if(autocvar_g_ctf_flag_return_damage_delay)
-                       this.ctf_flagdamaged_byworld = true;
-               else
-               {
-                       this.health = 0;
-                       ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
-               }
-               return;
-       }
-       if(autocvar_g_ctf_flag_return_damage)
-       {
-               // reduce health and check if it should be returned
-               this.health = this.health - damage;
-               ctf_CheckFlagReturn(this, RETURN_DAMAGE);
-               return;
-       }
-}
-
-void ctf_FlagThink(entity this)
-{
-       // declarations
-       entity tmp_entity;
-
-       this.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
-
-       // captureshield
-       if(this == ctf_worldflaglist) // only for the first flag
-               FOREACH_CLIENT(true, { ctf_CaptureShield_Update(it, 1); }); // release shield only
-
-       // sanity checks
-       if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
-               LOG_TRACE("wtf the flag got squashed?");
-               tracebox(this.origin, this.m_mins, this.m_maxs, this.origin, MOVE_NOMONSTERS, this);
-               if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
-                       setsize(this, this.m_mins, this.m_maxs);
-       }
-
-       // main think method
-       switch(this.ctf_status)
-       {
-               case FLAG_BASE:
-               {
-                       if(autocvar_g_ctf_dropped_capture_radius)
-                       {
-                               for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
-                                       if(tmp_entity.ctf_status == FLAG_DROPPED)
-                                       if(vdist(this.origin - tmp_entity.origin, <, autocvar_g_ctf_dropped_capture_radius))
-                                       if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
-                                               ctf_Handle_Capture(this, tmp_entity, CAPTURE_DROPPED);
-                       }
-                       return;
-               }
-
-               case FLAG_DROPPED:
-               {
-                       this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
-
-                       if(autocvar_g_ctf_flag_dropped_floatinwater)
-                       {
-                               vector midpoint = ((this.absmin + this.absmax) * 0.5);
-                               if(pointcontents(midpoint) == CONTENT_WATER)
-                               {
-                                       this.velocity = this.velocity * 0.5;
-
-                                       if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
-                                               { this.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
-                                       else
-                                               { set_movetype(this, MOVETYPE_FLY); }
-                               }
-                               else if(this.move_movetype == MOVETYPE_FLY) { set_movetype(this, MOVETYPE_TOSS); }
-                       }
-                       if(autocvar_g_ctf_flag_return_dropped)
-                       {
-                               if((vdist(this.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_dropped)) || (autocvar_g_ctf_flag_return_dropped == -1))
-                               {
-                                       this.health = 0;
-                                       ctf_CheckFlagReturn(this, RETURN_DROPPED);
-                                       return;
-                               }
-                       }
-                       if(this.ctf_flagdamaged_byworld)
-                       {
-                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
-                               ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
-                               return;
-                       }
-                       else if(autocvar_g_ctf_flag_return_time)
-                       {
-                               this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
-                               ctf_CheckFlagReturn(this, RETURN_TIMEOUT);
-                               return;
-                       }
-                       return;
-               }
-
-               case FLAG_CARRY:
-               {
-                       if(this.speedrunning && ctf_captimerecord && (time >= this.ctf_pickuptime + ctf_captimerecord))
-                       {
-                               this.health = 0;
-                               ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
-
-                               CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
-                               ImpulseCommands(this.owner);
-                       }
-                       if(autocvar_g_ctf_stalemate)
-                       {
-                               if(time >= wpforenemy_nextthink)
-                               {
-                                       ctf_CheckStalemate();
-                                       wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
-                               }
-                       }
-                       if(CTF_SAMETEAM(this, this.owner) && this.team)
-                       {
-                               if(autocvar_g_ctf_flag_return) // drop the flag if reverse status has changed
-                                       ctf_Handle_Throw(this.owner, NULL, DROP_THROW);
-                               else if(vdist(this.owner.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_carried_radius))
-                                       ctf_Handle_Return(this, this.owner);
-                       }
-                       return;
-               }
-
-               case FLAG_PASSING:
-               {
-                       vector targ_origin = ((this.pass_target.absmin + this.pass_target.absmax) * 0.5);
-                       targ_origin = WarpZone_RefSys_TransformOrigin(this.pass_target, this, targ_origin); // origin of target as seen by the flag (us)
-                       WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
-
-                       if((this.pass_target == NULL)
-                               || (IS_DEAD(this.pass_target))
-                               || (this.pass_target.flagcarried)
-                               || (vdist(this.origin - targ_origin, >, autocvar_g_ctf_pass_radius))
-                               || ((trace_fraction < 1) && (trace_ent != this.pass_target))
-                               || (time > this.ctf_droptime + autocvar_g_ctf_pass_timelimit))
-                       {
-                               // give up, pass failed
-                               ctf_Handle_Drop(this, NULL, DROP_PASS);
-                       }
-                       else
-                       {
-                               // still a viable target, go for it
-                               ctf_CalculatePassVelocity(this, targ_origin, this.origin, true);
-                       }
-                       return;
-               }
-
-               default: // this should never happen
-               {
-                       LOG_TRACE("ctf_FlagThink(): Flag exists with no status?");
-                       return;
-               }
-       }
-}
-
-METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
-{
-       return = false;
-       if(game_stopped) return;
-       if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
-
-       bool is_not_monster = (!IS_MONSTER(toucher));
-
-       // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
-       if(ITEM_TOUCH_NEEDKILL())
-       {
-               if(!autocvar_g_ctf_flag_return_damage_delay)
-               {
-                       flag.health = 0;
-                       ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
-               }
-               if(!flag.ctf_flagdamaged_byworld) { return; }
-       }
-
-       // special touch behaviors
-       if(STAT(FROZEN, toucher)) { return; }
-       else if(IS_VEHICLE(toucher))
-       {
-               if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
-                       toucher = toucher.owner; // the player is actually the vehicle owner, not other
-               else
-                       return; // do nothing
-       }
-       else if(IS_MONSTER(toucher))
-       {
-               if(!autocvar_g_ctf_allow_monster_touch)
-                       return; // do nothing
-       }
-       else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
-       {
-               if(time > flag.wait) // if we haven't in a while, play a sound/effect
-               {
-                       Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
-                       _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
-                       flag.wait = time + FLAG_TOUCHRATE;
-               }
-               return;
-       }
-       else if(IS_DEAD(toucher)) { return; }
-
-       switch(flag.ctf_status)
-       {
-               case FLAG_BASE:
-               {
-                       if(ctf_oneflag)
-                       {
-                               if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
-                                       ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
-                               else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
-                                       ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
-                       }
-                       else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
-                               ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
-                       else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
-                       {
-                               ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
-                               ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // now pickup the flag
-                       }
-                       else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
-                               ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
-                       break;
-               }
-
-               case FLAG_DROPPED:
-               {
-                       if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
-                               ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
-                       else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
-                               ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
-                       break;
-               }
-
-               case FLAG_CARRY:
-               {
-                       LOG_TRACE("Someone touched a flag even though it was being carried?");
-                       break;
-               }
-
-               case FLAG_PASSING:
-               {
-                       if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
-                       {
-                               if(DIFF_TEAM(toucher, flag.pass_sender))
-                               {
-                                       if(ctf_Immediate_Return_Allowed(flag, toucher))
-                                               ctf_Handle_Return(flag, toucher);
-                                       else if(is_not_monster && (!toucher.flagcarried))
-                                               ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
-                               }
-                               else if(!toucher.flagcarried)
-                                       ctf_Handle_Retrieve(flag, toucher);
-                       }
-                       break;
-               }
-       }
-}
-
-.float last_respawn;
-void ctf_RespawnFlag(entity flag)
-{
-       // check for flag respawn being called twice in a row
-       if(flag.last_respawn > time - 0.5)
-               { backtrace("flag respawn called twice quickly! please notify Samual about this..."); }
-
-       flag.last_respawn = time;
-
-       // reset the player (if there is one)
-       if((flag.owner) && (flag.owner.flagcarried == flag))
-       {
-               WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
-               WaypointSprite_Kill(flag.owner.wps_flagreturn);
-               WaypointSprite_Kill(flag.wps_flagcarrier);
-
-               flag.owner.flagcarried = NULL;
-               GameRules_scoring_vip(flag.owner, false);
-
-               if(flag.speedrunning)
-                       ctf_FakeTimeLimit(flag.owner, -1);
-       }
-
-       if((flag.owner) && (flag.owner.vehicle))
-               flag.scale = FLAG_SCALE;
-
-       if(flag.ctf_status == FLAG_DROPPED)
-               { WaypointSprite_Kill(flag.wps_flagdropped); }
-
-       // reset the flag
-       setattachment(flag, NULL, "");
-       setorigin(flag, flag.ctf_spawnorigin);
-
-       set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
-       flag.takedamage = DAMAGE_NO;
-       flag.health = flag.max_flag_health;
-       flag.solid = SOLID_TRIGGER;
-       flag.velocity = '0 0 0';
-       flag.angles = flag.mangle;
-       flag.flags = FL_ITEM | FL_NOTARGET;
-
-       flag.ctf_status = FLAG_BASE;
-       flag.owner = NULL;
-       flag.pass_distance = 0;
-       flag.pass_sender = NULL;
-       flag.pass_target = NULL;
-       flag.ctf_dropper = NULL;
-       flag.ctf_pickuptime = 0;
-       flag.ctf_droptime = 0;
-       flag.ctf_flagdamaged_byworld = false;
-       navigation_dynamicgoal_unset(flag);
-
-       ctf_CheckStalemate();
-}
-
-void ctf_Reset(entity this)
-{
-       if(this.owner && IS_PLAYER(this.owner))
-               ctf_Handle_Throw(this.owner, NULL, DROP_RESET);
-
-       this.enemy = NULL;
-       ctf_RespawnFlag(this);
-}
-
-bool ctf_FlagBase_Customize(entity this, entity client)
-{
-       entity e = WaypointSprite_getviewentity(client);
-       entity wp_owner = this.owner;
-       entity flag = e.flagcarried;
-       if(flag && CTF_SAMETEAM(e, flag))
-               return false;
-       if(flag && (flag.cnt || wp_owner.cnt) && wp_owner.cnt != flag.cnt)
-               return false;
-       return true;
-}
-
-void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map by ctf_FlagSetup()
-{
-       // bot waypoints
-       waypoint_spawnforitem_force(this, this.origin);
-       navigation_dynamicgoal_init(this, true);
-
-       // waypointsprites
-       entity basename;
-       switch (this.team)
-       {
-               case NUM_TEAM_1: basename = WP_FlagBaseRed; break;
-               case NUM_TEAM_2: basename = WP_FlagBaseBlue; break;
-               case NUM_TEAM_3: basename = WP_FlagBaseYellow; break;
-               case NUM_TEAM_4: basename = WP_FlagBasePink; break;
-               default: basename = WP_FlagBaseNeutral; break;
-       }
-
-       entity wp = WaypointSprite_SpawnFixed(basename, this.origin + FLAG_WAYPOINT_OFFSET, this, wps_flagbase, RADARICON_FLAG);
-       wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 1 1');
-       WaypointSprite_UpdateTeamRadar(this.wps_flagbase, RADARICON_FLAG, ((this.team) ? colormapPaletteColor(this.team - 1, false) : '1 1 1'));
-       setcefc(wp, ctf_FlagBase_Customize);
-
-       // captureshield setup
-       ctf_CaptureShield_Spawn(this);
-}
-
-.bool pushable;
-
-void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
-{
-       // main setup
-       flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist
-       ctf_worldflaglist = flag;
-
-       setattachment(flag, NULL, "");
-
-       flag.netname = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
-       flag.team = teamnumber;
-       flag.classname = "item_flag_team";
-       flag.target = "###item###"; // wut?
-       flag.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;
-       flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
-       flag.health = flag.max_flag_health;
-       flag.event_damage = ctf_FlagDamage;
-       flag.pushable = true;
-       flag.teleportable = TELEPORT_NORMAL;
-       flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
-       flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
-       flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
-       if(flag.damagedbycontents)
-               IL_PUSH(g_damagedbycontents, flag);
-       flag.velocity = '0 0 0';
-       flag.mangle = flag.angles;
-       flag.reset = ctf_Reset;
-       settouch(flag, ctf_FlagTouch);
-       setthink(flag, ctf_FlagThink);
-       flag.nextthink = time + FLAG_THINKRATE;
-       flag.ctf_status = FLAG_BASE;
-
-       // crudely force them all to 0
-       if(autocvar_g_ctf_score_ignore_fields)
-               flag.cnt = flag.score_assist = flag.score_team_capture = flag.score_capture = flag.score_drop = flag.score_pickup = flag.score_return = 0;
-
-       string teamname = Static_Team_ColorName_Lower(teamnumber);
-       // appearence
-       if(!flag.scale)                         { flag.scale = FLAG_SCALE; }
-       if(flag.skin == 0)                      { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
-       if(flag.model == "")            { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
-       if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
-       if (flag.passeffect == "")      { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
-       if (flag.capeffect == "")       { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
-
-       // sounds
-#define X(s,b) \
-               if(flag.s == "") flag.s = b; \
-               precache_sound(flag.s);
-
-       X(snd_flag_taken,               strzone(SND(CTF_TAKEN(teamnumber))))
-       X(snd_flag_returned,    strzone(SND(CTF_RETURNED(teamnumber))))
-       X(snd_flag_capture,     strzone(SND(CTF_CAPTURE(teamnumber))))
-       X(snd_flag_dropped,     strzone(SND(CTF_DROPPED(teamnumber))))
-       X(snd_flag_respawn,     strzone(SND(CTF_RESPAWN)))
-       X(snd_flag_touch,               strzone(SND(CTF_TOUCH)))
-       X(snd_flag_pass,                strzone(SND(CTF_PASS)))
-#undef X
-
-       // precache
-       precache_model(flag.model);
-
-       // appearence
-       _setmodel(flag, flag.model); // precision set below
-       setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
-       flag.m_mins = flag.mins; // store these for squash checks
-       flag.m_maxs = flag.maxs;
-       setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
-
-       if(autocvar_g_ctf_flag_glowtrails)
-       {
-               switch(teamnumber)
-               {
-                       case NUM_TEAM_1: flag.glow_color = 251; break;
-                       case NUM_TEAM_2: flag.glow_color = 210; break;
-                       case NUM_TEAM_3: flag.glow_color = 110; break;
-                       case NUM_TEAM_4: flag.glow_color = 145; break;
-                       default:                 flag.glow_color = 254; break;
-               }
-               flag.glow_size = 25;
-               flag.glow_trail = 1;
-       }
-
-       flag.effects |= EF_LOWPRECISION;
-       if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
-       if(autocvar_g_ctf_dynamiclights)
-       {
-               switch(teamnumber)
-               {
-                       case NUM_TEAM_1: flag.effects |= EF_RED; break;
-                       case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
-                       case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
-                       case NUM_TEAM_4: flag.effects |= EF_RED; break;
-                       default:                 flag.effects |= EF_DIMLIGHT; break;
-               }
-       }
-
-       // flag placement
-       if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
-       {
-               flag.dropped_origin = flag.origin;
-               flag.noalign = true;
-               set_movetype(flag, MOVETYPE_NONE);
-       }
-       else // drop to floor, automatically find a platform and set that as spawn origin
-       {
-               flag.noalign = false;
-               droptofloor(flag);
-               set_movetype(flag, MOVETYPE_NONE);
-       }
-
-       InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-// NOTE: LEGACY CODE, needs to be re-written!
-
-void havocbot_ctf_calculate_middlepoint()
-{
-       entity f;
-       vector s = '0 0 0';
-       vector fo = '0 0 0';
-       int n = 0;
-
-       f = ctf_worldflaglist;
-       while (f)
-       {
-               fo = f.origin;
-               s = s + fo;
-               f = f.ctf_worldflagnext;
-               n++;
-       }
-       if(!n)
-               return;
-
-       havocbot_middlepoint = s / n;
-       havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
-
-       havocbot_symmetryaxis_equation = '0 0 0';
-       if(n == 2)
-       {
-               // for symmetrical editing of waypoints
-               entity f1 = ctf_worldflaglist;
-               entity f2 = f1.ctf_worldflagnext;
-               float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
-               float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
-               havocbot_symmetryaxis_equation.x = m;
-               havocbot_symmetryaxis_equation.y = q;
-       }
-       // store number of flags in this otherwise unused vector component
-       havocbot_symmetryaxis_equation.z = n;
-}
-
-
-entity havocbot_ctf_find_flag(entity bot)
-{
-       entity f;
-       f = ctf_worldflaglist;
-       while (f)
-       {
-               if (CTF_SAMETEAM(bot, f))
-                       return f;
-               f = f.ctf_worldflagnext;
-       }
-       return NULL;
-}
-
-entity havocbot_ctf_find_enemy_flag(entity bot)
-{
-       entity f;
-       f = ctf_worldflaglist;
-       while (f)
-       {
-               if(ctf_oneflag)
-               {
-                       if(CTF_DIFFTEAM(bot, f))
-                       {
-                               if(f.team)
-                               {
-                                       if(bot.flagcarried)
-                                               return f;
-                               }
-                               else if(!bot.flagcarried)
-                                       return f;
-                       }
-               }
-               else if (CTF_DIFFTEAM(bot, f))
-                       return f;
-               f = f.ctf_worldflagnext;
-       }
-       return NULL;
-}
-
-int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
-{
-       if (!teamplay)
-               return 0;
-
-       int c = 0;
-
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
-                       continue;
-
-               if(vdist(it.origin - org, <, tc_radius))
-                       ++c;
-       });
-
-       return c;
-}
-
-// unused
-#if 0
-void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale)
-{
-       entity head;
-       head = ctf_worldflaglist;
-       while (head)
-       {
-               if (CTF_SAMETEAM(this, head))
-                       break;
-               head = head.ctf_worldflagnext;
-       }
-       if (head)
-               navigation_routerating(this, head, ratingscale, 10000);
-}
-#endif
-
-void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale)
-{
-       entity head;
-       head = ctf_worldflaglist;
-       while (head)
-       {
-               if (CTF_SAMETEAM(this, head))
-               {
-                       if (this.flagcarried)
-                       if ((this.flagcarried.cnt || head.cnt) && this.flagcarried.cnt != head.cnt)
-                       {
-                               head = head.ctf_worldflagnext; // skip base if it has a different group
-                               continue;
-                       }
-                       break;
-               }
-               head = head.ctf_worldflagnext;
-       }
-       if (!head)
-               return;
-
-       navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale)
-{
-       entity head;
-       head = ctf_worldflaglist;
-       while (head)
-       {
-               if(ctf_oneflag)
-               {
-                       if(CTF_DIFFTEAM(this, head))
-                       {
-                               if(head.team)
-                               {
-                                       if(this.flagcarried)
-                                               break;
-                               }
-                               else if(!this.flagcarried)
-                                       break;
-                       }
-               }
-               else if(CTF_DIFFTEAM(this, head))
-                       break;
-               head = head.ctf_worldflagnext;
-       }
-       if (head)
-               navigation_routerating(this, head, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemybase(entity this, float ratingscale)
-{
-       if (!bot_waypoints_for_items)
-       {
-               havocbot_goalrating_ctf_enemyflag(this, ratingscale);
-               return;
-       }
-
-       entity head;
-
-       head = havocbot_ctf_find_enemy_flag(this);
-
-       if (!head)
-               return;
-
-       navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_ourstolenflag(entity this, float ratingscale)
-{
-       entity mf;
-
-       mf = havocbot_ctf_find_flag(this);
-
-       if(mf.ctf_status == FLAG_BASE)
-               return;
-
-       if(mf.tag_entity)
-               navigation_routerating(this, mf.tag_entity, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector org, float df_radius)
-{
-       entity head;
-       head = ctf_worldflaglist;
-       while (head)
-       {
-               // flag is out in the field
-               if(head.ctf_status != FLAG_BASE)
-               if(head.tag_entity==NULL)       // dropped
-               {
-                       if(df_radius)
-                       {
-                               if(vdist(org - head.origin, <, df_radius))
-                                       navigation_routerating(this, head, ratingscale, 10000);
-                       }
-                       else
-                               navigation_routerating(this, head, ratingscale, 10000);
-               }
-
-               head = head.ctf_worldflagnext;
-       }
-}
-
-void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
-{
-       IL_EACH(g_items, it.bot_pickup,
-       {
-               // gather health and armor only
-               if (it.solid)
-               if (it.health || it.armorvalue)
-               if (vdist(it.origin - org, <, sradius))
-               {
-                       // get the value of the item
-                       float t = it.bot_pickupevalfunc(this, it) * 0.0001;
-                       if (t > 0)
-                               navigation_routerating(this, it, t * ratingscale, 500);
-               }
-       });
-}
-
-void havocbot_ctf_reset_role(entity this)
-{
-       float cdefense, cmiddle, coffense;
-       entity mf, ef;
-       float c;
-
-       if(IS_DEAD(this))
-               return;
-
-       // Check ctf flags
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       mf = havocbot_ctf_find_flag(this);
-       ef = havocbot_ctf_find_enemy_flag(this);
-
-       // Retrieve stolen flag
-       if(mf.ctf_status!=FLAG_BASE)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
-               return;
-       }
-
-       // If enemy flag is taken go to the middle to intercept pursuers
-       if(ef.ctf_status!=FLAG_BASE)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
-               return;
-       }
-
-       // if there is only me on the team switch to offense
-       c = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
-
-       if(c==1)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
-               return;
-       }
-
-       // Evaluate best position to take
-       // Count mates on middle position
-       cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
-
-       // Count mates on defense position
-       cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
-
-       // Count mates on offense position
-       coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
-
-       if(cdefense<=coffense)
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
-       else if(coffense<=cmiddle)
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
-       else
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
-}
-
-void havocbot_role_ctf_carrier(entity this)
-{
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried == NULL)
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               if(ctf_oneflag)
-                       havocbot_goalrating_ctf_enemybase(this, 50000);
-               else
-                       havocbot_goalrating_ctf_ourbase(this, 50000);
-
-               if(this.health<100)
-                       havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-
-               entity head = ctf_worldflaglist;
-               while (head)
-               {
-                       if (this.goalentity == head.bot_basewaypoint)
-                       {
-                               this.goalentity_lock_timeout = time + 5;
-                               break;
-                       }
-                       head = head.ctf_worldflagnext;
-               }
-
-               if (this.goalentity)
-                       this.havocbot_cantfindflag = time + 10;
-               else if (time > this.havocbot_cantfindflag)
-               {
-                       // Can't navigate to my own base, suicide!
-                       // TODO: drop it and wander around
-                       Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
-                       return;
-               }
-       }
-}
-
-void havocbot_role_ctf_escort(entity this)
-{
-       entity mf, ef;
-
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       // If enemy flag is back on the base switch to previous role
-       ef = havocbot_ctf_find_enemy_flag(this);
-       if(ef.ctf_status==FLAG_BASE)
-       {
-               this.havocbot_role = this.havocbot_previous_role;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       // If the flag carrier reached the base switch to defense
-       mf = havocbot_ctf_find_flag(this);
-       if(mf.ctf_status!=FLAG_BASE)
-       if(vdist(ef.origin - mf.dropped_origin, <, 300))
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
-               return;
-       }
-
-       // Set the role timeout if necessary
-       if (!this.havocbot_role_timeout)
-       {
-               this.havocbot_role_timeout = time + random() * 30 + 60;
-       }
-
-       // If nothing happened just switch to previous role
-       if (time > this.havocbot_role_timeout)
-       {
-               this.havocbot_role = this.havocbot_previous_role;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       // Chase the flag carrier
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               havocbot_goalrating_ctf_enemyflag(this, 30000);
-               havocbot_goalrating_ctf_ourstolenflag(this, 40000);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ctf_offense(entity this)
-{
-       entity mf, ef;
-       vector pos;
-
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       // Check flags
-       mf = havocbot_ctf_find_flag(this);
-       ef = havocbot_ctf_find_enemy_flag(this);
-
-       // Own flag stolen
-       if(mf.ctf_status!=FLAG_BASE)
-       {
-               if(mf.tag_entity)
-                       pos = mf.tag_entity.origin;
-               else
-                       pos = mf.origin;
-
-               // Try to get it if closer than the enemy base
-               if(vlen2(this.origin-ef.dropped_origin)>vlen2(this.origin-pos))
-               {
-                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
-                       return;
-               }
-       }
-
-       // Escort flag carrier
-       if(ef.ctf_status!=FLAG_BASE)
-       {
-               if(ef.tag_entity)
-                       pos = ef.tag_entity.origin;
-               else
-                       pos = ef.origin;
-
-               if(vdist(pos - mf.dropped_origin, >, 700))
-               {
-                       havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_ESCORT);
-                       return;
-               }
-       }
-
-       // About to fail, switch to middlefield
-       if(this.health<50)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
-               return;
-       }
-
-       // Set the role timeout if necessary
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + 120;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_enemybase(this, 20000);
-               havocbot_goalrating_items(this, 5000, this.origin, 1000);
-               havocbot_goalrating_items(this, 1000, this.origin, 10000);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-// Retriever (temporary role):
-void havocbot_role_ctf_retriever(entity this)
-{
-       entity mf;
-
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       // If flag is back on the base switch to previous role
-       mf = havocbot_ctf_find_flag(this);
-       if(mf.ctf_status==FLAG_BASE)
-       {
-               if (mf.enemy == this) // did this bot return the flag?
-                       navigation_goalrating_timeout_force(this);
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + 20;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               float rt_radius;
-               rt_radius = 10000;
-
-               navigation_goalrating_start(this);
-
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
-               havocbot_goalrating_ctf_enemybase(this, 30000);
-               havocbot_goalrating_items(this, 500, this.origin, rt_radius);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ctf_middle(entity this)
-{
-       entity mf;
-
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       mf = havocbot_ctf_find_flag(this);
-       if(mf.ctf_status!=FLAG_BASE)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + 10;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               vector org;
-
-               org = havocbot_middlepoint;
-               org.z = this.origin.z;
-
-               navigation_goalrating_start(this);
-
-               havocbot_goalrating_ctf_ourstolenflag(this, 50000);
-               havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
-               havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
-               havocbot_goalrating_items(this, 2500, this.origin, 10000);
-               havocbot_goalrating_ctf_enemybase(this, 2500);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ctf_defense(entity this)
-{
-       entity mf;
-
-       if(IS_DEAD(this))
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-
-       if (this.flagcarried)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
-               return;
-       }
-
-       // If own flag was captured
-       mf = havocbot_ctf_find_flag(this);
-       if(mf.ctf_status!=FLAG_BASE)
-       {
-               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + 30;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               havocbot_ctf_reset_role(this);
-               return;
-       }
-       if (navigation_goalrating_timeout(this))
-       {
-               vector org = mf.dropped_origin;
-
-               navigation_goalrating_start(this);
-
-               // if enemies are closer to our base, go there
-               entity closestplayer = NULL;
-               float distance, bestdistance = 10000;
-               FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
-                       distance = vlen(org - it.origin);
-                       if(distance<bestdistance)
-                       {
-                               closestplayer = it;
-                               bestdistance = distance;
-                       }
-               });
-
-               if(closestplayer)
-               if(DIFF_TEAM(closestplayer, this))
-               if(vdist(org - this.origin, >, 1000))
-               if(checkpvs(this.origin,closestplayer)||random()<0.5)
-                       havocbot_goalrating_ctf_ourbase(this, 30000);
-
-               havocbot_goalrating_ctf_ourstolenflag(this, 20000);
-               havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
-               havocbot_goalrating_items(this, 5000, this.origin, 10000);
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ctf_setrole(entity bot, int role)
-{
-       string s = "(null)";
-       switch(role)
-       {
-               case HAVOCBOT_CTF_ROLE_CARRIER:
-                       s = "carrier";
-                       bot.havocbot_role = havocbot_role_ctf_carrier;
-                       bot.havocbot_role_timeout = 0;
-                       bot.havocbot_cantfindflag = time + 10;
-                       if (bot.havocbot_previous_role != bot.havocbot_role)
-                               navigation_goalrating_timeout_force(bot);
-                       break;
-               case HAVOCBOT_CTF_ROLE_DEFENSE:
-                       s = "defense";
-                       bot.havocbot_role = havocbot_role_ctf_defense;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_CTF_ROLE_MIDDLE:
-                       s = "middle";
-                       bot.havocbot_role = havocbot_role_ctf_middle;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_CTF_ROLE_OFFENSE:
-                       s = "offense";
-                       bot.havocbot_role = havocbot_role_ctf_offense;
-                       bot.havocbot_role_timeout = 0;
-                       break;
-               case HAVOCBOT_CTF_ROLE_RETRIEVER:
-                       s = "retriever";
-                       bot.havocbot_previous_role = bot.havocbot_role;
-                       bot.havocbot_role = havocbot_role_ctf_retriever;
-                       bot.havocbot_role_timeout = time + 10;
-                       if (bot.havocbot_previous_role != bot.havocbot_role)
-                               navigation_goalrating_timeout_expire(bot, 2);
-                       break;
-               case HAVOCBOT_CTF_ROLE_ESCORT:
-                       s = "escort";
-                       bot.havocbot_previous_role = bot.havocbot_role;
-                       bot.havocbot_role = havocbot_role_ctf_escort;
-                       bot.havocbot_role_timeout = time + 30;
-                       if (bot.havocbot_previous_role != bot.havocbot_role)
-                               navigation_goalrating_timeout_expire(bot, 2);
-                       break;
-       }
-       LOG_TRACE(bot.netname, " switched to ", s);
-}
-
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       int t = 0, t2 = 0, t3 = 0;
-       bool b1 = false, b2 = false, b3 = false, b4 = false, b5 = false; // TODO: kill this, we WANT to show the other flags, somehow! (note: also means you don't see if you're FC)
-
-       // initially clear items so they can be set as necessary later.
-       STAT(CTF_FLAGSTATUS, player) &= ~(CTF_RED_FLAG_CARRYING         | CTF_RED_FLAG_TAKEN            | CTF_RED_FLAG_LOST
-                                                  | CTF_BLUE_FLAG_CARRYING             | CTF_BLUE_FLAG_TAKEN           | CTF_BLUE_FLAG_LOST
-                                                  | CTF_YELLOW_FLAG_CARRYING   | CTF_YELLOW_FLAG_TAKEN         | CTF_YELLOW_FLAG_LOST
-                                                  | CTF_PINK_FLAG_CARRYING     | CTF_PINK_FLAG_TAKEN           | CTF_PINK_FLAG_LOST
-                                                  | CTF_NEUTRAL_FLAG_CARRYING  | CTF_NEUTRAL_FLAG_TAKEN        | CTF_NEUTRAL_FLAG_LOST
-                                                  | CTF_FLAG_NEUTRAL | CTF_SHIELDED | CTF_STALEMATE);
-
-       // scan through all the flags and notify the client about them
-       for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
-       {
-               if(flag.team == NUM_TEAM_1 && !b1) { b1 = true; t = CTF_RED_FLAG_CARRYING;              t2 = CTF_RED_FLAG_TAKEN;                t3 = CTF_RED_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_2 && !b2) { b2 = true; t = CTF_BLUE_FLAG_CARRYING;             t2 = CTF_BLUE_FLAG_TAKEN;               t3 = CTF_BLUE_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_3 && !b3) { b3 = true; t = CTF_YELLOW_FLAG_CARRYING;   t2 = CTF_YELLOW_FLAG_TAKEN;             t3 = CTF_YELLOW_FLAG_LOST; }
-               if(flag.team == NUM_TEAM_4 && !b4) { b4 = true; t = CTF_PINK_FLAG_CARRYING;             t2 = CTF_PINK_FLAG_TAKEN;               t3 = CTF_PINK_FLAG_LOST; }
-               if(flag.team == 0 && !b5)                  { b5 = true; t = CTF_NEUTRAL_FLAG_CARRYING;  t2 = CTF_NEUTRAL_FLAG_TAKEN;    t3 = CTF_NEUTRAL_FLAG_LOST; STAT(CTF_FLAGSTATUS, player) |= CTF_FLAG_NEUTRAL; }
-
-               switch(flag.ctf_status)
-               {
-                       case FLAG_PASSING:
-                       case FLAG_CARRY:
-                       {
-                               if((flag.owner == player) || (flag.pass_sender == player))
-                                       STAT(CTF_FLAGSTATUS, player) |= t; // carrying: player is currently carrying the flag
-                               else
-                                       STAT(CTF_FLAGSTATUS, player) |= t2; // taken: someone else is carrying the flag
-                               break;
-                       }
-                       case FLAG_DROPPED:
-                       {
-                               STAT(CTF_FLAGSTATUS, player) |= t3; // lost: the flag is dropped somewhere on the map
-                               break;
-                       }
-               }
-       }
-
-       // item for stopping players from capturing the flag too often
-       if(player.ctf_captureshielded)
-               STAT(CTF_FLAGSTATUS, player) |= CTF_SHIELDED;
-
-       if(ctf_stalemate)
-               STAT(CTF_FLAGSTATUS, player) |= CTF_STALEMATE;
-
-       // update the health of the flag carrier waypointsprite
-       if(player.wps_flagcarrier)
-               WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
-}
-
-MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_damage = M_ARGV(4, float);
-       vector frag_force = M_ARGV(6, vector);
-
-       if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
-       {
-               if(frag_target == frag_attacker) // damage done to yourself
-               {
-                       frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor;
-                       frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor;
-               }
-               else // damage done to everyone else
-               {
-                       frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor;
-                       frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
-               }
-
-               M_ARGV(4, float) = frag_damage;
-               M_ARGV(6, vector) = frag_force;
-       }
-       else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
-       {
-               if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
-               if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
-               {
-                       frag_target.wps_helpme_time = time;
-                       WaypointSprite_HelpMePing(frag_target.wps_flagcarrier);
-               }
-               // todo: add notification for when flag carrier needs help?
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
-       {
-               GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
-               GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
-       }
-
-       if(frag_target.flagcarried)
-       {
-               entity tmp_entity = frag_target.flagcarried;
-               ctf_Handle_Throw(frag_target, NULL, DROP_NORMAL);
-               tmp_entity.ctf_dropper = NULL;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
-{
-       M_ARGV(2, float) = 0; // frag score
-       return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true
-}
-
-void ctf_RemovePlayer(entity player)
-{
-       if(player.flagcarried)
-               { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
-
-       for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
-       {
-               if(flag.pass_sender == player) { flag.pass_sender = NULL; }
-               if(flag.pass_target == player) { flag.pass_target = NULL; }
-               if(flag.ctf_dropper == player) { flag.ctf_dropper = NULL; }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       ctf_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       ctf_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, ClientConnect)
-{
-       if(!autocvar_g_ctf_leaderboard)
-               return;
-
-       entity player = M_ARGV(0, entity);
-
-       if(IS_REAL_CLIENT(player))
-       {
-               for(int i = 1; i <= RANKINGS_CNT; ++i)
-               {
-                       race_SendRankings(i, 0, 0, MSG_ONE);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GetPressedKeys)
-{
-       if(!autocvar_g_ctf_leaderboard)
-               return;
-
-       entity player = M_ARGV(0, entity);
-
-       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
-       {
-               if (!player.stored_netname)
-                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
-               if(player.stored_netname != player.netname)
-               {
-                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
-                       strunzone(player.stored_netname);
-                       player.stored_netname = strzone(player.netname);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.flagcarried)
-       if(!autocvar_g_ctf_portalteleport)
-               { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
-{
-       if(MUTATOR_RETURNVALUE || game_stopped) return;
-
-       entity player = M_ARGV(0, entity);
-
-       if((time > player.throw_antispam) && !IS_DEAD(player) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
-       {
-               // pass the flag to a team mate
-               if(autocvar_g_ctf_pass)
-               {
-                       entity head, closest_target = NULL;
-                       head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
-
-                       while(head) // find the closest acceptable target to pass to
-                       {
-                               if(IS_PLAYER(head) && !IS_DEAD(head))
-                               if(head != player && SAME_TEAM(head, player))
-                               if(!head.speedrunning && !head.vehicle)
-                               {
-                                       // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
-                                       vector head_center = WarpZone_UnTransformOrigin(head, CENTER_OR_VIEWOFS(head));
-                                       vector passer_center = CENTER_OR_VIEWOFS(player);
-
-                                       if(ctf_CheckPassDirection(head_center, passer_center, player.v_angle, head.WarpZone_findradius_nearest))
-                                       {
-                                               if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried)
-                                               {
-                                                       if(IS_BOT_CLIENT(head))
-                                                       {
-                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
-                                                               ctf_Handle_Throw(head, player, DROP_PASS);
-                                                       }
-                                                       else
-                                                       {
-                                                               Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname);
-                                                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
-                                                       }
-                                                       player.throw_antispam = time + autocvar_g_ctf_pass_wait;
-                                                       return true;
-                                               }
-                                               else if(player.flagcarried && !head.flagcarried)
-                                               {
-                                                       if(closest_target)
-                                                       {
-                                                               vector closest_target_center = WarpZone_UnTransformOrigin(closest_target, CENTER_OR_VIEWOFS(closest_target));
-                                                               if(vlen2(passer_center - head_center) < vlen2(passer_center - closest_target_center))
-                                                                       { closest_target = head; }
-                                                       }
-                                                       else { closest_target = head; }
-                                               }
-                                       }
-                               }
-                               head = head.chain;
-                       }
-
-                       if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
-               }
-
-               // throw the flag in front of you
-               if(autocvar_g_ctf_throw && player.flagcarried)
-               {
-                       if(player.throw_count == -1)
-                       {
-                               if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_delay)
-                               {
-                                       player.throw_prevtime = time;
-                                       player.throw_count = 1;
-                                       ctf_Handle_Throw(player, NULL, DROP_THROW);
-                                       return true;
-                               }
-                               else
-                               {
-                                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
-                                       return false;
-                               }
-                       }
-                       else
-                       {
-                               if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_time) { player.throw_count = 1; }
-                               else { player.throw_count += 1; }
-                               if(player.throw_count >= autocvar_g_ctf_throw_punish_count) { player.throw_count = -1; }
-
-                               player.throw_prevtime = time;
-                               ctf_Handle_Throw(player, NULL, DROP_THROW);
-                               return true;
-                       }
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, HelpMePing)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
-       {
-               player.wps_helpme_time = time;
-               WaypointSprite_HelpMePing(player.wps_flagcarrier);
-       }
-       else // create a normal help me waypointsprite
-       {
-               WaypointSprite_Spawn(WP_Helpme, waypointsprite_deployed_lifetime, waypointsprite_limitedrange, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_helpme, false, RADARICON_HELPME);
-               WaypointSprite_Ping(player.wps_helpme);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, VehicleEnter)
-{
-       entity player = M_ARGV(0, entity);
-       entity veh = M_ARGV(1, entity);
-
-       if(player.flagcarried)
-       {
-               if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
-               {
-                       ctf_Handle_Throw(player, NULL, DROP_NORMAL);
-               }
-               else
-               {
-                       player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
-                       setattachment(player.flagcarried, veh, "");
-                       setorigin(player.flagcarried, VEHICLE_FLAG_OFFSET);
-                       player.flagcarried.scale = VEHICLE_FLAG_SCALE;
-                       //player.flagcarried.angles = '0 0 0';
-               }
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, VehicleExit)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.flagcarried)
-       {
-               setattachment(player.flagcarried, player, "");
-               setorigin(player.flagcarried, FLAG_CARRY_OFFSET);
-               player.flagcarried.scale = FLAG_SCALE;
-               player.flagcarried.angles = '0 0 0';
-               player.flagcarried.nodrawtoclient = NULL;
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.flagcarried)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN));
-               ctf_RespawnFlag(player.flagcarried);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, MatchEnd)
-{
-       entity flag; // temporary entity for the search method
-
-       for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
-       {
-               switch(flag.ctf_status)
-               {
-                       case FLAG_DROPPED:
-                       case FLAG_PASSING:
-                       {
-                               // lock the flag, game is over
-                               set_movetype(flag, MOVETYPE_NONE);
-                               flag.takedamage = DAMAGE_NO;
-                               flag.solid = SOLID_NOT;
-                               flag.nextthink = false; // stop thinking
-
-                               //dprint("stopping the ", flag.netname, " from moving.\n");
-                               break;
-                       }
-
-                       default:
-                       case FLAG_BASE:
-                       case FLAG_CARRY:
-                       {
-                               // do nothing for these flags
-                               break;
-                       }
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       havocbot_ctf_reset_role(bot);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
-{
-       //M_ARGV(0, float) = ctf_teams;
-       M_ARGV(1, string) = "ctf_team";
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       STAT(CTF_FLAGSTATUS, client) = STAT(CTF_FLAGSTATUS, spectatee);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GetRecords)
-{
-       int record_page = M_ARGV(0, int);
-       string ret_string = M_ARGV(1, string);
-
-       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
-       {
-               if (MapInfo_Get_ByID(i))
-               {
-                       float r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
-
-                       if(!r)
-                               continue;
-
-                       // TODO: uid2name
-                       string h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
-                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
-               }
-       }
-
-       M_ARGV(1, string) = ret_string;
-}
-
-bool superspec_Spectate(entity this, entity targ); // TODO
-void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel); // TODO
-MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
-{
-       entity player = M_ARGV(0, entity);
-       string cmd_name = M_ARGV(1, string);
-       int cmd_argc = M_ARGV(2, int);
-
-       if(IS_PLAYER(player) || MUTATOR_RETURNVALUE || !cvar("g_superspectate")) { return false; }
-
-       if(cmd_name == "followfc")
-       {
-               if(!g_ctf)
-                       return true;
-
-               int _team = 0;
-               bool found = false;
-
-               if(cmd_argc == 2)
-               {
-                       switch(argv(1))
-                       {
-                               case "red":    if(ctf_teams & BIT(0)) _team = NUM_TEAM_1; break;
-                               case "blue":   if(ctf_teams & BIT(1)) _team = NUM_TEAM_2; break;
-                               case "yellow": if(ctf_teams & BIT(2)) _team = NUM_TEAM_3; break;
-                               case "pink":   if(ctf_teams & BIT(3)) _team = NUM_TEAM_4; break;
-                       }
-               }
-
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       if(it.flagcarried && (it.team == _team || _team == 0))
-                       {
-                               found = true;
-                               if(_team == 0 && IS_SPEC(player) && player.enemy == it)
-                                       continue; // already spectating this fc, try another
-                               return superspec_Spectate(player, it);
-                       }
-               });
-
-               if(!found)
-                       superspec_msg("", "", player, "No active flag carrier\n", 1);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
-{
-       entity frag_target = M_ARGV(0, entity);
-
-       if(frag_target.flagcarried)
-               ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
-}
-
-
-// ==========
-// Spawnfuncs
-// ==========
-
-/*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team one (Red).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red and blue as skins 0 and 1...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team1)
-{
-       if(!g_ctf) { delete(this); return; }
-
-       ctf_FlagSetup(NUM_TEAM_1, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team two (Blue).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red and blue as skins 0 and 1...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team2)
-{
-       if(!g_ctf) { delete(this); return; }
-
-       ctf_FlagSetup(NUM_TEAM_2, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team3 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team three (Yellow).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team3)
-{
-       if(!g_ctf) { delete(this); return; }
-
-       ctf_FlagSetup(NUM_TEAM_3, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team4 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team four (Pink).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team4)
-{
-       if(!g_ctf) { delete(this); return; }
-
-       ctf_FlagSetup(NUM_TEAM_4, this);
-}
-
-/*QUAKED spawnfunc_item_flag_neutral (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag (Neutral).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_neutral)
-{
-       if(!g_ctf) { delete(this); return; }
-       if(!cvar("g_ctf_oneflag")) { delete(this); return; }
-
-       ctf_FlagSetup(0, this);
-}
-
-/*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
-Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
-Note: If you use spawnfunc_ctf_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
-Keys:
-"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
-"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
-spawnfunc(ctf_team)
-{
-       if(!g_ctf) { delete(this); return; }
-
-       this.classname = "ctf_team";
-       this.team = this.cnt + 1;
-}
-
-// compatibility for quake maps
-spawnfunc(team_CTF_redflag)    { spawnfunc_item_flag_team1(this);    }
-spawnfunc(team_CTF_blueflag)   { spawnfunc_item_flag_team2(this);    }
-spawnfunc(info_player_team1);
-spawnfunc(team_CTF_redplayer)  { spawnfunc_info_player_team1(this);  }
-spawnfunc(team_CTF_redspawn)   { spawnfunc_info_player_team1(this);  }
-spawnfunc(info_player_team2);
-spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this);  }
-spawnfunc(team_CTF_bluespawn)  { spawnfunc_info_player_team2(this);  }
-
-spawnfunc(team_CTF_neutralflag)        { spawnfunc_item_flag_neutral(this);  }
-spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this);  }
-
-// compatibility for wop maps
-spawnfunc(team_redplayer)      { spawnfunc_info_player_team1(this);  }
-spawnfunc(team_blueplayer)     { spawnfunc_info_player_team2(this);  }
-spawnfunc(team_ctl_redlolly)   { spawnfunc_item_flag_team1(this);    }
-spawnfunc(team_CTL_redlolly)   { spawnfunc_item_flag_team1(this);    }
-spawnfunc(team_ctl_bluelolly)  { spawnfunc_item_flag_team2(this);    }
-spawnfunc(team_CTL_bluelolly)  { spawnfunc_item_flag_team2(this);    }
-
-
-// ==============
-// Initialization
-// ==============
-
-// scoreboard setup
-void ctf_ScoreRules(int teams)
-{
-       CheckAllowedTeams(NULL);
-       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
-        field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
-        field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
-        field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
-        field(SP_CTF_PICKUPS, "pickups", 0);
-        field(SP_CTF_FCKILLS, "fckills", 0);
-        field(SP_CTF_RETURNS, "returns", 0);
-        field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
-       });
-}
-
-// code from here on is just to support maps that don't have flag and team entities
-void ctf_SpawnTeam (string teamname, int teamcolor)
-{
-       entity this = new_pure(ctf_team);
-       this.netname = teamname;
-       this.cnt = teamcolor - 1;
-       this.spawnfunc_checked = true;
-       this.team = teamcolor;
-}
-
-void ctf_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
-{
-       ctf_teams = 0;
-
-       entity tmp_entity;
-       for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
-       {
-               //if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
-               //if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
-
-               switch(tmp_entity.team)
-               {
-                       case NUM_TEAM_1: BITSET_ASSIGN(ctf_teams, BIT(0)); break;
-                       case NUM_TEAM_2: BITSET_ASSIGN(ctf_teams, BIT(1)); break;
-                       case NUM_TEAM_3: BITSET_ASSIGN(ctf_teams, BIT(2)); break;
-                       case NUM_TEAM_4: BITSET_ASSIGN(ctf_teams, BIT(3)); break;
-               }
-               if(tmp_entity.team == 0) { ctf_oneflag = true; }
-       }
-
-       havocbot_ctf_calculate_middlepoint();
-
-       if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
-       {
-               ctf_teams = 0; // so set the default red and blue teams
-               BITSET_ASSIGN(ctf_teams, BIT(0));
-               BITSET_ASSIGN(ctf_teams, BIT(1));
-       }
-
-       //ctf_teams = bound(2, ctf_teams, 4);
-
-       // if no teams are found, spawn defaults
-       if(find(NULL, classname, "ctf_team") == NULL)
-       {
-               LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.");
-               if(ctf_teams & BIT(0))
-                       ctf_SpawnTeam("Red", NUM_TEAM_1);
-               if(ctf_teams & BIT(1))
-                       ctf_SpawnTeam("Blue", NUM_TEAM_2);
-               if(ctf_teams & BIT(2))
-                       ctf_SpawnTeam("Yellow", NUM_TEAM_3);
-               if(ctf_teams & BIT(3))
-                       ctf_SpawnTeam("Pink", NUM_TEAM_4);
-       }
-
-       ctf_ScoreRules(ctf_teams);
-}
-
-void ctf_Initialize()
-{
-       ctf_captimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
-
-       ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
-       ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
-       ctf_captureshield_force = autocvar_g_ctf_shield_force;
-
-       InitializeEntity(NULL, ctf_DelayedInit, INITPRIO_GAMETYPE);
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_ctf.qh b/qcsrc/server/mutators/mutator/gamemode_ctf.qh
deleted file mode 100644 (file)
index 14bf281..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-#pragma once
-
-#ifdef SVQC
-
-#include "../gamemode.qh"
-
-void ctf_Initialize();
-
-REGISTER_MUTATOR(ctf, false)
-{
-    MUTATOR_STATIC();
-    MUTATOR_ONADD
-    {
-        GameRules_teams(true);
-        GameRules_limit_score(autocvar_capturelimit_override);
-        GameRules_limit_lead(autocvar_captureleadlimit_override);
-
-        ctf_Initialize();
-    }
-    return 0;
-}
-
-// used in cheats.qc
-void ctf_RespawnFlag(entity flag);
-
-// score rule declarations
-const int ST_CTF_CAPS = 1;
-
-CLASS(Flag, Pickup)
-    ATTRIB(Flag, m_mins, vector, (PL_MIN_CONST + '0 0 -13') * 1.4); // scaling be damned
-    ATTRIB(Flag, m_maxs, vector, (PL_MAX_CONST + '0 0 -13') * 1.4);
-ENDCLASS(Flag)
-Flag CTF_FLAG; STATIC_INIT(Flag) { CTF_FLAG = NEW(Flag); }
-void ctf_FlagTouch(entity this, entity toucher) { ITEM_HANDLE(Pickup, CTF_FLAG, this, toucher); }
-
-// flag constants // for most of these, there is just one question to be asked: WHYYYYY?
-
-const float FLAG_SCALE = 0.6;
-
-const float FLAG_THINKRATE = 0.2;
-const float FLAG_TOUCHRATE = 0.5;
-const float WPFE_THINKRATE = 0.5;
-
-const vector FLAG_DROP_OFFSET = ('0 0 32');
-const vector FLAG_CARRY_OFFSET = ('-16 0 8');
-#define FLAG_SPAWN_OFFSET ('0 0 1' * (PL_MAX_CONST.z - 13))
-const vector FLAG_WAYPOINT_OFFSET = ('0 0 64');
-const vector FLAG_FLOAT_OFFSET = ('0 0 32');
-const vector FLAG_PASS_ARC_OFFSET = ('0 0 -10');
-
-const vector VEHICLE_FLAG_OFFSET = ('0 0 96');
-const float VEHICLE_FLAG_SCALE = 1.0;
-
-// waypoint colors
-#define WPCOLOR_ENEMYFC(t) ((t) ? colormapPaletteColor(t - 1, false) * 0.75 : '1 1 1')
-#define WPCOLOR_FLAGCARRIER(t) (WP_FlagCarrier.m_color)
-#define WPCOLOR_DROPPEDFLAG(t) ((t) ? ('0.25 0.25 0.25' + colormapPaletteColor(t - 1, false)) * 0.5 : '1 1 1')
-
-// sounds
-#define snd_flag_taken noise
-#define snd_flag_returned noise1
-#define snd_flag_capture noise2
-#define snd_flag_respawn noise3
-.string snd_flag_dropped;
-.string snd_flag_touch;
-.string snd_flag_pass;
-
-// score fields
-.float score_assist;
-.float score_capture;
-.float score_drop; // note: negated
-.float score_pickup;
-.float score_return;
-.float score_team_capture; // shouldn't be too high
-
-// effects
-.string toucheffect;
-.string passeffect;
-.string capeffect;
-
-// list of flags on the map
-entity ctf_worldflaglist;
-.entity ctf_worldflagnext;
-.entity ctf_staleflagnext;
-
-// waypoint sprites
-.entity wps_helpme;
-.entity wps_flagbase;
-.entity wps_flagcarrier;
-.entity wps_flagdropped;
-.entity wps_flagreturn;
-.entity wps_enemyflagcarrier;
-.float wps_helpme_time;
-bool wpforenemy_announced;
-float wpforenemy_nextthink;
-
-// statuses
-const int FLAG_BASE = 1;
-const int FLAG_DROPPED = 2;
-const int FLAG_CARRY = 3;
-const int FLAG_PASSING = 4;
-
-const int DROP_NORMAL = 1;
-const int DROP_THROW = 2;
-const int DROP_PASS = 3;
-const int DROP_RESET = 4;
-
-const int PICKUP_BASE = 1;
-const int PICKUP_DROPPED = 2;
-
-const int CAPTURE_NORMAL = 1;
-const int CAPTURE_DROPPED = 2;
-
-const int RETURN_TIMEOUT = 1;
-const int RETURN_DROPPED = 2;
-const int RETURN_DAMAGE = 3;
-const int RETURN_SPEEDRUN = 4;
-const int RETURN_NEEDKILL = 5;
-
-bool ctf_Stalemate_Customize(entity this, entity client);
-
-void ctf_Handle_Throw(entity player, entity receiver, float droptype);
-
-// flag properties
-#define ctf_spawnorigin dropped_origin
-bool ctf_stalemate; // indicates that a stalemate is active
-float ctf_captimerecord; // record time for capturing the flag
-.float ctf_pickuptime;
-.float ctf_droptime;
-.int ctf_status; // status of the flag (FLAG_BASE, FLAG_DROPPED, FLAG_CARRY declared globally)
-.entity ctf_dropper; // don't allow spam of dropping the flag
-.int max_flag_health;
-.float next_take_time;
-.bool ctf_flagdamaged_byworld;
-int ctf_teams;
-.entity enemy; // when flag is back in the base, it remembers last player who carried/touched the flag, useful to bots
-
-// passing/throwing properties
-.float pass_distance;
-.entity pass_sender;
-.entity pass_target;
-.float throw_antispam;
-.float throw_prevtime;
-.int throw_count;
-
-// CaptureShield: If the player is too bad to be allowed to capture, shield them from taking the flag.
-.bool ctf_captureshielded; // set to 1 if the player is too bad to be allowed to capture
-float ctf_captureshield_min_negscore; // punish at -20 points
-float ctf_captureshield_max_ratio; // punish at most 30% of each team
-float ctf_captureshield_force; // push force of the shield
-
-// 1 flag ctf
-bool ctf_oneflag; // indicates whether or not a neutral flag has been found
-
-// bot player logic
-const int HAVOCBOT_CTF_ROLE_NONE = 0;
-const int HAVOCBOT_CTF_ROLE_DEFENSE = 2;
-const int HAVOCBOT_CTF_ROLE_MIDDLE = 4;
-const int HAVOCBOT_CTF_ROLE_OFFENSE = 8;
-const int HAVOCBOT_CTF_ROLE_CARRIER = 16;
-const int HAVOCBOT_CTF_ROLE_RETRIEVER = 32;
-const int HAVOCBOT_CTF_ROLE_ESCORT = 64;
-
-.bool havocbot_cantfindflag;
-
-void havocbot_role_ctf_setrole(entity bot, int role);
-
-// team checking
-#define CTF_SAMETEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? DIFF_TEAM(a,b) : SAME_TEAM(a,b))
-#define CTF_DIFFTEAM(a,b) ((autocvar_g_ctf_reverse || (ctf_oneflag && autocvar_g_ctf_oneflag_reverse)) ? SAME_TEAM(a,b) : DIFF_TEAM(a,b))
-#endif
-
-const int CTF_RED_FLAG_TAKEN                   = 1;
-const int CTF_RED_FLAG_LOST                            = 2;
-const int CTF_RED_FLAG_CARRYING                        = 3;
-const int CTF_BLUE_FLAG_TAKEN                  = 4;
-const int CTF_BLUE_FLAG_LOST                   = 8;
-const int CTF_BLUE_FLAG_CARRYING               = 12;
-const int CTF_YELLOW_FLAG_TAKEN                        = 16;
-const int CTF_YELLOW_FLAG_LOST                 = 32;
-const int CTF_YELLOW_FLAG_CARRYING             = 48;
-const int CTF_PINK_FLAG_TAKEN                  = 64;
-const int CTF_PINK_FLAG_LOST                   = 128;
-const int CTF_PINK_FLAG_CARRYING               = 192;
-const int CTF_NEUTRAL_FLAG_TAKEN               = 256;
-const int CTF_NEUTRAL_FLAG_LOST                        = 512;
-const int CTF_NEUTRAL_FLAG_CARRYING            = 768;
-const int CTF_FLAG_NEUTRAL                             = 2048;
-const int CTF_SHIELDED                                 = 4096;
-const int CTF_STALEMATE                                        = 8192;
diff --git a/qcsrc/server/mutators/mutator/gamemode_cts.qc b/qcsrc/server/mutators/mutator/gamemode_cts.qc
deleted file mode 100644 (file)
index daaf8a9..0000000
+++ /dev/null
@@ -1,431 +0,0 @@
-#include "gamemode_cts.qh"
-
-#include <server/race.qh>
-#include <server/items.qh>
-
-float autocvar_g_cts_finish_kill_delay;
-bool autocvar_g_cts_selfdamage;
-
-// legacy bot roles
-.float race_checkpoint;
-void havocbot_role_cts(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               bool raw_touch_check = true;
-               int cp = this.race_checkpoint;
-
-               LABEL(search_racecheckpoints)
-               IL_EACH(g_racecheckpoints, true,
-               {
-                       if(it.cnt == cp || cp == -1)
-                       {
-                               // redirect bot to next goal if it touched the waypoint of an untouchable checkpoint
-                               // e.g. checkpoint in front of Stormkeep's warpzone
-                               // the same workaround is applied in Race game mode
-                               if (raw_touch_check && vdist(this.origin - it.nearestwaypoint.origin, <, 30))
-                               {
-                                       cp = race_NextCheckpoint(cp);
-                                       raw_touch_check = false;
-                                       goto search_racecheckpoints;
-                               }
-                               navigation_routerating(this, it, 1000000, 5000);
-                       }
-               });
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void cts_ScoreRules()
-{
-    GameRules_score_enabled(false);
-    GameRules_scoring(0, 0, 0, {
-        if (g_race_qualifying) {
-            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-        } else {
-            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
-            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
-        }
-    });
-}
-
-void cts_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
-{
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":cts:", mode, ":", ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
-}
-
-void KillIndicator_Think(entity this);
-void CTS_ClientKill(entity e) // silent version of ClientKill, used when player finishes a CTS run. Useful to prevent cheating by running back to the start line and starting out with more speed
-{
-    e.killindicator = spawn();
-    e.killindicator.owner = e;
-    setthink(e.killindicator, KillIndicator_Think);
-    e.killindicator.nextthink = time + (e.lip) * 0.05;
-    e.killindicator.cnt = ceil(autocvar_g_cts_finish_kill_delay);
-    e.killindicator.health = 1; // this is used to indicate that it should be silent
-    e.lip = 0;
-}
-
-MUTATOR_HOOKFUNCTION(cts, PlayerPhysics)
-{
-       entity player = M_ARGV(0, entity);
-       float dt = M_ARGV(1, float);
-
-       player.race_movetime_frac += dt;
-       float f = floor(player.race_movetime_frac);
-       player.race_movetime_frac -= f;
-       player.race_movetime_count += f;
-       player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
-
-#ifdef SVQC
-       if(IS_PLAYER(player))
-       {
-               if (player.race_penalty)
-                       if (time > player.race_penalty)
-                               player.race_penalty = 0;
-               if(player.race_penalty)
-               {
-                       player.velocity = '0 0 0';
-                       set_movetype(player, MOVETYPE_NONE);
-                       player.disableclientprediction = 2;
-               }
-       }
-#endif
-
-       // force kbd movement for fairness
-       float wishspeed;
-       vector wishvel;
-
-       // if record times matter
-       // ensure nothing EVIL is being done (i.e. div0_evade)
-       // this hinders joystick users though
-       // but it still gives SOME analog control
-       wishvel.x = fabs(CS(player).movement.x);
-       wishvel.y = fabs(CS(player).movement.y);
-       if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
-       {
-               wishvel.z = 0;
-               wishspeed = vlen(wishvel);
-               if(wishvel.x >= 2 * wishvel.y)
-               {
-                       // pure X motion
-                       if(CS(player).movement.x > 0)
-                               CS(player).movement_x = wishspeed;
-                       else
-                               CS(player).movement_x = -wishspeed;
-                       CS(player).movement_y = 0;
-               }
-               else if(wishvel.y >= 2 * wishvel.x)
-               {
-                       // pure Y motion
-                       CS(player).movement_x = 0;
-                       if(CS(player).movement.y > 0)
-                               CS(player).movement_y = wishspeed;
-                       else
-                               CS(player).movement_y = -wishspeed;
-               }
-               else
-               {
-                       // diagonal
-                       if(CS(player).movement.x > 0)
-                               CS(player).movement_x = M_SQRT1_2 * wishspeed;
-                       else
-                               CS(player).movement_x = -M_SQRT1_2 * wishspeed;
-                       if(CS(player).movement.y > 0)
-                               CS(player).movement_y = M_SQRT1_2 * wishspeed;
-                       else
-                               CS(player).movement_y = -M_SQRT1_2 * wishspeed;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, reset_map_global)
-{
-       float s;
-
-       Score_NicePrint(NULL);
-
-       race_ClearRecords();
-       PlayerScore_Sort(race_place, 0, 1, 0);
-
-       FOREACH_CLIENT(true, {
-               if(it.race_place)
-               {
-                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
-                       if(!s)
-                               it.race_place = 0;
-               }
-               cts_EventLog(ftos(it.race_place), it);
-       });
-
-       if(g_race_qualifying == 2)
-       {
-               g_race_qualifying = 0;
-               independent_players = 0;
-               cvar_set("fraglimit", ftos(race_fraglimit));
-               cvar_set("leadlimit", ftos(race_leadlimit));
-               cvar_set("timelimit", ftos(race_timelimit));
-               cts_ScoreRules();
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, ClientConnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       race_PreparePlayer(player);
-       player.race_checkpoint = -1;
-
-       if(IS_REAL_CLIENT(player))
-       {
-               string rr = CTS_RECORD;
-
-               msg_entity = player;
-               race_send_recordtime(MSG_ONE);
-               race_send_speedaward(MSG_ONE);
-
-               speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
-               speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
-               race_send_speedaward_alltimebest(MSG_ONE);
-
-               float i;
-               for (i = 1; i <= RANKINGS_CNT; ++i)
-               {
-                       race_SendRankings(i, 0, 0, MSG_ONE);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, AbortSpeedrun)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(autocvar_g_allow_checkpoints)
-               race_PreparePlayer(player); // nice try
-}
-
-MUTATOR_HOOKFUNCTION(cts, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
-               player.frags = FRAGS_LMS_LOSER;
-       else
-               player.frags = FRAGS_SPECTATOR;
-
-       race_PreparePlayer(player);
-       player.race_checkpoint = -1;
-}
-
-MUTATOR_HOOKFUNCTION(cts, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-       entity spawn_spot = M_ARGV(1, entity);
-
-       if(spawn_spot.target == "")
-               // Emergency: this wasn't a real spawnpoint. Can this ever happen?
-               race_PreparePlayer(player);
-
-       // if we need to respawn, do it right
-       player.race_respawn_checkpoint = player.race_checkpoint;
-       player.race_respawn_spotref = spawn_spot;
-
-       player.race_place = 0;
-}
-
-MUTATOR_HOOKFUNCTION(cts, PutClientInServer)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(IS_PLAYER(player))
-       if(!game_stopped)
-       {
-               if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
-                       race_PreparePlayer(player);
-               else // respawn
-                       race_RetractPlayer(player);
-
-               race_AbandonRaceCheck(player);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       frag_target.respawn_flags |= RESPAWN_FORCE;
-       race_AbandonRaceCheck(frag_target);
-}
-
-MUTATOR_HOOKFUNCTION(cts, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       bot.havocbot_role = havocbot_role_cts;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(cts, GetPressedKeys)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
-       {
-               if (!player.stored_netname)
-                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
-               if(player.stored_netname != player.netname)
-               {
-                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
-                       strunzone(player.stored_netname);
-                       player.stored_netname = strzone(player.netname);
-               }
-       }
-
-       if (!IS_OBSERVER(player))
-       {
-               if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
-               {
-                       speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
-                       speedaward_holder = player.netname;
-                       speedaward_uid = player.crypto_idfp;
-                       speedaward_lastupdate = time;
-               }
-               if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
-               {
-                       string rr = CTS_RECORD;
-                       race_send_speedaward(MSG_ALL);
-                       speedaward_lastsent = speedaward_speed;
-                       if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
-                       {
-                               speedaward_alltimebest = speedaward_speed;
-                               speedaward_alltimebest_holder = speedaward_holder;
-                               speedaward_alltimebest_uid = speedaward_uid;
-                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
-                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
-                               race_send_speedaward_alltimebest(MSG_ALL);
-                       }
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, ForbidThrowCurrentWeapon)
-{
-       // no weapon dropping in CTS
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(cts, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       if (Item_IsLoot(item))
-       {
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, Damage_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);
-
-       if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL.m_id)
-       if(!autocvar_g_cts_selfdamage)
-       {
-               frag_damage = 0;
-               M_ARGV(4, float) = frag_damage;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, ForbidPlayerScore_Clear)
-{
-       return true; // in CTS, you don't lose score by observing
-}
-
-MUTATOR_HOOKFUNCTION(cts, GetRecords)
-{
-       int record_page = M_ARGV(0, int);
-       string ret_string = M_ARGV(1, string);
-
-       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
-       {
-               if(MapInfo_Get_ByID(i))
-               {
-                       float r = race_readTime(MapInfo_Map_bspname, 1);
-
-                       if(!r)
-                               continue;
-
-                       string h = race_readName(MapInfo_Map_bspname, 1);
-                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
-               }
-       }
-
-       M_ARGV(1, string) = ret_string;
-}
-
-void ClientKill_Now(entity this);
-MUTATOR_HOOKFUNCTION(cts, ClientKill)
-{
-    entity player = M_ARGV(0, entity);
-
-       M_ARGV(1, float) = 0; // kill delay
-
-       if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
-       {
-               delete(player.killindicator);
-               player.killindicator = NULL;
-
-               ClientKill_Now(player); // allow instant kill in this case
-               return;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(autocvar_g_cts_finish_kill_delay)
-               CTS_ClientKill(player);
-}
-
-MUTATOR_HOOKFUNCTION(cts, HideTeamNagger)
-{
-       return true; // doesn't work so well (but isn't cts a teamless mode?)
-}
-
-MUTATOR_HOOKFUNCTION(cts, FixClientCvars)
-{
-       entity player = M_ARGV(0, entity);
-
-       stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
-}
-
-MUTATOR_HOOKFUNCTION(cts, WantWeapon)
-{
-       M_ARGV(1, float) = (M_ARGV(0, entity) == WEP_SHOTGUN); // want weapon = weapon info
-       M_ARGV(3, bool) = true; // want mutator blocked
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(cts, ForbidDropCurrentWeapon)
-{
-       return true;
-}
-
-void cts_Initialize()
-{
-       cts_ScoreRules();
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_cts.qh b/qcsrc/server/mutators/mutator/gamemode_cts.qh
deleted file mode 100644 (file)
index c90919e..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-#include <server/race.qh>
-
-void cts_Initialize();
-
-REGISTER_MUTATOR(cts, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-               g_race_qualifying = true;
-               independent_players = 1;
-        GameRules_limit_score(0);
-        GameRules_limit_lead(0);
-
-               cts_Initialize();
-       }
-       return 0;
-}
-
-// scores
-const float ST_CTS_LAPS = 1;
diff --git a/qcsrc/server/mutators/mutator/gamemode_deathmatch.qc b/qcsrc/server/mutators/mutator/gamemode_deathmatch.qc
deleted file mode 100644 (file)
index 9590027..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "gamemode_deathmatch.qh"
-
-MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
-{
-       // announce remaining frags
-       return true;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_deathmatch.qh b/qcsrc/server/mutators/mutator/gamemode_deathmatch.qh
deleted file mode 100644 (file)
index f45b080..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-REGISTER_MUTATOR(dm, false)
-{
-    MUTATOR_STATIC();
-       return 0;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_domination.qc b/qcsrc/server/mutators/mutator/gamemode_domination.qc
deleted file mode 100644 (file)
index 38ef58b..0000000
+++ /dev/null
@@ -1,670 +0,0 @@
-#include "gamemode_domination.qh"
-
-#include <server/teamplay.qh>
-
-bool g_domination;
-
-int autocvar_g_domination_default_teams;
-bool autocvar_g_domination_disable_frags;
-int autocvar_g_domination_point_amt;
-bool autocvar_g_domination_point_fullbright;
-float autocvar_g_domination_round_timelimit;
-float autocvar_g_domination_warmup;
-float autocvar_g_domination_point_rate;
-int autocvar_g_domination_teams_override;
-
-void dom_EventLog(string mode, float team_before, entity actor) // use an alias for easy changing and quick editing later
-{
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":dom:", mode, ":", ftos(team_before), ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
-}
-
-void set_dom_state(entity e)
-{
-       STAT(DOM_TOTAL_PPS, e) = total_pps;
-       STAT(DOM_PPS_RED, e) = pps_red;
-       STAT(DOM_PPS_BLUE, e) = pps_blue;
-       if(domination_teams >= 3)
-               STAT(DOM_PPS_YELLOW, e) = pps_yellow;
-       if(domination_teams >= 4)
-               STAT(DOM_PPS_PINK, e) = pps_pink;
-}
-
-void dompoint_captured(entity this)
-{
-       float old_delay, old_team, real_team;
-
-       // now that the delay has expired, switch to the latest team to lay claim to this point
-       entity head = this.owner;
-
-       real_team = this.cnt;
-       this.cnt = -1;
-
-       dom_EventLog("taken", this.team, this.dmg_inflictor);
-       this.dmg_inflictor = NULL;
-
-       this.goalentity = head;
-       this.model = head.mdl;
-       this.modelindex = head.dmg;
-       this.skin = head.skin;
-
-       float points, wait_time;
-       if (autocvar_g_domination_point_amt)
-               points = autocvar_g_domination_point_amt;
-       else
-               points = this.frags;
-       if (autocvar_g_domination_point_rate)
-               wait_time = autocvar_g_domination_point_rate;
-       else
-               wait_time = this.wait;
-
-       if(domination_roundbased)
-               bprint(sprintf("^3%s^3%s\n", head.netname, this.message));
-       else
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_DOMINATION_CAPTURE_TIME, head.netname, this.message, points, wait_time);
-
-       if(this.enemy.playerid == this.enemy_playerid)
-               GameRules_scoring_add(this.enemy, DOM_TAKES, 1);
-       else
-               this.enemy = NULL;
-
-       if (head.noise != "")
-               if(this.enemy)
-                       _sound(this.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
-               else
-                       _sound(this, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
-       if (head.noise1 != "")
-               play2all(head.noise1);
-
-       this.delay = time + wait_time;
-
-       // do trigger work
-       old_delay = this.delay;
-       old_team = this.team;
-       this.team = real_team;
-       this.delay = 0;
-       SUB_UseTargets (this, this, NULL);
-       this.delay = old_delay;
-       this.team = old_team;
-
-       entity msg = WP_DomNeut;
-       switch(real_team)
-       {
-               case NUM_TEAM_1: msg = WP_DomRed; break;
-               case NUM_TEAM_2: msg = WP_DomBlue; break;
-               case NUM_TEAM_3: msg = WP_DomYellow; break;
-               case NUM_TEAM_4: msg = WP_DomPink; break;
-       }
-
-       WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
-
-       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
-       IL_EACH(g_dompoints, true,
-       {
-               if (autocvar_g_domination_point_amt)
-                       points = autocvar_g_domination_point_amt;
-               else
-                       points = it.frags;
-               if (autocvar_g_domination_point_rate)
-                       wait_time = autocvar_g_domination_point_rate;
-               else
-                       wait_time = it.wait;
-               switch(it.goalentity.team)
-               {
-                       case NUM_TEAM_1: pps_red += points/wait_time; break;
-                       case NUM_TEAM_2: pps_blue += points/wait_time; break;
-                       case NUM_TEAM_3: pps_yellow += points/wait_time; break;
-                       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);
-
-       this.captime = time;
-
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), { set_dom_state(it); });
-}
-
-void AnimateDomPoint(entity this)
-{
-       if(this.pain_finished > time)
-               return;
-       this.pain_finished = time + this.t_width;
-       if(this.nextthink > this.pain_finished)
-               this.nextthink = this.pain_finished;
-
-       this.frame = this.frame + 1;
-       if(this.frame > this.t_length)
-               this.frame = 0;
-}
-
-void dompointthink(entity this)
-{
-       float fragamt;
-
-       this.nextthink = time + 0.1;
-
-       //this.frame = this.frame + 1;
-       //if(this.frame > 119)
-       //      this.frame = 0;
-       AnimateDomPoint(this);
-
-       // give points
-
-       if (game_stopped || this.delay > time || time < game_starttime) // game has ended, don't keep giving points
-               return;
-
-       if(autocvar_g_domination_point_rate)
-               this.delay = time + autocvar_g_domination_point_rate;
-       else
-               this.delay = time + this.wait;
-
-       // give credit to the team
-       // NOTE: this defaults to 0
-       if (!domination_roundbased)
-       if (this.goalentity.netname != "")
-       {
-               if(autocvar_g_domination_point_amt)
-                       fragamt = autocvar_g_domination_point_amt;
-               else
-                       fragamt = this.frags;
-               TeamScore_AddToTeam(this.goalentity.team, ST_SCORE, fragamt);
-               TeamScore_AddToTeam(this.goalentity.team, ST_DOM_TICKS, fragamt);
-
-               // give credit to the individual player, if he is still there
-               if (this.enemy.playerid == this.enemy_playerid)
-               {
-                       GameRules_scoring_add(this.enemy, SCORE, fragamt);
-                       GameRules_scoring_add(this.enemy, DOM_TICKS, fragamt);
-               }
-               else
-                       this.enemy = NULL;
-       }
-}
-
-void dompointtouch(entity this, entity toucher)
-{
-       if (!IS_PLAYER(toucher))
-               return;
-       if (toucher.health < 1)
-               return;
-
-       if(round_handler_IsActive() && !round_handler_IsRoundStarted())
-               return;
-
-       if(time < this.captime + 0.3)
-               return;
-
-       // only valid teams can claim it
-       entity head = find(NULL, classname, "dom_team");
-       while (head && head.team != toucher.team)
-               head = find(head, classname, "dom_team");
-       if (!head || head.netname == "" || head == this.goalentity)
-               return;
-
-       // delay capture
-
-       this.team = this.goalentity.team; // this stores the PREVIOUS team!
-
-       this.cnt = toucher.team;
-       this.owner = head; // team to switch to after the delay
-       this.dmg_inflictor = toucher;
-
-       // this.state = 1;
-       // this.delay = time + cvar("g_domination_point_capturetime");
-       //this.nextthink = time + cvar("g_domination_point_capturetime");
-       //this.think = dompoint_captured;
-
-       // go to neutral team in the mean time
-       head = find(NULL, classname, "dom_team");
-       while (head && head.netname != "")
-               head = find(head, classname, "dom_team");
-       if(head == NULL)
-               return;
-
-       WaypointSprite_UpdateSprites(this.sprite, WP_DomNeut, WP_Null, WP_Null);
-       WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, '0 1 1');
-       WaypointSprite_Ping(this.sprite);
-
-       this.goalentity = head;
-       this.model = head.mdl;
-       this.modelindex = head.dmg;
-       this.skin = head.skin;
-
-       this.enemy = toucher; // individual player scoring
-       this.enemy_playerid = toucher.playerid;
-       dompoint_captured(this);
-}
-
-void dom_controlpoint_setup(entity this)
-{
-       entity head;
-       // find the spawnfunc_dom_team representing unclaimed points
-       head = find(NULL, classname, "dom_team");
-       while(head && head.netname != "")
-               head = find(head, classname, "dom_team");
-       if (!head)
-               objerror(this, "no spawnfunc_dom_team with netname \"\" found\n");
-
-       // copy important properties from spawnfunc_dom_team entity
-       this.goalentity = head;
-       _setmodel(this, head.mdl); // precision already set
-       this.skin = head.skin;
-
-       this.cnt = -1;
-
-       if(this.message == "")
-               this.message = " has captured a control point";
-
-       if(this.frags <= 0)
-               this.frags = 1;
-       if(this.wait <= 0)
-               this.wait = 5;
-
-       float points, waittime;
-       if (autocvar_g_domination_point_amt)
-               points = autocvar_g_domination_point_amt;
-       else
-               points = this.frags;
-       if (autocvar_g_domination_point_rate)
-               waittime = autocvar_g_domination_point_rate;
-       else
-               waittime = this.wait;
-
-       total_pps += points/waittime;
-
-       if(!this.t_width)
-               this.t_width = 0.02; // frame animation rate
-       if(!this.t_length)
-               this.t_length = 239; // maximum frame
-
-       setthink(this, dompointthink);
-       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');
-       droptofloor(this);
-
-       waypoint_spawnforitem(this);
-       WaypointSprite_SpawnFixed(WP_DomNeut, this.origin + '0 0 32', this, sprite, RADARICON_DOMPOINT);
-}
-
-float total_controlpoints;
-void Domination_count_controlpoints()
-{
-       total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
-       IL_EACH(g_dompoints, true,
-       {
-               ++total_controlpoints;
-               redowned += (it.goalentity.team == NUM_TEAM_1);
-               blueowned += (it.goalentity.team == NUM_TEAM_2);
-               yellowowned += (it.goalentity.team == NUM_TEAM_3);
-               pinkowned += (it.goalentity.team == NUM_TEAM_4);
-       });
-}
-
-float Domination_GetWinnerTeam()
-{
-       float winner_team = 0;
-       if(redowned == total_controlpoints)
-               winner_team = NUM_TEAM_1;
-       if(blueowned == total_controlpoints)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
-       }
-       if(yellowowned == total_controlpoints)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
-       }
-       if(pinkowned == total_controlpoints)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
-               return winner_team;
-       return -1; // no control points left?
-}
-
-#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
-float Domination_CheckWinner()
-{
-       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
-
-               game_stopped = true;
-               round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
-               return 1;
-       }
-
-       Domination_count_controlpoints();
-
-       float winner_team = Domination_GetWinnerTeam();
-
-       if(winner_team == -1)
-               return 0;
-
-       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_DOM_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);
-       }
-
-       game_stopped = true;
-       round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
-
-       return 1;
-}
-
-float Domination_CheckPlayers()
-{
-       return 1;
-}
-
-void Domination_RoundStart()
-{
-       FOREACH_CLIENT(IS_PLAYER(it), { it.player_blocked = false; });
-}
-
-//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))
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
-               havocbot_goalrating_items(this, 8000, this.origin, 8000);
-               //havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
-               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
-{
-       // fallback?
-       M_ARGV(0, float) = domination_teams;
-       string ret_string = "dom_team";
-
-       entity head = find(NULL, classname, ret_string);
-       while(head)
-       {
-               if(head.netname != "")
-               {
-                       switch(head.team)
-                       {
-                               case NUM_TEAM_1: c1 = 0; break;
-                               case NUM_TEAM_2: c2 = 0; break;
-                               case NUM_TEAM_3: c3 = 0; break;
-                               case NUM_TEAM_4: c4 = 0; break;
-                       }
-               }
-
-               head = find(head, classname, ret_string);
-       }
-
-       M_ARGV(1, string) = string_null;
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(dom, reset_map_players)
-{
-       total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               PutClientInServer(it);
-               if(domination_roundbased)
-                       it.player_blocked = 1;
-               if(IS_REAL_CLIENT(it))
-                       set_dom_state(it);
-       });
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(dom, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(domination_roundbased)
-       if(!round_handler_IsRoundStarted())
-               player.player_blocked = 1;
-       else
-               player.player_blocked = 0;
-}
-
-MUTATOR_HOOKFUNCTION(dom, ClientConnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       set_dom_state(player);
-}
-
-MUTATOR_HOOKFUNCTION(dom, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       bot.havocbot_role = havocbot_role_dom;
-       return true;
-}
-
-/*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
-Control point for Domination gameplay.
-*/
-spawnfunc(dom_controlpoint)
-{
-       if(!g_domination)
-       {
-               delete(this);
-               return;
-       }
-       setthink(this, dom_controlpoint_setup);
-       this.nextthink = time + 0.1;
-       this.reset = dom_controlpoint_setup;
-
-       if(!this.scale)
-               this.scale = 0.6;
-
-       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)
-Team declaration for Domination gameplay, this allows you to decide what team
-names and control point models are used in your map.
-
-Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
-can have netname set!  The nameless team owns all control points at start.
-
-Keys:
-"netname"
- Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
-"cnt"
- Scoreboard color of the team (for example 4 is red and 13 is blue)
-"model"
- Model to use for control points owned by this team (for example
- "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
- keycard)
-"skin"
- Skin of the model to use (for team skins on a single model)
-"noise"
- Sound to play when this team captures a point.
- (this is a localized sound, like a small alarm or other effect)
-"noise1"
- Narrator speech to play when this team captures a point.
- (this is a global sound, like "Red team has captured a control point")
-*/
-
-spawnfunc(dom_team)
-{
-       if(!g_domination || autocvar_g_domination_teams_override >= 2)
-       {
-               delete(this);
-               return;
-       }
-       precache_model(this.model);
-       if (this.noise != "")
-               precache_sound(this.noise);
-       if (this.noise1 != "")
-               precache_sound(this.noise1);
-       this.classname = "dom_team";
-       _setmodel(this, this.model); // precision not needed
-       this.mdl = this.model;
-       this.dmg = this.modelindex;
-       this.model = "";
-       this.modelindex = 0;
-       // this would have to be changed if used in quakeworld
-       if(this.cnt)
-               this.team = this.cnt + 1; // WHY are these different anyway?
-}
-
-// scoreboard setup
-void ScoreRules_dom(int teams)
-{
-       if(domination_roundbased)
-       {
-           GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
-            field_team(ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
-            field(SP_DOM_TAKES, "takes", 0);
-           });
-       }
-       else
-       {
-               float sp_domticks, sp_score;
-               sp_score = sp_domticks = 0;
-               if(autocvar_g_domination_disable_frags)
-                       sp_domticks = SFL_SORT_PRIO_PRIMARY;
-               else
-                       sp_score = SFL_SORT_PRIO_PRIMARY;
-               GameRules_scoring(teams, sp_score, sp_score, {
-            field_team(ST_DOM_TICKS, "ticks", sp_domticks);
-            field(SP_DOM_TICKS, "ticks", sp_domticks);
-            field(SP_DOM_TAKES, "takes", 0);
-               });
-       }
-}
-
-// code from here on is just to support maps that don't have control point and team entities
-void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
-{
-    TC(Sound, capsound);
-    entity e = new_pure(dom_team);
-       e.netname = strzone(teamname);
-       e.cnt = teamcolor;
-       e.model = pointmodel;
-       e.skin = pointskin;
-       e.noise = strzone(Sound_fixpath(capsound));
-       e.noise1 = strzone(capnarration);
-       e.message = strzone(capmessage);
-
-       // this code is identical to spawnfunc_dom_team
-       _setmodel(e, e.model); // precision not needed
-       e.mdl = e.model;
-       e.dmg = e.modelindex;
-       e.model = "";
-       e.modelindex = 0;
-       // this would have to be changed if used in quakeworld
-       e.team = e.cnt + 1;
-
-       //eprint(e);
-}
-
-void dom_spawnpoint(vector org)
-{
-       entity e = spawn();
-       e.classname = "dom_controlpoint";
-       setthink(e, spawnfunc_dom_controlpoint);
-       e.nextthink = time;
-       setorigin(e, org);
-       spawnfunc_dom_controlpoint(e);
-}
-
-// spawn some default teams if the map is not set up for domination
-void dom_spawnteams(int teams)
-{
-    TC(int, teams);
-       dom_spawnteam(Team_ColoredFullName(NUM_TEAM_1), NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, SND_DOM_CLAIM, "", "Red team has captured a control point");
-       dom_spawnteam(Team_ColoredFullName(NUM_TEAM_2), NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, SND_DOM_CLAIM, "", "Blue team has captured a control point");
-       if(teams >= 3)
-               dom_spawnteam(Team_ColoredFullName(NUM_TEAM_3), NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, SND_DOM_CLAIM, "", "Yellow team has captured a control point");
-       if(teams >= 4)
-               dom_spawnteam(Team_ColoredFullName(NUM_TEAM_4), NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, SND_DOM_CLAIM, "", "Pink team has captured a control point");
-       dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, SND_Null, "", "");
-}
-
-void dom_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
-{
-       // if no teams are found, spawn defaults
-       if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
-       {
-               LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
-               domination_teams = autocvar_g_domination_teams_override;
-               if (domination_teams < 2)
-                       domination_teams = autocvar_g_domination_default_teams;
-               domination_teams = bound(2, domination_teams, 4);
-               dom_spawnteams(domination_teams);
-       }
-
-       CheckAllowedTeams(NULL);
-       //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
-
-       int teams = 0;
-       if(c1 >= 0) teams |= BIT(0);
-       if(c2 >= 0) teams |= BIT(1);
-       if(c3 >= 0) teams |= BIT(2);
-       if(c4 >= 0) teams |= BIT(3);
-       domination_teams = teams;
-
-       domination_roundbased = autocvar_g_domination_roundbased;
-
-       ScoreRules_dom(domination_teams);
-
-       if(domination_roundbased)
-       {
-               round_handler_Spawn(Domination_CheckPlayers, Domination_CheckWinner, Domination_RoundStart);
-               round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
-       }
-}
-
-void dom_Initialize()
-{
-       g_domination = true;
-       InitializeEntity(NULL, dom_DelayedInit, INITPRIO_GAMETYPE);
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_domination.qh b/qcsrc/server/mutators/mutator/gamemode_domination.qh
deleted file mode 100644 (file)
index 95311c9..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-
-#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_STATIC();
-       MUTATOR_ONADD
-       {
-               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;
-
-               GameRules_teams(true);
-        GameRules_limit_score(fraglimit_override);
-        GameRules_limit_lead(autocvar_g_domination_point_leadlimit);
-
-               dom_Initialize();
-       }
-       return 0;
-}
-
-// score rule declarations
-const float ST_DOM_TICKS = 1;
-const float ST_DOM_CAPS = 1;
-
-// pps: points per second
-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(); }
diff --git a/qcsrc/server/mutators/mutator/gamemode_freezetag.qc b/qcsrc/server/mutators/mutator/gamemode_freezetag.qc
deleted file mode 100644 (file)
index 36546c4..0000000
+++ /dev/null
@@ -1,585 +0,0 @@
-#include "gamemode_freezetag.qh"
-
-float autocvar_g_freezetag_frozen_maxtime;
-float autocvar_g_freezetag_revive_clearspeed;
-float autocvar_g_freezetag_round_timelimit;
-//int autocvar_g_freezetag_teams;
-int autocvar_g_freezetag_teams_override;
-float autocvar_g_freezetag_warmup;
-
-void freezetag_count_alive_players()
-{
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               switch(it.team)
-               {
-                       case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
-               }
-       });
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               STAT(REDALIVE, it) = redalive;
-               STAT(BLUEALIVE, it) = bluealive;
-               STAT(YELLOWALIVE, it) = yellowalive;
-               STAT(PINKALIVE, it) = pinkalive;
-       });
-
-       eliminatedPlayers.SendFlags |= 1;
-}
-#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
-
-float freezetag_CheckTeams()
-{
-       static float prev_missing_teams_mask;
-       if(FREEZETAG_ALIVE_TEAMS_OK())
-       {
-               if(prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               return 1;
-       }
-       if(total_players == 0)
-       {
-               if(prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               return 0;
-       }
-       int missing_teams_mask = 0;
-       if(freezetag_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(freezetag_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(freezetag_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(freezetag_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
-       if(prev_missing_teams_mask != missing_teams_mask)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
-               prev_missing_teams_mask = missing_teams_mask;
-       }
-       return 0;
-}
-
-float freezetag_getWinnerTeam()
-{
-       float winner_team = 0;
-       if(redalive >= 1)
-               winner_team = NUM_TEAM_1;
-       if(bluealive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
-       }
-       if(yellowalive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
-       }
-       if(pinkalive >= 1)
-       {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
-               return winner_team;
-       return -1; // no player left
-}
-
-void nades_Clear(entity);
-void nades_GiveBonus(entity player, float score);
-
-float freezetag_CheckWinner()
-{
-       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       it.freezetag_frozen_timeout = 0;
-                       nades_Clear(it);
-               });
-               game_stopped = true;
-               round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-               return 1;
-       }
-
-       if(FREEZETAG_ALIVE_TEAMS() > 1)
-               return 0;
-
-       int winner_team = freezetag_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_SCORE, +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);
-       }
-
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               it.freezetag_frozen_timeout = 0;
-               nades_Clear(it);
-       });
-
-       game_stopped = true;
-       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-       return 1;
-}
-
-entity freezetag_LastPlayerForTeam(entity this)
-{
-       entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(it.health >= 1)
-               if(!STAT(FROZEN, it))
-               if(SAME_TEAM(it, this))
-               if(!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
-       });
-       return last_pl;
-}
-
-void freezetag_LastPlayerForTeam_Notify(entity this)
-{
-       if(round_handler_IsActive())
-       if(round_handler_IsRoundStarted())
-       {
-               entity pl = freezetag_LastPlayerForTeam(this);
-               if(pl)
-                       Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
-       }
-}
-
-void freezetag_Add_Score(entity targ, entity attacker)
-{
-       if(attacker == targ)
-       {
-               // you froze your own dumb targ
-               // counted as "suicide" already
-               GameRules_scoring_add(targ, SCORE, -1);
-       }
-       else if(IS_PLAYER(attacker))
-       {
-               // got frozen by an enemy
-               // counted as "kill" and "death" already
-               GameRules_scoring_add(targ, SCORE, -1);
-               GameRules_scoring_add(attacker, SCORE, +1);
-       }
-       // else nothing - got frozen by the game type rules themselves
-}
-
-void freezetag_Freeze(entity targ, entity attacker)
-{
-       if(STAT(FROZEN, targ))
-               return;
-
-       if(autocvar_g_freezetag_frozen_maxtime > 0)
-               targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
-
-       Freeze(targ, 0, 1, true);
-
-       freezetag_count_alive_players();
-
-       freezetag_Add_Score(targ, attacker);
-}
-
-void freezetag_Unfreeze(entity this)
-{
-       this.freezetag_frozen_time = 0;
-       this.freezetag_frozen_timeout = 0;
-
-       Unfreeze(this);
-}
-
-float freezetag_isEliminated(entity e)
-{
-       if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
-               return true;
-       return false;
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-void(entity this) havocbot_role_ft_freeing;
-void(entity this) havocbot_role_ft_offense;
-
-void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
-{
-       float t;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
-               if (STAT(FROZEN, it) == 1)
-               {
-                       if(vdist(it.origin - org, >, sradius))
-                               continue;
-                       navigation_routerating(this, it, ratingscale, 2000);
-               }
-               else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
-               {
-                       // If teamate is not frozen still seek them out as fight better
-                       // in a group.
-                       t = 0.2 * 150 / (this.health + this.armorvalue);
-                       navigation_routerating(this, it, t * ratingscale, 2000);
-               }
-       });
-}
-
-void havocbot_role_ft_offense(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + random() * 10 + 20;
-
-       // Count how many players on team are unfrozen.
-       int unfrozen = 0;
-       FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
-
-       // If only one left on team or if role has timed out then start trying to free players.
-       if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
-       {
-               LOG_TRACE("changing role to freeing");
-               this.havocbot_role = havocbot_role_ft_freeing;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
-               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_ft_freeing(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + random() * 10 + 20;
-
-       if (time > this.havocbot_role_timeout)
-       {
-               LOG_TRACE("changing role to offense");
-               this.havocbot_role = havocbot_role_ft_offense;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 8000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
-               havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
-               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-
-// ==============
-// Hook Functions
-// ==============
-
-void ft_RemovePlayer(entity this)
-{
-       this.health = 0; // neccessary to update correctly alive stats
-       if(!STAT(FROZEN, this))
-               freezetag_LastPlayerForTeam_Notify(this);
-       freezetag_Unfreeze(this);
-       freezetag_count_alive_players();
-}
-
-MUTATOR_HOOKFUNCTION(ft, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       ft_RemovePlayer(player);
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       ft_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_deathtype = M_ARGV(3, float);
-
-       if(round_handler_IsActive())
-       if(round_handler_CountdownRunning())
-       {
-               if(STAT(FROZEN, frag_target))
-                       freezetag_Unfreeze(frag_target);
-               freezetag_count_alive_players();
-               return true; // let the player die so that he can respawn whenever he wants
-       }
-
-       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
-       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
-       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
-               || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
-       {
-               // let the player die, he will be automatically frozen when he respawns
-               if(STAT(FROZEN, frag_target) != 1)
-               {
-                       freezetag_Add_Score(frag_target, frag_attacker);
-                       freezetag_count_alive_players();
-                       freezetag_LastPlayerForTeam_Notify(frag_target);
-               }
-               else
-                       freezetag_Unfreeze(frag_target); // remove ice
-               frag_target.health = 0; // Unfreeze resets health
-               frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
-               return true;
-       }
-
-       if(STAT(FROZEN, frag_target))
-               return true;
-
-       freezetag_Freeze(frag_target, frag_attacker);
-       freezetag_LastPlayerForTeam_Notify(frag_target);
-
-       if(frag_attacker == frag_target || frag_attacker == NULL)
-       {
-               if(IS_PLAYER(frag_target))
-                       Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
-       }
-       else
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
-               return true; // do nothing, round is starting right now
-
-       if(player.freezetag_frozen_timeout == -2) // player was dead
-       {
-               freezetag_Freeze(player, NULL);
-               return true;
-       }
-
-       freezetag_count_alive_players();
-
-       if(round_handler_IsActive())
-       if(round_handler_IsRoundStarted())
-       {
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
-               freezetag_Freeze(player, NULL);
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, reset_map_players)
-{
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               CS(it).killcount = 0;
-               it.freezetag_frozen_timeout = -1;
-               PutClientInServer(it);
-               it.freezetag_frozen_timeout = 0;
-       });
-       freezetag_count_alive_players();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
-{
-       M_ARGV(2, float) = 0; // no frags counted in Freeze Tag
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
-{
-       if(game_stopped)
-               return true;
-
-       if(round_handler_IsActive())
-       if(!round_handler_IsRoundStarted())
-               return true;
-
-       int n;
-       entity o = NULL;
-       entity player = M_ARGV(0, entity);
-       //if(STAT(FROZEN, player))
-       //if(player.freezetag_frozen_timeout > 0 && time < player.freezetag_frozen_timeout)
-               //player.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (player.freezetag_frozen_timeout - time) / (player.freezetag_frozen_timeout - player.freezetag_frozen_time);
-
-       if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
-               n = -1;
-       else
-       {
-               vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
-               n = 0;
-               FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
-                       if(STAT(FROZEN, it) == 0)
-                       if(!IS_DEAD(it))
-                       if(SAME_TEAM(it, player))
-                       if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
-                       {
-                               if(!o)
-                                       o = it;
-                               if(STAT(FROZEN, player) == 1)
-                                       it.reviving = true;
-                               ++n;
-                       }
-               });
-
-       }
-
-       if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
-       {
-               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
-
-               if(STAT(REVIVE_PROGRESS, player) >= 1)
-               {
-                       freezetag_Unfreeze(player);
-                       freezetag_count_alive_players();
-
-                       if(n == -1)
-                       {
-                               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
-                               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
-                               return true;
-                       }
-
-                       // EVERY team mate nearby gets a point (even if multiple!)
-                       FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
-                               GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
-                               GameRules_scoring_add(it, SCORE, +1);
-                               nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
-                       });
-
-                       Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
-                       Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, o.netname);
-               }
-
-               FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
-                       STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
-                       it.reviving = false;
-               });
-       }
-       else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
-       {
-               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
-       }
-       else if(!n && !STAT(FROZEN, player))
-       {
-               STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, SetStartItems)
-{
-       start_items &= ~IT_UNLIMITED_AMMO;
-       //start_health       = warmup_start_health       = cvar("g_lms_start_health");
-       //start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
-       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
-       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
-       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
-       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
-}
-
-MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       if (!IS_DEAD(bot))
-       {
-               if (random() < 0.5)
-                       bot.havocbot_role = havocbot_role_ft_freeing;
-               else
-                       bot.havocbot_role = havocbot_role_ft_offense;
-       }
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(0, float) = freezetag_teams;
-}
-
-MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
-{
-       // most weapons arena
-       if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
-               M_ARGV(0, string) = "most";
-}
-
-MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
-{
-       entity frag_attacker = M_ARGV(0, entity);
-       entity frag_target = M_ARGV(1, entity);
-       //float frag_deathtype = M_ARGV(2, float);
-       int kill_count_to_attacker = M_ARGV(3, int);
-       int kill_count_to_target = M_ARGV(4, int);
-
-       if(STAT(FROZEN, frag_target))
-               return; // target was already frozen, so this is just pushing them off the cliff
-
-       Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
-       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
-
-       return true;
-}
-
-void freezetag_Initialize()
-{
-       freezetag_teams = autocvar_g_freezetag_teams_override;
-       if(freezetag_teams < 2)
-               freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
-
-       freezetag_teams = BITS(bound(2, freezetag_teams, 4));
-       GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
-       });
-
-       round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
-       round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-
-       EliminatedPlayers_Init(freezetag_isEliminated);
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_freezetag.qh b/qcsrc/server/mutators/mutator/gamemode_freezetag.qh
deleted file mode 100644 (file)
index a258d82..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-#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_STATIC();
-       MUTATOR_ONADD
-       {
-               GameRules_teams(true);
-        GameRules_spawning_teams(autocvar_g_freezetag_team_spawns);
-        GameRules_limit_score(autocvar_g_freezetag_point_limit);
-        GameRules_limit_lead(autocvar_g_freezetag_point_leadlimit);
-
-               freezetag_Initialize();
-       }
-       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;
diff --git a/qcsrc/server/mutators/mutator/gamemode_invasion.qc b/qcsrc/server/mutators/mutator/gamemode_invasion.qc
deleted file mode 100644 (file)
index 1b8b77a..0000000
+++ /dev/null
@@ -1,603 +0,0 @@
-#include "gamemode_invasion.qh"
-
-#include <common/monsters/sv_spawn.qh>
-#include <common/monsters/sv_monsters.qh>
-
-#include <server/teamplay.qh>
-
-IntrusiveList g_invasion_roundends;
-STATIC_INIT(g_invasion_roundends) { g_invasion_roundends = IL_NEW(); }
-
-IntrusiveList g_invasion_waves;
-STATIC_INIT(g_invasion_waves) { g_invasion_waves = IL_NEW(); }
-
-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;
-float autocvar_g_invasion_warmup;
-int autocvar_g_invasion_monster_count;
-bool autocvar_g_invasion_zombies_only;
-float autocvar_g_invasion_spawn_delay;
-
-bool victent_present;
-.bool inv_endreached;
-
-bool inv_warning_shown; // spammy
-
-.string spawnmob;
-
-void target_invasion_roundend_use(entity this, entity actor, entity trigger)
-{
-       if(!IS_PLAYER(actor)) { return; }
-
-       actor.inv_endreached = true;
-
-       int plnum = 0;
-       int realplnum = 0;
-       // let's not count bots
-       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-               ++realplnum;
-               if(it.inv_endreached)
-                       ++plnum;
-       });
-       if(plnum < ceil(realplnum * min(1, this.count))) // 70% of players
-               return;
-
-       this.winning = true;
-}
-
-spawnfunc(target_invasion_roundend)
-{
-       if(!g_invasion) { delete(this); return; }
-
-       victent_present = true; // a victory entity is present, we don't need to rely on monster count TODO: merge this with the intrusive list (can check empty)
-
-       if(!this.count) { this.count = 0.7; } // require at least 70% of the players to reach the end before triggering victory
-
-       this.use = target_invasion_roundend_use;
-
-       IL_PUSH(g_invasion_roundends, this);
-}
-
-spawnfunc(invasion_wave)
-{
-       if(!g_invasion) { delete(this); return; }
-
-       IL_PUSH(g_invasion_waves, this);
-}
-
-spawnfunc(invasion_spawnpoint)
-{
-       if(!g_invasion) { delete(this); return; }
-
-       this.classname = "invasion_spawnpoint";
-       IL_PUSH(g_invasion_spawns, this);
-}
-
-void ClearWinners();
-
-// Invasion stage mode winning condition: If the attackers triggered a round end (by fulfilling all objectives)
-// they win.
-int WinningCondition_Invasion()
-{
-       WinningConditionHelper(NULL); // set worldstatus
-
-       int status = WINNING_NO;
-
-       if(autocvar_g_invasion_type == INV_TYPE_STAGE)
-       {
-               SetWinners(inv_endreached, true);
-
-               int found = 0;
-               IL_EACH(g_invasion_roundends, true,
-               {
-                       ++found;
-                       if(it.winning)
-                       {
-                               bprint("Invasion: round completed.\n");
-                               // winners already set (TODO: teamplay support)
-
-                               status = WINNING_YES;
-                               break;
-                       }
-               });
-
-               if(!found)
-                       status = WINNING_YES; // just end it? TODO: should warn mapper!
-       }
-       else if(autocvar_g_invasion_type == INV_TYPE_HUNT)
-       {
-               ClearWinners();
-
-               int found = 0; // NOTE: this ends the round if no monsters are placed
-               IL_EACH(g_monsters, !(it.spawnflags & MONSTERFLAG_RESPAWNED),
-               {
-                       ++found;
-               });
-
-               if(found <= 0)
-               {
-                       FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
-                       {
-                               it.winning = true;
-                       });
-                       status = WINNING_YES;
-               }
-       }
-
-       return status;
-}
-
-Monster invasion_PickMonster(int supermonster_count)
-{
-       RandomSelection_Init();
-
-       FOREACH(Monsters, it != MON_Null,
-       {
-               if((it.spawnflags & MON_FLAG_HIDDEN) || (it.spawnflags & MONSTER_TYPE_PASSIVE) || (it.spawnflags & MONSTER_TYPE_FLY) || (it.spawnflags & MONSTER_TYPE_SWIM) ||
-                       (it.spawnflags & MONSTER_SIZE_QUAKE) || ((it.spawnflags & MON_FLAG_SUPERMONSTER) && supermonster_count >= 1))
-                       continue;
-               if(autocvar_g_invasion_zombies_only && !(it.spawnflags & MONSTER_TYPE_UNDEAD))
-                       continue;
-        RandomSelection_AddEnt(it, 1, 1);
-       });
-
-       return RandomSelection_chosen_ent;
-}
-
-entity invasion_PickSpawn()
-{
-       RandomSelection_Init();
-
-       IL_EACH(g_invasion_spawns, true,
-       {
-               RandomSelection_AddEnt(it, 1, ((time < it.spawnshieldtime) ? 0.2 : 1)); // give recently used spawnpoints a very low rating
-               it.spawnshieldtime = time + autocvar_g_invasion_spawnpoint_spawn_delay;
-       });
-
-       return RandomSelection_chosen_ent;
-}
-
-entity invasion_GetWaveEntity(int wavenum)
-{
-       IL_EACH(g_invasion_waves, it.cnt == wavenum,
-       {
-               return it; // found one
-       });
-
-       // if no specific one is found, find the last existing wave ent
-       entity best = NULL;
-       IL_EACH(g_invasion_waves, it.cnt <= wavenum,
-       {
-               if(!best || it.cnt > best.cnt)
-                       best = it;
-       });
-
-       return best;
-}
-
-void invasion_SpawnChosenMonster(Monster mon)
-{
-       entity monster;
-       entity spawn_point = invasion_PickSpawn();
-       entity wave_ent = invasion_GetWaveEntity(inv_roundcnt);
-
-       string tospawn = "";
-       if(wave_ent && wave_ent.spawnmob && wave_ent.spawnmob != "")
-       {
-               RandomSelection_Init();
-               FOREACH_WORD(wave_ent.spawnmob, true,
-               {
-                       RandomSelection_AddString(it, 1, 1);
-               });
-
-               tospawn = RandomSelection_chosen_string;
-       }
-
-       if(spawn_point == NULL)
-       {
-               if(!inv_warning_shown)
-               {
-                       inv_warning_shown = true;
-                       LOG_TRACE("Warning: couldn't find any invasion_spawnpoint spawnpoints, attempting to spawn monsters in random locations");
-               }
-               entity e = spawn();
-               setsize(e, mon.m_mins, mon.m_maxs);
-
-               if(MoveToRandomMapLocation(e, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
-                       monster = spawnmonster(e, tospawn, mon.monsterid, NULL, NULL, e.origin, false, false, 2);
-               else
-               {
-                       delete(e);
-                       return;
-               }
-       }
-       else // if spawnmob field falls through (unset), fallback to mon (relying on spawnmonster for that behaviour)
-               monster = spawnmonster(spawn(), ((spawn_point.spawnmob && spawn_point.spawnmob != "") ? spawn_point.spawnmob : tospawn), mon.monsterid, spawn_point, spawn_point, spawn_point.origin, false, false, 2);
-
-       if(!monster)
-               return;
-
-       monster.spawnshieldtime = time;
-
-       if(spawn_point)
-       {
-               if(spawn_point.target_range)
-                       monster.target_range = spawn_point.target_range;
-               monster.target2 = spawn_point.target2;
-       }
-
-       if(teamplay)
-       {
-               if(spawn_point && spawn_point.team && inv_monsters_perteam[spawn_point.team] > 0)
-                       monster.team = spawn_point.team;
-               else
-               {
-                       RandomSelection_Init();
-                       if(inv_monsters_perteam[NUM_TEAM_1] > 0) RandomSelection_AddFloat(NUM_TEAM_1, 1, 1);
-                       if(inv_monsters_perteam[NUM_TEAM_2] > 0) RandomSelection_AddFloat(NUM_TEAM_2, 1, 1);
-                       if(invasion_teams >= 3) if(inv_monsters_perteam[NUM_TEAM_3] > 0) { RandomSelection_AddFloat(NUM_TEAM_3, 1, 1); }
-                       if(invasion_teams >= 4) if(inv_monsters_perteam[NUM_TEAM_4] > 0) { RandomSelection_AddFloat(NUM_TEAM_4, 1, 1); }
-
-                       monster.team = RandomSelection_chosen_float;
-               }
-
-               monster_setupcolors(monster);
-
-               if(monster.sprite)
-               {
-                       WaypointSprite_UpdateTeamRadar(monster.sprite, RADARICON_DANGER, ((monster.team) ? Team_ColorRGB(monster.team) : '1 0 0'));
-
-                       monster.sprite.team = 0;
-                       monster.sprite.SendFlags |= 1;
-               }
-       }
-
-       if(monster.monster_attack)
-               IL_REMOVE(g_monster_targets, monster);
-       monster.monster_attack = false; // it's the player's job to kill all the monsters
-
-       if(inv_roundcnt >= inv_maxrounds)
-               monster.spawnflags |= MONSTERFLAG_MINIBOSS; // last round spawns minibosses
-}
-
-void invasion_SpawnMonsters(int supermonster_count)
-{
-       Monster chosen_monster = invasion_PickMonster(supermonster_count);
-
-       invasion_SpawnChosenMonster(chosen_monster);
-}
-
-bool Invasion_CheckWinner()
-{
-       if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
-       {
-               IL_EACH(g_monsters, true,
-               {
-                       Monster_Remove(it);
-               });
-               IL_CLEAR(g_monsters);
-
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
-               round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
-               return 1;
-       }
-
-       float total_alive_monsters = 0, supermonster_count = 0, red_alive = 0, blue_alive = 0, yellow_alive = 0, pink_alive = 0;
-
-       IL_EACH(g_monsters, it.health > 0,
-       {
-               if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
-                       ++supermonster_count;
-               ++total_alive_monsters;
-
-               if(teamplay)
-               switch(it.team)
-               {
-                       case NUM_TEAM_1: ++red_alive; break;
-                       case NUM_TEAM_2: ++blue_alive; break;
-                       case NUM_TEAM_3: ++yellow_alive; break;
-                       case NUM_TEAM_4: ++pink_alive; break;
-               }
-       });
-
-       if((total_alive_monsters + inv_numkilled) < inv_maxspawned && inv_maxcurrent < inv_maxspawned)
-       {
-               if(time >= inv_lastcheck)
-               {
-                       invasion_SpawnMonsters(supermonster_count);
-                       inv_lastcheck = time + autocvar_g_invasion_spawn_delay;
-               }
-
-               return 0;
-       }
-
-       if(inv_numspawned < 1)
-               return 0; // nothing has spawned yet
-
-       if(teamplay)
-       {
-               if(((red_alive > 0) + (blue_alive > 0) + (yellow_alive > 0) + (pink_alive > 0)) > 1)
-                       return 0;
-       }
-       else if(inv_numkilled < inv_maxspawned)
-               return 0;
-
-       entity winner = NULL;
-       float winning_score = 0, winner_team = 0;
-
-
-       if(teamplay)
-       {
-               if(red_alive > 0) { winner_team = NUM_TEAM_1; }
-               if(blue_alive > 0)
-               if(winner_team) { winner_team = 0; }
-               else { winner_team = NUM_TEAM_2; }
-               if(yellow_alive > 0)
-               if(winner_team) { winner_team = 0; }
-               else { winner_team = NUM_TEAM_3; }
-               if(pink_alive > 0)
-               if(winner_team) { winner_team = 0; }
-               else { winner_team = NUM_TEAM_4; }
-       }
-       else
-       {
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       float cs = GameRules_scoring_add(it, KILLS, 0);
-                       if(cs > winning_score)
-                       {
-                               winning_score = cs;
-                               winner = it;
-                       }
-               });
-       }
-
-       IL_EACH(g_monsters, true,
-       {
-               Monster_Remove(it);
-       });
-       IL_CLEAR(g_monsters);
-
-       if(teamplay)
-       {
-               if(winner_team)
-               {
-                       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));
-               }
-       }
-       else if(winner)
-       {
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, winner.netname);
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_PLAYER_WIN, winner.netname);
-       }
-
-       round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
-
-       return 1;
-}
-
-bool Invasion_CheckPlayers()
-{
-       return true;
-}
-
-void Invasion_RoundStart()
-{
-       int numplayers = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               it.player_blocked = false;
-               ++numplayers;
-       });
-
-       if(inv_roundcnt < inv_maxrounds)
-               inv_roundcnt += 1; // a limiter to stop crazy counts
-
-       inv_monsterskill = inv_roundcnt + max(1, numplayers * 0.3);
-
-       inv_maxcurrent = 0;
-       inv_numspawned = 0;
-       inv_numkilled = 0;
-
-       inv_maxspawned = rint(max(autocvar_g_invasion_monster_count, autocvar_g_invasion_monster_count * (inv_roundcnt * 0.5)));
-
-       if(teamplay)
-       {
-               DistributeEvenly_Init(inv_maxspawned, invasion_teams);
-               inv_monsters_perteam[NUM_TEAM_1] = DistributeEvenly_Get(1);
-               inv_monsters_perteam[NUM_TEAM_2] = DistributeEvenly_Get(1);
-               if(invasion_teams >= 3) inv_monsters_perteam[NUM_TEAM_3] = DistributeEvenly_Get(1);
-               if(invasion_teams >= 4) inv_monsters_perteam[NUM_TEAM_4] = DistributeEvenly_Get(1);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(inv, MonsterDies)
-{
-       entity frag_target = M_ARGV(0, entity);
-       entity frag_attacker = M_ARGV(1, entity);
-
-       if(!(frag_target.spawnflags & MONSTERFLAG_RESPAWNED))
-       {
-               if(autocvar_g_invasion_type == INV_TYPE_ROUND)
-               {
-                       inv_numkilled += 1;
-                       inv_maxcurrent -= 1;
-               }
-               if(teamplay) { inv_monsters_perteam[frag_target.team] -= 1; }
-
-               if(IS_PLAYER(frag_attacker))
-               if(SAME_TEAM(frag_attacker, frag_target)) // in non-teamplay modes, same team = same player, so this works
-                       GameRules_scoring_add(frag_attacker, KILLS, -1);
-               else
-               {
-                       GameRules_scoring_add(frag_attacker, KILLS, +1);
-                       if(teamplay)
-                               TeamScore_AddToTeam(frag_attacker.team, ST_INV_KILLS, +1);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(inv, MonsterSpawn)
-{
-       entity mon = M_ARGV(0, entity);
-       mon.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
-
-       if(autocvar_g_invasion_type == INV_TYPE_HUNT)
-               return false; // allowed
-
-       if(!(mon.spawnflags & MONSTERFLAG_SPAWNED))
-               return true;
-
-       if(!(mon.spawnflags & MONSTERFLAG_RESPAWNED))
-       {
-               inv_numspawned += 1;
-               inv_maxcurrent += 1;
-       }
-
-       mon.monster_skill = inv_monsterskill;
-
-       if((get_monsterinfo(mon.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_INVASION_SUPERMONSTER, mon.monster_name);
-}
-
-MUTATOR_HOOKFUNCTION(inv, SV_StartFrame)
-{
-       if(autocvar_g_invasion_type != INV_TYPE_ROUND)
-               return; // uses map spawned monsters
-
-       monsters_total = inv_maxspawned; // TODO: make sure numspawned never exceeds maxspawned
-       monsters_killed = inv_numkilled;
-}
-
-MUTATOR_HOOKFUNCTION(inv, PlayerRegen)
-{
-       // no regeneration in invasion, regardless of the game type
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(inv, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.bot_attack)
-               IL_REMOVE(g_bot_targets, player);
-       player.bot_attack = false;
-}
-
-MUTATOR_HOOKFUNCTION(inv, Damage_Calculate)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_damage = M_ARGV(4, float);
-       vector frag_force = M_ARGV(6, vector);
-
-       if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target) && frag_attacker != frag_target)
-       {
-               frag_damage = 0;
-               frag_force = '0 0 0';
-
-               M_ARGV(4, float) = frag_damage;
-               M_ARGV(6, vector) = frag_force;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(inv, BotShouldAttack)
-{
-       entity targ = M_ARGV(1, entity);
-
-       if(!IS_MONSTER(targ))
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(inv, SetStartItems)
-{
-       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
-       {
-               start_health = 200;
-               start_armorvalue = 200;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(inv, AccuracyTargetValid)
-{
-       entity frag_target = M_ARGV(1, entity);
-
-       if(IS_MONSTER(frag_target))
-               return MUT_ACCADD_INVALID;
-       return MUT_ACCADD_INDIFFERENT;
-}
-
-MUTATOR_HOOKFUNCTION(inv, AllowMobSpawning)
-{
-       // monster spawning disabled during an invasion
-       M_ARGV(1, string) = "You cannot spawn monsters during an invasion!";
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(inv, CheckRules_World)
-{
-       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
-               return false;
-
-       M_ARGV(0, float) = WinningCondition_Invasion();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(inv, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(0, float) = invasion_teams;
-}
-
-MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
-{
-       M_ARGV(0, string) = "This command does not work during an invasion!";
-       return true;
-}
-
-void invasion_ScoreRules(int inv_teams)
-{
-       if(inv_teams) { CheckAllowedTeams(NULL); }
-       GameRules_score_enabled(false);
-       GameRules_scoring(inv_teams, 0, 0, {
-           if (inv_teams) {
-            field_team(ST_INV_KILLS, "frags", SFL_SORT_PRIO_PRIMARY);
-           }
-           field(SP_KILLS, "frags", ((inv_teams) ? SFL_SORT_PRIO_SECONDARY : SFL_SORT_PRIO_PRIMARY));
-       });
-}
-
-void invasion_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
-{
-       if(autocvar_g_invasion_type == INV_TYPE_HUNT || autocvar_g_invasion_type == INV_TYPE_STAGE)
-               cvar_set("fraglimit", "0");
-
-       if(autocvar_g_invasion_teams)
-       {
-               invasion_teams = BITS(bound(2, autocvar_g_invasion_teams, 4));
-       }
-       else
-               invasion_teams = 0;
-
-       independent_players = 1; // to disable extra useless scores
-
-       invasion_ScoreRules(invasion_teams);
-
-       independent_players = 0;
-
-       if(autocvar_g_invasion_type == INV_TYPE_ROUND)
-       {
-               round_handler_Spawn(Invasion_CheckPlayers, Invasion_CheckWinner, Invasion_RoundStart);
-               round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
-
-               inv_roundcnt = 0;
-               inv_maxrounds = 15; // 15?
-       }
-}
-
-void invasion_Initialize()
-{
-       InitializeEntity(NULL, invasion_DelayedInit, INITPRIO_GAMETYPE);
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_invasion.qh b/qcsrc/server/mutators/mutator/gamemode_invasion.qh
deleted file mode 100644 (file)
index 0ea0e82..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-#define autocvar_g_invasion_point_limit cvar("g_invasion_point_limit")
-int autocvar_g_invasion_teams;
-int autocvar_g_invasion_type;
-bool autocvar_g_invasion_team_spawns;
-bool g_invasion;
-void invasion_Initialize();
-
-REGISTER_MUTATOR(inv, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-               if (autocvar_g_invasion_teams >= 2) {
-                       GameRules_teams(true);
-                       GameRules_spawning_teams(autocvar_g_invasion_team_spawns);
-               }
-        GameRules_limit_score(autocvar_g_invasion_point_limit);
-
-               g_invasion = true;
-               cvar_settemp("g_monsters", "1");
-               invasion_Initialize();
-       }
-       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;
-
-const int INV_TYPE_ROUND = 0; // round-based waves of enemies
-const int INV_TYPE_HUNT = 1; // clear the map of placed enemies
-const int INV_TYPE_STAGE = 2; // reach the end of the level
diff --git a/qcsrc/server/mutators/mutator/gamemode_keepaway.qc b/qcsrc/server/mutators/mutator/gamemode_keepaway.qc
deleted file mode 100644 (file)
index 567f24b..0000000
+++ /dev/null
@@ -1,472 +0,0 @@
-#include "gamemode_keepaway.qh"
-
-#include <common/effects/all.qh>
-
-.entity ballcarried;
-
-int autocvar_g_keepaway_ballcarrier_effects;
-float autocvar_g_keepaway_ballcarrier_damage;
-float autocvar_g_keepaway_ballcarrier_force;
-float autocvar_g_keepaway_ballcarrier_highspeed;
-float autocvar_g_keepaway_ballcarrier_selfdamage;
-float autocvar_g_keepaway_ballcarrier_selfforce;
-float autocvar_g_keepaway_noncarrier_damage;
-float autocvar_g_keepaway_noncarrier_force;
-float autocvar_g_keepaway_noncarrier_selfdamage;
-float autocvar_g_keepaway_noncarrier_selfforce;
-bool autocvar_g_keepaway_noncarrier_warn;
-int autocvar_g_keepaway_score_bckill;
-int autocvar_g_keepaway_score_killac;
-int autocvar_g_keepaway_score_timepoints;
-float autocvar_g_keepaway_score_timeinterval;
-float autocvar_g_keepawayball_damageforcescale;
-int autocvar_g_keepawayball_effects;
-float autocvar_g_keepawayball_respawntime;
-int autocvar_g_keepawayball_trail_color;
-
-bool ka_ballcarrier_waypointsprite_visible_for_player(entity this, entity player, entity view) // runs on waypoints which are attached to ballcarriers, updates once per frame
-{
-       if(view.ballcarried)
-               if(IS_SPEC(player))
-                       return false; // we don't want spectators of the ballcarrier to see the attached waypoint on the top of their screen
-
-       // TODO: Make the ballcarrier lack a waypointsprite whenever they have the invisibility powerup
-
-       return true;
-}
-
-void ka_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
-{
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":ka:", mode, ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
-}
-
-void ka_TouchEvent(entity this, entity toucher);
-void ka_RespawnBall(entity this) // runs whenever the ball needs to be relocated
-{
-       if(game_stopped) return;
-       vector oldballorigin = this.origin;
-
-       if(!MoveToRandomMapLocation(this, DPCONTENTS_SOLID | DPCONTENTS_CORPSE | DPCONTENTS_PLAYERCLIP, DPCONTENTS_SLIME | DPCONTENTS_LAVA | DPCONTENTS_SKY | DPCONTENTS_BODY | DPCONTENTS_DONOTENTER, Q3SURFACEFLAG_SKY, 10, 1024, 256))
-       {
-               entity spot = SelectSpawnPoint(this, true);
-               setorigin(this, spot.origin);
-               this.angles = spot.angles;
-       }
-
-       makevectors(this.angles);
-       set_movetype(this, MOVETYPE_BOUNCE);
-       this.velocity = '0 0 200';
-       this.angles = '0 0 0';
-       this.effects = autocvar_g_keepawayball_effects;
-       settouch(this, ka_TouchEvent);
-       setthink(this, ka_RespawnBall);
-       this.nextthink = time + autocvar_g_keepawayball_respawntime;
-       navigation_dynamicgoal_set(this);
-
-       Send_Effect(EFFECT_ELECTRO_COMBO, oldballorigin, '0 0 0', 1);
-       Send_Effect(EFFECT_ELECTRO_COMBO, this.origin, '0 0 0', 1);
-
-       WaypointSprite_Spawn(WP_KaBall, 0, 0, this, '0 0 64', NULL, this.team, this, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
-       WaypointSprite_Ping(this.waypointsprite_attachedforcarrier);
-
-       sound(this, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-}
-
-void ka_TimeScoring(entity this)
-{
-       if(this.owner.ballcarried)
-       { // add points for holding the ball after a certain amount of time
-               if(autocvar_g_keepaway_score_timepoints)
-                       GameRules_scoring_add(this.owner, SCORE, autocvar_g_keepaway_score_timepoints);
-
-               GameRules_scoring_add(this.owner, KEEPAWAY_BCTIME, (autocvar_g_keepaway_score_timeinterval / 1)); // interval is divided by 1 so that time always shows "seconds"
-               this.nextthink = time + autocvar_g_keepaway_score_timeinterval;
-       }
-}
-
-void ka_TouchEvent(entity this, entity toucher) // runs any time that the ball comes in contact with something
-{
-       if(game_stopped) return;
-       if(!this) return;
-       if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
-       { // The ball fell off the map, respawn it since players can't get to it
-               ka_RespawnBall(this);
-               return;
-       }
-       if(IS_DEAD(toucher)) { return; }
-       if(STAT(FROZEN, toucher)) { return; }
-       if (!IS_PLAYER(toucher))
-       {  // The ball just touched an object, most likely the world
-               Send_Effect(EFFECT_BALL_SPARKS, this.origin, '0 0 0', 1);
-               sound(this, CH_TRIGGER, SND_KA_TOUCH, VOL_BASE, ATTEN_NORM);
-               return;
-       }
-       else if(this.wait > time) { return; }
-
-       // attach the ball to the player
-       this.owner = toucher;
-       toucher.ballcarried = this;
-       GameRules_scoring_vip(toucher, true);
-       setattachment(this, toucher, "");
-       setorigin(this, '0 0 0');
-
-       // make the ball invisible/unable to do anything/set up time scoring
-       this.velocity = '0 0 0';
-       set_movetype(this, MOVETYPE_NONE);
-       this.effects |= EF_NODRAW;
-       settouch(this, func_null);
-       setthink(this, ka_TimeScoring);
-       this.nextthink = time + autocvar_g_keepaway_score_timeinterval;
-       this.takedamage = DAMAGE_NO;
-       navigation_dynamicgoal_unset(this);
-
-       // apply effects to player
-       toucher.glow_color = autocvar_g_keepawayball_trail_color;
-       toucher.glow_trail = true;
-       toucher.effects |= autocvar_g_keepaway_ballcarrier_effects;
-
-       // messages and sounds
-       ka_EventLog("pickup", toucher);
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_PICKUP, toucher.netname);
-       Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP, toucher.netname);
-       Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_KEEPAWAY_PICKUP_SELF);
-       sound(this.owner, CH_TRIGGER, SND_KA_PICKEDUP, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-
-       // scoring
-       GameRules_scoring_add(toucher, KEEPAWAY_PICKUPS, 1);
-
-       // waypoints
-       WaypointSprite_AttachCarrier(WP_KaBallCarrier, toucher, RADARICON_FLAGCARRIER);
-       toucher.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = ka_ballcarrier_waypointsprite_visible_for_player;
-       WaypointSprite_UpdateRule(toucher.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-       WaypointSprite_Ping(toucher.waypointsprite_attachedforcarrier);
-       WaypointSprite_Kill(this.waypointsprite_attachedforcarrier);
-}
-
-void ka_DropEvent(entity plyr) // runs any time that a player is supposed to lose the ball
-{
-       entity ball;
-       ball = plyr.ballcarried;
-
-       if(!ball) { return; }
-
-       // reset the ball
-       setattachment(ball, NULL, "");
-       set_movetype(ball, MOVETYPE_BOUNCE);
-       ball.wait = time + 1;
-       settouch(ball, ka_TouchEvent);
-       setthink(ball, ka_RespawnBall);
-       ball.nextthink = time + autocvar_g_keepawayball_respawntime;
-       ball.takedamage = DAMAGE_YES;
-       ball.effects &= ~EF_NODRAW;
-       setorigin(ball, plyr.origin + '0 0 10');
-       ball.velocity = '0 0 200' + '0 100 0'*crandom() + '100 0 0'*crandom();
-       entity e = ball.owner; ball.owner = NULL;
-       e.ballcarried = NULL;
-       GameRules_scoring_vip(e, false);
-       navigation_dynamicgoal_set(ball);
-
-       // reset the player effects
-       plyr.glow_trail = false;
-       plyr.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
-
-       // messages and sounds
-       ka_EventLog("dropped", plyr);
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_KEEPAWAY_DROPPED, plyr.netname);
-       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEEPAWAY_DROPPED, plyr.netname);
-       sound(NULL, CH_TRIGGER, SND_KA_DROPPED, VOL_BASE, ATTEN_NONE); // ATTEN_NONE (it's a sound intended to be heard anywhere)
-
-       // scoring
-       // GameRules_scoring_add(plyr, KEEPAWAY_DROPS, 1); Not anymore, this is 100% the same as pickups and is useless.
-
-       // waypoints
-       WaypointSprite_Spawn(WP_KaBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER);
-       WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-       WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-       WaypointSprite_Kill(plyr.waypointsprite_attachedforcarrier);
-}
-
-/** used to clear the ballcarrier whenever the match switches from warmup to normal */
-void ka_Reset(entity this)
-{
-       if((this.owner) && (IS_PLAYER(this.owner)))
-               ka_DropEvent(this.owner);
-
-       if(time < game_starttime)
-       {
-               setthink(this, ka_RespawnBall);
-               settouch(this, func_null);
-               this.nextthink = game_starttime;
-       }
-       else
-               ka_RespawnBall(this);
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-void havocbot_goalrating_ball(entity this, float ratingscale, vector org)
-{
-       float t;
-       entity ball_owner;
-       ball_owner = ka_ball.owner;
-
-       if (ball_owner == this)
-               return;
-
-       // If ball is carried by player then hunt them down.
-       if (ball_owner)
-       {
-               t = (this.health + this.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
-               navigation_routerating(this, ball_owner, t * ratingscale, 2000);
-       }
-       else // Ball has been dropped so collect.
-               navigation_routerating(this, ka_ball, ratingscale, 2000);
-}
-
-void havocbot_role_ka_carrier(entity this)
-{
-       if (IS_DEAD(this))
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
-               havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-
-       if (!this.ballcarried)
-       {
-               this.havocbot_role = havocbot_role_ka_collector;
-               navigation_goalrating_timeout_expire(this, 2);
-       }
-}
-
-void havocbot_role_ka_collector(entity this)
-{
-       if (IS_DEAD(this))
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-               havocbot_goalrating_items(this, 10000, this.origin, 10000);
-               havocbot_goalrating_enemyplayers(this, 1000, this.origin, 10000);
-               havocbot_goalrating_ball(this, 20000, this.origin);
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-
-       if (this.ballcarried)
-       {
-               this.havocbot_role = havocbot_role_ka_carrier;
-               navigation_goalrating_timeout_expire(this, 2);
-       }
-}
-
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ka, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
-       {
-               if(frag_target.ballcarried) { // add to amount of times killing carrier
-                       GameRules_scoring_add(frag_attacker, KEEPAWAY_CARRIERKILLS, 1);
-                       if(autocvar_g_keepaway_score_bckill) // add bckills to the score
-                               GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_bckill);
-               }
-               else if(!frag_attacker.ballcarried)
-                       if(autocvar_g_keepaway_noncarrier_warn)
-                               Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN);
-
-               if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
-                       GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_killac);
-       }
-
-       if(frag_target.ballcarried) { ka_DropEvent(frag_target); } // a player with the ball has died, drop it
-}
-
-MUTATOR_HOOKFUNCTION(ka, GiveFragsForKill)
-{
-       M_ARGV(2, float) = 0; // no frags counted in keepaway
-       return true; // you deceptive little bugger ;3 This needs to be true in order for this function to even count.
-}
-
-MUTATOR_HOOKFUNCTION(ka, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       // clear the item used for the ball in keepaway
-       player.items &= ~IT_KEY1;
-
-       // if the player has the ball, make sure they have the item for it (Used for HUD primarily)
-       if(player.ballcarried)
-               player.items |= IT_KEY1;
-}
-
-MUTATOR_HOOKFUNCTION(ka, PlayerUseKey)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(MUTATOR_RETURNVALUE == 0)
-       if(player.ballcarried)
-       {
-               ka_DropEvent(player);
-               return true;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(ka, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-       float frag_damage = M_ARGV(4, float);
-       vector frag_force = M_ARGV(6, vector);
-
-       if(frag_attacker.ballcarried) // if the attacker is a ballcarrier
-       {
-               if(frag_target == frag_attacker) // damage done to yourself
-               {
-                       frag_damage *= autocvar_g_keepaway_ballcarrier_selfdamage;
-                       frag_force *= autocvar_g_keepaway_ballcarrier_selfforce;
-               }
-               else // damage done to noncarriers
-               {
-                       frag_damage *= autocvar_g_keepaway_ballcarrier_damage;
-                       frag_force *= autocvar_g_keepaway_ballcarrier_force;
-               }
-       }
-       else if (!frag_target.ballcarried) // if the target is a noncarrier
-       {
-               if(frag_target == frag_attacker) // damage done to yourself
-               {
-                       frag_damage *= autocvar_g_keepaway_noncarrier_selfdamage;
-                       frag_force *= autocvar_g_keepaway_noncarrier_selfforce;
-               }
-               else // damage done to other noncarriers
-               {
-                       frag_damage *= autocvar_g_keepaway_noncarrier_damage;
-                       frag_force *= autocvar_g_keepaway_noncarrier_force;
-               }
-       }
-
-       M_ARGV(4, float) = frag_damage;
-       M_ARGV(6, vector) = frag_force;
-}
-
-MUTATOR_HOOKFUNCTION(ka, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
-}
-
-MUTATOR_HOOKFUNCTION(ka, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
-}
-
-MUTATOR_HOOKFUNCTION(ka, PlayerPowerups)
-{
-       entity player = M_ARGV(0, entity);
-
-       // In the future this hook is supposed to allow me to do some extra stuff with waypointsprites and invisibility powerup
-       // So bare with me until I can fix a certain bug with ka_ballcarrier_waypointsprite_visible_for_player()
-
-       player.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
-
-       if(player.ballcarried)
-               player.effects |= autocvar_g_keepaway_ballcarrier_effects;
-}
-
-
-MUTATOR_HOOKFUNCTION(ka, PlayerPhysics_UpdateStats)
-{
-       entity player = M_ARGV(0, entity);
-       // these automatically reset, no need to worry
-
-       if(player.ballcarried)
-               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_keepaway_ballcarrier_highspeed;
-}
-
-MUTATOR_HOOKFUNCTION(ka, BotShouldAttack)
-{
-       entity bot = M_ARGV(0, entity);
-       entity targ = M_ARGV(1, entity);
-
-       // if neither player has ball then don't attack unless the ball is on the ground
-       if(!targ.ballcarried && !bot.ballcarried && ka_ball.owner)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(ka, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       if (bot.ballcarried)
-               bot.havocbot_role = havocbot_role_ka_carrier;
-       else
-               bot.havocbot_role = havocbot_role_ka_collector;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
-{
-       entity frag_target = M_ARGV(0, entity);
-
-       if(frag_target.ballcarried)
-               ka_DropEvent(frag_target);
-}
-
-.bool pushable;
-
-// ==============
-// Initialization
-// ==============
-
-MODEL(KA_BALL, "models/orbs/orbblue.md3");
-
-void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
-{
-       entity e = new(keepawayball);
-       setmodel(e, MDL_KA_BALL);
-       setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
-       e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
-       e.takedamage = DAMAGE_YES;
-       e.solid = SOLID_TRIGGER;
-       set_movetype(e, MOVETYPE_BOUNCE);
-       e.glow_color = autocvar_g_keepawayball_trail_color;
-       e.glow_trail = true;
-       e.flags = FL_ITEM;
-       IL_PUSH(g_items, e);
-       e.pushable = true;
-       e.reset = ka_Reset;
-       settouch(e, ka_TouchEvent);
-       e.owner = NULL;
-       ka_ball = e;
-       navigation_dynamicgoal_init(ka_ball, false);
-
-       InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
-}
-
-void ka_Initialize() // run at the start of a match, initiates game mode
-{
-       ka_SpawnBall();
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_keepaway.qh b/qcsrc/server/mutators/mutator/gamemode_keepaway.qh
deleted file mode 100644 (file)
index abbabbd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-void ka_Initialize();
-
-REGISTER_MUTATOR(ka, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-           GameRules_scoring(0, SFL_SORT_PRIO_PRIMARY, 0, {
-            field(SP_KEEPAWAY_PICKUPS, "pickups", 0);
-            field(SP_KEEPAWAY_CARRIERKILLS, "bckills", 0);
-            field(SP_KEEPAWAY_BCTIME, "bctime", SFL_SORT_PRIO_SECONDARY);
-        });
-
-               ka_Initialize();
-       }
-       return false;
-}
-
-
-entity ka_ball;
-
-void(entity this) havocbot_role_ka_carrier;
-void(entity this) havocbot_role_ka_collector;
-
-void ka_DropEvent(entity plyr);
diff --git a/qcsrc/server/mutators/mutator/gamemode_keyhunt.qc b/qcsrc/server/mutators/mutator/gamemode_keyhunt.qc
deleted file mode 100644 (file)
index 0457648..0000000
+++ /dev/null
@@ -1,1321 +0,0 @@
-#include "gamemode_keyhunt.qh"
-
-float autocvar_g_balance_keyhunt_damageforcescale;
-float autocvar_g_balance_keyhunt_delay_collect;
-float autocvar_g_balance_keyhunt_delay_damage_return;
-float autocvar_g_balance_keyhunt_delay_return;
-float autocvar_g_balance_keyhunt_delay_round;
-float autocvar_g_balance_keyhunt_delay_tracking;
-float autocvar_g_balance_keyhunt_return_when_unreachable;
-float autocvar_g_balance_keyhunt_dropvelocity;
-float autocvar_g_balance_keyhunt_maxdist;
-float autocvar_g_balance_keyhunt_protecttime;
-
-int autocvar_g_balance_keyhunt_score_capture;
-int autocvar_g_balance_keyhunt_score_carrierfrag;
-int autocvar_g_balance_keyhunt_score_collect;
-int autocvar_g_balance_keyhunt_score_destroyed;
-int autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
-int autocvar_g_balance_keyhunt_score_push;
-float autocvar_g_balance_keyhunt_throwvelocity;
-
-//int autocvar_g_keyhunt_teams;
-int autocvar_g_keyhunt_teams_override;
-
-// #define KH_PLAYER_USE_ATTACHMENT
-// #define KH_PLAYER_USE_CARRIEDMODEL
-
-#ifdef KH_PLAYER_USE_ATTACHMENT
-const vector KH_PLAYER_ATTACHMENT_DIST_ROTATED = '0 -4 0';
-const vector KH_PLAYER_ATTACHMENT_DIST = '4 0 0';
-const vector KH_PLAYER_ATTACHMENT = '0 0 0';
-const vector KH_PLAYER_ATTACHMENT_ANGLES = '0 0 0';
-const string KH_PLAYER_ATTACHMENT_BONE = "";
-#else
-const float KH_KEY_ZSHIFT = 22;
-const float KH_KEY_XYDIST = 24;
-const float KH_KEY_XYSPEED = 45;
-#endif
-const float KH_KEY_WP_ZSHIFT = 20;
-
-const vector KH_KEY_MIN = '-10 -10 -46';
-const vector KH_KEY_MAX = '10 10 3';
-const float KH_KEY_BRIGHTNESS = 2;
-
-bool kh_no_radar_circles;
-
-// kh_state
-//     bits  0- 4: team of key 1, or 0 for no such key, or 30 for dropped, or 31 for self
-//     bits  5- 9: team of key 2, or 0 for no such key, or 30 for dropped, or 31 for self
-//     bits 10-14: team of key 3, or 0 for no such key, or 30 for dropped, or 31 for self
-//     bits 15-19: team of key 4, or 0 for no such key, or 30 for dropped, or 31 for self
-.float siren_time;  //  time delay the siren
-//.float stuff_time;  //  time delay to stuffcmd a cvar
-
-int kh_keystatus[17];
-//kh_keystatus[0] = status of dropped keys, kh_keystatus[1 - 16] = player #
-//replace 17 with cvar("maxplayers") or similar !!!!!!!!!
-//for(i = 0; i < maxplayers; ++i)
-//     kh_keystatus[i] = "0";
-
-int kh_Team_ByID(int t)
-{
-       if(t == 0) return NUM_TEAM_1;
-       if(t == 1) return NUM_TEAM_2;
-       if(t == 2) return NUM_TEAM_3;
-       if(t == 3) return NUM_TEAM_4;
-       return 0;
-}
-
-//entity kh_worldkeylist;
-.entity kh_worldkeynext;
-entity kh_controller;
-//bool kh_tracking_enabled;
-int kh_teams;
-int kh_interferemsg_team;
-float kh_interferemsg_time;
-.entity kh_next, kh_prev; // linked list
-.float kh_droptime;
-.int kh_dropperteam;
-.entity kh_previous_owner;
-.int kh_previous_owner_playerid;
-
-int kh_key_dropped, kh_key_carried;
-
-int kh_Key_AllOwnedByWhichTeam();
-
-const int ST_KH_CAPS = 1;
-void kh_ScoreRules(int teams)
-{
-       GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-        field_team(ST_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
-        field(SP_KH_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
-        field(SP_KH_PUSHES, "pushes", 0);
-        field(SP_KH_DESTROYS, "destroyed", SFL_LOWER_IS_BETTER);
-        field(SP_KH_PICKUPS, "pickups", 0);
-        field(SP_KH_KCKILLS, "kckills", 0);
-        field(SP_KH_LOSSES, "losses", SFL_LOWER_IS_BETTER);
-       });
-}
-
-bool kh_KeyCarrier_waypointsprite_visible_for_player(entity this, entity player, entity view)  // runs all the time
-{
-       if(!IS_PLAYER(view) || DIFF_TEAM(this, view))
-               if(!kh_tracking_enabled)
-                       return false;
-
-       return true;
-}
-
-bool kh_Key_waypointsprite_visible_for_player(entity this, entity player, entity view)
-{
-       if(!kh_tracking_enabled)
-               return false;
-       if(!this.owner)
-               return true;
-       if(!this.owner.owner)
-               return true;
-       return false;  // draw only when key is not owned
-}
-
-void kh_update_state()
-{
-       entity key;
-       int f;
-       int s = 0;
-       FOR_EACH_KH_KEY(key)
-       {
-               if(key.owner)
-                       f = key.team;
-               else
-                       f = 30;
-               s |= (32 ** key.count) * f;
-       }
-
-       FOREACH_CLIENT(true, { STAT(KH_KEYS, it) = s; });
-
-       FOR_EACH_KH_KEY(key)
-       {
-               if(key.owner)
-                       STAT(KH_KEYS, key.owner) |= (32 ** key.count) * 31;
-       }
-       //print(ftos((nextent(NULL)).kh_state), "\n");
-}
-
-
-
-
-var kh_Think_t kh_Controller_Thinkfunc;
-void kh_Controller_SetThink(float t, kh_Think_t func)  // runs occasionaly
-{
-       kh_Controller_Thinkfunc = func;
-       kh_controller.cnt = ceil(t);
-       if(t == 0)
-               kh_controller.nextthink = time; // force
-}
-void kh_WaitForPlayers();
-void kh_Controller_Think(entity this)  // called a lot
-{
-       if(game_stopped)
-               return;
-       if(this.cnt > 0)
-       {
-               if(getthink(this) != kh_WaitForPlayers)
-                       this.cnt -= 1;
-       }
-       else if(this.cnt == 0)
-       {
-               this.cnt -= 1;
-               kh_Controller_Thinkfunc();
-       }
-       this.nextthink = time + 1;
-}
-
-// frags f: take from cvar * f
-// frags 0: no frags
-void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner)  // update the score when a key is captured
-{
-       string s;
-       if(game_stopped)
-               return;
-
-       if(frags_player)
-               UpdateFrags(player, frags_player);
-
-       if(key && key.owner && frags_owner)
-               UpdateFrags(key.owner, frags_owner);
-
-       if(!autocvar_sv_eventlog)  //output extra info to the console or text file
-               return;
-
-       s = strcat(":keyhunt:", what, ":", ftos(player.playerid), ":", ftos(frags_player));
-
-       if(key && key.owner)
-               s = strcat(s, ":", ftos(key.owner.playerid));
-       else
-               s = strcat(s, ":0");
-
-       s = strcat(s, ":", ftos(frags_owner), ":");
-
-       if(key)
-               s = strcat(s, key.netname);
-
-       GameLogEcho(s);
-}
-
-vector kh_AttachedOrigin(entity e)  // runs when a team captures the flag, it can run 2 or 3 times.
-{
-       if(e.tag_entity)
-       {
-               makevectors(e.tag_entity.angles);
-               return e.tag_entity.origin + e.origin.x * v_forward - e.origin.y * v_right + e.origin.z * v_up;
-       }
-       else
-               return e.origin;
-}
-
-void kh_Key_Attach(entity key)  // runs when a player picks up a key and several times when a key is assigned to a player at the start of a round
-{
-#ifdef KH_PLAYER_USE_ATTACHMENT
-       entity first = key.owner.kh_next;
-       if(key == first)
-       {
-               setattachment(key, key.owner, KH_PLAYER_ATTACHMENT_BONE);
-               if(key.kh_next)
-               {
-                       setattachment(key.kh_next, key, "");
-                       setorigin(key, key.kh_next.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
-                       setorigin(key.kh_next, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
-                       key.kh_next.angles = '0 0 0';
-               }
-               else
-                       setorigin(key, KH_PLAYER_ATTACHMENT);
-               key.angles = KH_PLAYER_ATTACHMENT_ANGLES;
-       }
-       else
-       {
-               setattachment(key, key.kh_prev, "");
-               if(key.kh_next)
-                       setattachment(key.kh_next, key, "");
-               setorigin(key, KH_PLAYER_ATTACHMENT_DIST_ROTATED);
-               setorigin(first, first.origin - 0.5 * KH_PLAYER_ATTACHMENT_DIST);
-               key.angles = '0 0 0';
-       }
-#else
-       setattachment(key, key.owner, "");
-       setorigin(key, '0 0 1' * KH_KEY_ZSHIFT);  // fixing x, y in think
-       key.angles_y -= key.owner.angles.y;
-#endif
-       key.flags = 0;
-       if(IL_CONTAINS(g_items, key))
-               IL_REMOVE(g_items, key);
-       key.solid = SOLID_NOT;
-       set_movetype(key, MOVETYPE_NONE);
-       key.team = key.owner.team;
-       key.nextthink = time;
-       key.damageforcescale = 0;
-       key.takedamage = DAMAGE_NO;
-       key.modelindex = kh_key_carried;
-       navigation_dynamicgoal_unset(key);
-}
-
-void kh_Key_Detach(entity key) // runs every time a key is dropped or lost. Runs several times times when all the keys are captured
-{
-#ifdef KH_PLAYER_USE_ATTACHMENT
-       entity first = key.owner.kh_next;
-       if(key == first)
-       {
-               if(key.kh_next)
-               {
-                       setattachment(key.kh_next, key.owner, KH_PLAYER_ATTACHMENT_BONE);
-                       setorigin(key.kh_next, key.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
-                       key.kh_next.angles = KH_PLAYER_ATTACHMENT_ANGLES;
-               }
-       }
-       else
-       {
-               if(key.kh_next)
-                       setattachment(key.kh_next, key.kh_prev, "");
-               setorigin(first, first.origin + 0.5 * KH_PLAYER_ATTACHMENT_DIST);
-       }
-       // in any case:
-       setattachment(key, NULL, "");
-       setorigin(key, key.owner.origin + '0 0 1' * (STAT(PL_MIN, key.owner).z - KH_KEY_MIN_z));
-       key.angles = key.owner.angles;
-#else
-       setorigin(key, key.owner.origin + key.origin.z * '0 0 1');
-       setattachment(key, NULL, "");
-       key.angles_y += key.owner.angles.y;
-#endif
-       key.flags = FL_ITEM;
-       if(!IL_CONTAINS(g_items, key))
-               IL_PUSH(g_items, key);
-       key.solid = SOLID_TRIGGER;
-       set_movetype(key, MOVETYPE_TOSS);
-       key.pain_finished = time + autocvar_g_balance_keyhunt_delay_return;
-       key.damageforcescale = autocvar_g_balance_keyhunt_damageforcescale;
-       key.takedamage = DAMAGE_YES;
-       // let key.team stay
-       key.modelindex = kh_key_dropped;
-       navigation_dynamicgoal_set(key);
-       key.kh_previous_owner = key.owner;
-       key.kh_previous_owner_playerid = key.owner.playerid;
-}
-
-void kh_Key_AssignTo(entity key, entity player)  // runs every time a key is picked up or assigned. Runs prior to kh_key_attach
-{
-       if(key.owner == player)
-               return;
-
-       int ownerteam0 = kh_Key_AllOwnedByWhichTeam();
-
-       if(key.owner)
-       {
-               kh_Key_Detach(key);
-
-               // remove from linked list
-               if(key.kh_next)
-                       key.kh_next.kh_prev = key.kh_prev;
-               key.kh_prev.kh_next = key.kh_next;
-               key.kh_next = NULL;
-               key.kh_prev = NULL;
-
-               if(key.owner.kh_next == NULL)
-               {
-                       // No longer a key carrier
-                       if(!kh_no_radar_circles)
-                               WaypointSprite_Ping(key.owner.waypointsprite_attachedforcarrier);
-                       WaypointSprite_DetachCarrier(key.owner);
-               }
-       }
-
-       key.owner = player;
-
-       if(player)
-       {
-               // insert into linked list
-               key.kh_next = player.kh_next;
-               key.kh_prev = player;
-               player.kh_next = key;
-               if(key.kh_next)
-                       key.kh_next.kh_prev = key;
-
-               float i;
-               i = kh_keystatus[key.owner.playerid];
-                       if(key.netname == "^1red key")
-                               i += 1;
-                       if(key.netname == "^4blue key")
-                               i += 2;
-                       if(key.netname == "^3yellow key")
-                               i += 4;
-                       if(key.netname == "^6pink key")
-                               i += 8;
-               kh_keystatus[key.owner.playerid] = i;
-
-               kh_Key_Attach(key);
-
-               if(key.kh_next == NULL)
-               {
-                       // player is now a key carrier
-                       entity wp = WaypointSprite_AttachCarrier(WP_Null, player, RADARICON_FLAGCARRIER);
-                       wp.colormod = colormapPaletteColor(player.team - 1, 0);
-                       player.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_KeyCarrier_waypointsprite_visible_for_player;
-                       WaypointSprite_UpdateRule(player.waypointsprite_attachedforcarrier, player.team, SPRITERULE_TEAMPLAY);
-                       if(player.team == NUM_TEAM_1)
-                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierRed, WP_KeyCarrierFriend, WP_KeyCarrierRed);
-                       else if(player.team == NUM_TEAM_2)
-                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierBlue, WP_KeyCarrierFriend, WP_KeyCarrierBlue);
-                       else if(player.team == NUM_TEAM_3)
-                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierYellow, WP_KeyCarrierFriend, WP_KeyCarrierYellow);
-                       else if(player.team == NUM_TEAM_4)
-                               WaypointSprite_UpdateSprites(player.waypointsprite_attachedforcarrier, WP_KeyCarrierPink, WP_KeyCarrierFriend, WP_KeyCarrierPink);
-                       if(!kh_no_radar_circles)
-                               WaypointSprite_Ping(player.waypointsprite_attachedforcarrier);
-               }
-       }
-
-       // moved that here, also update if there's no player
-       kh_update_state();
-
-       key.pusher = NULL;
-
-       int ownerteam = kh_Key_AllOwnedByWhichTeam();
-       if(ownerteam != ownerteam0)
-       {
-               entity k;
-               if(ownerteam != -1)
-               {
-                       kh_interferemsg_time = time + 0.2;
-                       kh_interferemsg_team = player.team;
-
-                       // audit all key carrier sprites, update them to "Run here"
-                       FOR_EACH_KH_KEY(k)
-                       {
-                               if (!k.owner) continue;
-                               entity first = WP_Null;
-                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
-                               entity third = WP_Null;
-                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
-                               WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFinish, third);
-                       }
-               }
-               else
-               {
-                       kh_interferemsg_time = 0;
-
-                       // audit all key carrier sprites, update them to "Key Carrier"
-                       FOR_EACH_KH_KEY(k)
-                       {
-                               if (!k.owner) continue;
-                               entity first = WP_Null;
-                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model1, { first = it; break; });
-                               entity third = WP_Null;
-                               FOREACH(Waypoints, it.netname == k.owner.waypointsprite_attachedforcarrier.model3, { third = it; break; });
-                               WaypointSprite_UpdateSprites(k.owner.waypointsprite_attachedforcarrier, first, WP_KeyCarrierFriend, third);
-                       }
-               }
-       }
-}
-
-void kh_Key_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
-       if(this.owner)
-               return;
-       if(ITEM_DAMAGE_NEEDKILL(deathtype))
-       {
-               this.pain_finished = bound(time, time + autocvar_g_balance_keyhunt_delay_damage_return, this.pain_finished);
-               return;
-       }
-       if(force == '0 0 0')
-               return;
-       if(time > this.pushltime)
-               if(IS_PLAYER(attacker))
-                       this.team = attacker.team;
-}
-
-void kh_Key_Collect(entity key, entity player)  //a player picks up a dropped key
-{
-       sound(player, CH_TRIGGER, SND_KH_COLLECT, VOL_BASE, ATTEN_NORM);
-
-       if(key.kh_dropperteam != player.team)
-       {
-               kh_Scores_Event(player, key, "collect", autocvar_g_balance_keyhunt_score_collect, 0);
-               GameRules_scoring_add(player, KH_PICKUPS, 1);
-       }
-       key.kh_dropperteam = 0;
-       int realteam = kh_Team_ByID(key.count);
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_PICKUP), player.netname);
-
-       kh_Key_AssignTo(key, player); // this also updates .kh_state
-}
-
-void kh_Key_Touch(entity this, entity toucher)  // runs many, many times when a key has been dropped and can be picked up
-{
-       if(game_stopped)
-               return;
-
-       if(this.owner) // already carried
-               return;
-
-       if(ITEM_TOUCH_NEEDKILL())
-       {
-               this.pain_finished = bound(time, time + autocvar_g_balance_keyhunt_delay_damage_return, this.pain_finished);
-               return;
-       }
-
-       if (!IS_PLAYER(toucher))
-               return;
-       if(IS_DEAD(toucher))
-               return;
-       if(toucher == this.enemy)
-               if(time < this.kh_droptime + autocvar_g_balance_keyhunt_delay_collect)
-                       return;  // you just dropped it!
-       kh_Key_Collect(this, toucher);
-}
-
-void kh_Key_Remove(entity key)  // runs after when all the keys have been collected or when a key has been dropped for more than X seconds
-{
-       entity o = key.owner;
-       kh_Key_AssignTo(key, NULL);
-       if(o) // it was attached
-               WaypointSprite_Kill(key.waypointsprite_attachedforcarrier);
-       else // it was dropped
-               WaypointSprite_DetachCarrier(key);
-
-       // remove key from key list
-       if (kh_worldkeylist == key)
-               kh_worldkeylist = kh_worldkeylist.kh_worldkeynext;
-       else
-       {
-               o = kh_worldkeylist;
-               while (o)
-               {
-                       if (o.kh_worldkeynext == key)
-                       {
-                               o.kh_worldkeynext = o.kh_worldkeynext.kh_worldkeynext;
-                               break;
-                       }
-                       o = o.kh_worldkeynext;
-               }
-       }
-
-       delete(key);
-
-       kh_update_state();
-}
-
-void kh_FinishRound()  // runs when a team captures the keys
-{
-       // prepare next round
-       kh_interferemsg_time = 0;
-       entity key;
-
-       kh_no_radar_circles = true;
-       FOR_EACH_KH_KEY(key)
-               kh_Key_Remove(key);
-       kh_no_radar_circles = false;
-
-       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
-       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
-}
-
-void nades_GiveBonus(entity player, float score);
-
-void kh_WinnerTeam(int winner_team)  // runs when a team wins
-{
-       // all key carriers get some points
-       entity key;
-       float 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)
-       {
-               float f = DistributeEvenly_Get(1);
-               kh_Scores_Event(key.owner, key, "capture", f, 0);
-               GameRules_scoring_add_team(key.owner, KH_CAPS, 1);
-               nades_GiveBonus(key.owner, autocvar_g_nades_bonus_score_high);
-       }
-
-       bool first = true;
-       string keyowner = "";
-       FOR_EACH_KH_KEY(key)
-               if(key.owner.kh_next == key)
-               {
-                       if(!first)
-                               keyowner = strcat(keyowner, ", ");
-                       keyowner = key.owner.netname;
-                       first = false;
-               }
-
-       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_KEYHUNT_CAPTURE), keyowner);
-
-       first = true;
-       vector firstorigin = '0 0 0', lastorigin = '0 0 0', midpoint = '0 0 0';
-       FOR_EACH_KH_KEY(key)
-       {
-               vector thisorigin = kh_AttachedOrigin(key);
-               //dprint("Key origin: ", vtos(thisorigin), "\n");
-               midpoint += thisorigin;
-
-               if(!first)
-                       te_lightning2(NULL, lastorigin, thisorigin);
-               lastorigin = thisorigin;
-               if(first)
-                       firstorigin = thisorigin;
-               first = false;
-       }
-       if(NumTeams(kh_teams) > 2)
-       {
-               te_lightning2(NULL, lastorigin, firstorigin);
-       }
-       midpoint = midpoint * (1 / NumTeams(kh_teams));
-       te_customflash(midpoint, 1000, 1, Team_ColorRGB(winner_team) * 0.5 + '0.5 0.5 0.5');  // make the color >=0.5 in each component
-
-       play2all(SND(KH_CAPTURE));
-       kh_FinishRound();
-}
-
-void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes a flag carrier off the map
-{
-       float f;
-       entity attacker = NULL;
-       if(lostkey.pusher)
-               if(lostkey.pusher.team != loser_team)
-                       if(IS_PLAYER(lostkey.pusher))
-                               attacker = lostkey.pusher;
-
-       if(attacker)
-       {
-               if(lostkey.kh_previous_owner)
-                       kh_Scores_Event(lostkey.kh_previous_owner, NULL, "pushed", 0, -autocvar_g_balance_keyhunt_score_push);
-                       // don't actually GIVE him the -nn points, just log
-               kh_Scores_Event(attacker, NULL, "push", autocvar_g_balance_keyhunt_score_push, 0);
-               GameRules_scoring_add(attacker, KH_PUSHES, 1);
-               //centerprint(attacker, "Your push is the best!"); // does this really need to exist?
-       }
-       else
-       {
-               int players = 0;
-               float of = autocvar_g_balance_keyhunt_score_destroyed_ownfactor;
-
-               FOREACH_CLIENT(IS_PLAYER(it) && it.team != loser_team, { ++players; });
-
-               entity key;
-               int keys = 0;
-               FOR_EACH_KH_KEY(key)
-                       if(key.owner && key.team != loser_team)
-                               ++keys;
-
-               if(lostkey.kh_previous_owner)
-                       kh_Scores_Event(lostkey.kh_previous_owner, NULL, "destroyed", 0, -autocvar_g_balance_keyhunt_score_destroyed);
-                       // don't actually GIVE him the -nn points, just log
-
-               if(lostkey.kh_previous_owner.playerid == lostkey.kh_previous_owner_playerid)
-                       GameRules_scoring_add(lostkey.kh_previous_owner, KH_DESTROYS, 1);
-
-               DistributeEvenly_Init(autocvar_g_balance_keyhunt_score_destroyed, keys * of + players);
-
-               FOR_EACH_KH_KEY(key)
-                       if(key.owner && key.team != loser_team)
-                       {
-                               f = DistributeEvenly_Get(of);
-                               kh_Scores_Event(key.owner, NULL, "destroyed_holdingkey", f, 0);
-                       }
-
-               int fragsleft = DistributeEvenly_Get(players);
-
-               // Now distribute these among all other teams...
-               int j = NumTeams(kh_teams) - 1;
-               for(int i = 0; i < NumTeams(kh_teams); ++i)
-               {
-                       int thisteam = kh_Team_ByID(i);
-                       if(thisteam == loser_team) // bad boy, no cookie - this WILL happen
-                               continue;
-
-                       players = 0;
-                       FOREACH_CLIENT(IS_PLAYER(it) && it.team == thisteam, { ++players; });
-
-                       DistributeEvenly_Init(fragsleft, j);
-                       fragsleft = DistributeEvenly_Get(j - 1);
-                       DistributeEvenly_Init(DistributeEvenly_Get(1), players);
-
-                       FOREACH_CLIENT(IS_PLAYER(it) && it.team == thisteam, {
-                               f = DistributeEvenly_Get(1);
-                               kh_Scores_Event(it, NULL, "destroyed", f, 0);
-                       });
-
-                       --j;
-               }
-       }
-
-       int realteam = kh_Team_ByID(lostkey.count);
-       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(loser_team, CENTER_ROUND_TEAM_LOSS));
-       if(attacker)
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_PUSHED), attacker.netname, lostkey.kh_previous_owner.netname);
-       else
-               Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DESTROYED), lostkey.kh_previous_owner.netname);
-
-       play2all(SND(KH_DESTROY));
-       te_tarexplosion(lostkey.origin);
-
-       kh_FinishRound();
-}
-
-void kh_Key_Think(entity this)  // runs all the time
-{
-       if(game_stopped)
-               return;
-
-       if(this.owner)
-       {
-#ifndef KH_PLAYER_USE_ATTACHMENT
-               makevectors('0 1 0' * (this.cnt + (time % 360) * KH_KEY_XYSPEED));
-               setorigin(this, v_forward * KH_KEY_XYDIST + '0 0 1' * this.origin.z);
-#endif
-       }
-
-       // if in nodrop or time over, end the round
-       if(!this.owner)
-               if(time > this.pain_finished)
-                       kh_LoserTeam(this.team, this);
-
-       if(this.owner)
-       if(kh_Key_AllOwnedByWhichTeam() != -1)
-       {
-               if(this.siren_time < time)
-               {
-                       sound(this.owner, CH_TRIGGER, SND_KH_ALARM, VOL_BASE, ATTEN_NORM);  // play a simple alarm
-                       this.siren_time = time + 2.5;  // repeat every 2.5 seconds
-               }
-
-               entity key;
-               vector p = this.owner.origin;
-               FOR_EACH_KH_KEY(key)
-                       if(vdist(key.owner.origin - p, >, autocvar_g_balance_keyhunt_maxdist))
-                               goto not_winning;
-               kh_WinnerTeam(this.team);
-LABEL(not_winning)
-       }
-
-       if(kh_interferemsg_time && time > kh_interferemsg_time)
-       {
-               kh_interferemsg_time = 0;
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       if(it.team == kh_interferemsg_team)
-                               if(it.kh_next)
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_MEET);
-                               else
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_KEYHUNT_HELP);
-                       else
-                               Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(kh_interferemsg_team, CENTER_KEYHUNT_INTERFERE));
-               });
-       }
-
-       this.nextthink = time + 0.05;
-}
-
-void key_reset(entity this)
-{
-       kh_Key_AssignTo(this, NULL);
-       kh_Key_Remove(this);
-}
-
-const string STR_ITEM_KH_KEY = "item_kh_key";
-void kh_Key_Spawn(entity initial_owner, float _angle, float i)  // runs every time a new flag is created, ie after all the keys have been collected
-{
-       entity key = spawn();
-       key.count = i;
-       key.classname = STR_ITEM_KH_KEY;
-       settouch(key, kh_Key_Touch);
-       setthink(key, kh_Key_Think);
-       key.nextthink = time;
-       key.items = IT_KEY1 | IT_KEY2;
-       key.cnt = _angle;
-       key.angles = '0 360 0' * random();
-       key.event_damage = kh_Key_Damage;
-       key.takedamage = DAMAGE_YES;
-       key.damagedbytriggers = autocvar_g_balance_keyhunt_return_when_unreachable;
-       key.damagedbycontents = autocvar_g_balance_keyhunt_return_when_unreachable;
-       key.modelindex = kh_key_dropped;
-       key.model = "key";
-       key.kh_dropperteam = 0;
-       key.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
-       setsize(key, KH_KEY_MIN, KH_KEY_MAX);
-       key.colormod = Team_ColorRGB(initial_owner.team) * KH_KEY_BRIGHTNESS;
-       key.reset = key_reset;
-       navigation_dynamicgoal_init(key, false);
-
-       switch(initial_owner.team)
-       {
-               case NUM_TEAM_1:
-                       key.netname = "^1red key";
-                       break;
-               case NUM_TEAM_2:
-                       key.netname = "^4blue key";
-                       break;
-               case NUM_TEAM_3:
-                       key.netname = "^3yellow key";
-                       break;
-               case NUM_TEAM_4:
-                       key.netname = "^6pink key";
-                       break;
-               default:
-                       key.netname = "NETGIER key";
-                       break;
-       }
-
-       // link into key list
-       key.kh_worldkeynext = kh_worldkeylist;
-       kh_worldkeylist = key;
-
-       Send_Notification(NOTIF_ONE, initial_owner, MSG_CENTER, APP_TEAM_NUM(initial_owner.team, CENTER_KEYHUNT_START));
-
-       WaypointSprite_Spawn(WP_KeyDropped, 0, 0, key, '0 0 1' * KH_KEY_WP_ZSHIFT, NULL, key.team, key, waypointsprite_attachedforcarrier, false, RADARICON_FLAG);
-       key.waypointsprite_attachedforcarrier.waypointsprite_visible_for_player = kh_Key_waypointsprite_visible_for_player;
-
-       kh_Key_AssignTo(key, initial_owner);
-}
-
-// -1 when no team completely owns all keys yet
-int kh_Key_AllOwnedByWhichTeam()  // constantly called. check to see if all the keys are owned by the same team
-{
-       entity key;
-       int teem = -1;
-       int keys = NumTeams(kh_teams);
-       FOR_EACH_KH_KEY(key)
-       {
-               if(!key.owner)
-                       return -1;
-               if(teem == -1)
-                       teem = key.team;
-               else if(teem != key.team)
-                       return -1;
-               --keys;
-       }
-       if(keys != 0)
-               return -1;
-       return teem;
-}
-
-void kh_Key_DropOne(entity key)
-{
-       // prevent collecting this one for some time
-       entity player = key.owner;
-
-       key.kh_droptime = time;
-       key.enemy = player;
-
-       kh_Scores_Event(player, key, "dropkey", 0, 0);
-       GameRules_scoring_add(player, KH_LOSSES, 1);
-       int realteam = kh_Team_ByID(key.count);
-       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_DROP), player.netname);
-
-       kh_Key_AssignTo(key, NULL);
-       makevectors(player.v_angle);
-       key.velocity = W_CalculateProjectileVelocity(player, player.velocity, autocvar_g_balance_keyhunt_throwvelocity * v_forward, false);
-       key.pusher = NULL;
-       key.pushltime = time + autocvar_g_balance_keyhunt_protecttime;
-       key.kh_dropperteam = key.team;
-
-       sound(player, CH_TRIGGER, SND_KH_DROP, VOL_BASE, ATTEN_NORM);
-}
-
-void kh_Key_DropAll(entity player, float suicide) // runs whenever a player dies
-{
-       if(player.kh_next)
-       {
-               entity mypusher = NULL;
-               if(player.pusher)
-                       if(time < player.pushltime)
-                               mypusher = player.pusher;
-
-               entity key;
-               while((key = player.kh_next))
-               {
-                       kh_Scores_Event(player, key, "losekey", 0, 0);
-                       GameRules_scoring_add(player, KH_LOSSES, 1);
-                       int realteam = kh_Team_ByID(key.count);
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(realteam, INFO_KEYHUNT_LOST), player.netname);
-                       kh_Key_AssignTo(key, NULL);
-                       makevectors('-1 0 0' * (45 + 45 * random()) + '0 360 0' * random());
-                       key.velocity = W_CalculateProjectileVelocity(player, player.velocity, autocvar_g_balance_keyhunt_dropvelocity * v_forward, false);
-                       key.pusher = mypusher;
-                       key.pushltime = time + autocvar_g_balance_keyhunt_protecttime;
-                       if(suicide)
-                               key.kh_dropperteam = player.team;
-               }
-               sound(player, CH_TRIGGER, SND_KH_DROP, VOL_BASE, ATTEN_NORM);
-       }
-}
-
-int kh_GetMissingTeams()
-{
-       int missing_teams = 0;
-       for(int i = 0; i < NumTeams(kh_teams); ++i)
-       {
-               int teem = kh_Team_ByID(i);
-               int players = 0;
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
-                               ++players;
-               });
-               if (!players)
-                       missing_teams |= (2 ** i);
-       }
-       return missing_teams;
-}
-
-void kh_WaitForPlayers()  // delay start of the round until enough players are present
-{
-       static int prev_missing_teams_mask;
-       if(time < game_starttime)
-       {
-               if (prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
-               return;
-       }
-
-       int missing_teams_mask = kh_GetMissingTeams();
-       if(!missing_teams_mask)
-       {
-               if(prev_missing_teams_mask > 0)
-                       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-               prev_missing_teams_mask = -1;
-               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_ROUNDSTART, autocvar_g_balance_keyhunt_delay_round);
-               kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_round, kh_StartRound);
-       }
-       else
-       {
-               if(player_count == 0)
-               {
-                       if(prev_missing_teams_mask > 0)
-                               Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
-                       prev_missing_teams_mask = -1;
-               }
-               else
-               {
-                       if(prev_missing_teams_mask != missing_teams_mask)
-                       {
-                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
-                               prev_missing_teams_mask = missing_teams_mask;
-                       }
-               }
-               kh_Controller_SetThink(1, kh_WaitForPlayers);
-       }
-}
-
-void kh_EnableTrackingDevice()  // runs after each round
-{
-       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
-       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
-
-       kh_tracking_enabled = true;
-}
-
-void kh_StartRound()  // runs at the start of each round
-{
-       if(time < game_starttime)
-       {
-               kh_Controller_SetThink(game_starttime - time + 0.1, kh_WaitForPlayers);
-               return;
-       }
-
-       if(kh_GetMissingTeams())
-       {
-               kh_Controller_SetThink(1, kh_WaitForPlayers);
-               return;
-       }
-
-       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT);
-       Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_KEYHUNT_OTHER);
-
-       for(int i = 0; i < NumTeams(kh_teams); ++i)
-       {
-               int teem = kh_Team_ByID(i);
-               int players = 0;
-               entity my_player = NULL;
-               FOREACH_CLIENT(IS_PLAYER(it), {
-                       if(!IS_DEAD(it) && !PHYS_INPUT_BUTTON_CHAT(it) && it.team == teem)
-                       {
-                               ++players;
-                               if(random() * players <= 1)
-                                       my_player = it;
-                       }
-               });
-               kh_Key_Spawn(my_player, 360 * i / NumTeams(kh_teams), i);
-       }
-
-       kh_tracking_enabled = false;
-       Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_KEYHUNT_SCAN, autocvar_g_balance_keyhunt_delay_tracking);
-       kh_Controller_SetThink(autocvar_g_balance_keyhunt_delay_tracking, kh_EnableTrackingDevice);
-}
-
-float kh_HandleFrags(entity attacker, entity targ, float f)  // adds to the player score
-{
-       if(attacker == targ)
-               return f;
-
-       if(targ.kh_next)
-       {
-               if(attacker.team == targ.team)
-               {
-                       int nk = 0;
-                       for(entity k = targ.kh_next; k != NULL; k = k.kh_next)
-                               ++nk;
-                       kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", -nk * autocvar_g_balance_keyhunt_score_collect, 0);
-               }
-               else
-               {
-                       kh_Scores_Event(attacker, targ.kh_next, "carrierfrag", autocvar_g_balance_keyhunt_score_carrierfrag-1, 0);
-                       GameRules_scoring_add(attacker, KH_KCKILLS, 1);
-                       // the frag gets added later
-               }
-       }
-
-       return f;
-}
-
-void kh_Initialize()  // sets up th KH environment
-{
-       // setup variables
-       kh_teams = autocvar_g_keyhunt_teams_override;
-       if(kh_teams < 2)
-               kh_teams = cvar("g_keyhunt_teams"); // read the cvar directly as it gets written earlier in the same frame
-       kh_teams = BITS(bound(2, kh_teams, 4));
-
-       // make a KH entity for controlling the game
-       kh_controller = spawn();
-       setthink(kh_controller, kh_Controller_Think);
-       kh_Controller_SetThink(0, kh_WaitForPlayers);
-
-       setmodel(kh_controller, MDL_KH_KEY);
-       kh_key_dropped = kh_controller.modelindex;
-       /*
-       dprint(vtos(kh_controller.mins));
-       dprint(vtos(kh_controller.maxs));
-       dprint("\n");
-       */
-#ifdef KH_PLAYER_USE_CARRIEDMODEL
-       setmodel(kh_controller, MDL_KH_KEY_CARRIED);
-       kh_key_carried = kh_controller.modelindex;
-#else
-       kh_key_carried = kh_key_dropped;
-#endif
-
-       kh_controller.model = "";
-       kh_controller.modelindex = 0;
-
-       kh_ScoreRules(kh_teams);
-}
-
-void kh_finalize()
-{
-       // to be called before intermission
-       kh_FinishRound();
-       delete(kh_controller);
-       kh_controller = NULL;
-}
-
-// legacy bot role
-
-void(entity this) havocbot_role_kh_carrier;
-void(entity this) havocbot_role_kh_defense;
-void(entity this) havocbot_role_kh_offense;
-void(entity this) havocbot_role_kh_freelancer;
-
-
-void havocbot_goalrating_kh(entity this, float ratingscale_team, float ratingscale_dropped, float ratingscale_enemy)
-{
-       entity head;
-       for (head = kh_worldkeylist; head; head = head.kh_worldkeynext)
-       {
-               if(head.owner == this)
-                       continue;
-               if(!kh_tracking_enabled)
-               {
-                       // if it's carried by our team we know about it
-                       // otherwise we have to see it to know about it
-                       if(!head.owner || head.team != this.team)
-                       {
-                               traceline(this.origin + this.view_ofs, head.origin, MOVE_NOMONSTERS, this);
-                               if (trace_fraction < 1 && trace_ent != head)
-                                       continue; // skip what I can't see
-                       }
-               }
-               if(!head.owner)
-                       navigation_routerating(this, head, ratingscale_dropped * 10000, 100000);
-               else if(head.team == this.team)
-                       navigation_routerating(this, head.owner, ratingscale_team * 10000, 100000);
-               else
-                       navigation_routerating(this, head.owner, ratingscale_enemy * 10000, 100000);
-       }
-
-       havocbot_goalrating_items(this, 1, this.origin, 10000);
-}
-
-void havocbot_role_kh_carrier(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (!(this.kh_next))
-       {
-               LOG_TRACE("changing role to freelancer");
-               this.havocbot_role = havocbot_role_kh_freelancer;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               if(kh_Key_AllOwnedByWhichTeam() == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // bring home
-               else
-                       havocbot_goalrating_kh(this, 4, 4, 1); // play defensively
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_kh_defense(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (this.kh_next)
-       {
-               LOG_TRACE("changing role to carrier");
-               this.havocbot_role = havocbot_role_kh_carrier;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + random() * 10 + 20;
-       if (time > this.havocbot_role_timeout)
-       {
-               LOG_TRACE("changing role to freelancer");
-               this.havocbot_role = havocbot_role_kh_freelancer;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               float key_owner_team;
-               navigation_goalrating_start(this);
-
-               key_owner_team = kh_Key_AllOwnedByWhichTeam();
-               if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend key carriers
-               else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 4, 1, 0.1); // play defensively
-               else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_kh_offense(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (this.kh_next)
-       {
-               LOG_TRACE("changing role to carrier");
-               this.havocbot_role = havocbot_role_kh_carrier;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + random() * 10 + 20;
-       if (time > this.havocbot_role_timeout)
-       {
-               LOG_TRACE("changing role to freelancer");
-               this.havocbot_role = havocbot_role_kh_freelancer;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               float key_owner_team;
-
-               navigation_goalrating_start(this);
-
-               key_owner_team = kh_Key_AllOwnedByWhichTeam();
-               if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
-               else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 0.1, 1, 4); // play offensively
-               else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK! EMERGENCY!
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void havocbot_role_kh_freelancer(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (this.kh_next)
-       {
-               LOG_TRACE("changing role to carrier");
-               this.havocbot_role = havocbot_role_kh_carrier;
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (!this.havocbot_role_timeout)
-               this.havocbot_role_timeout = time + random() * 10 + 10;
-       if (time > this.havocbot_role_timeout)
-       {
-               if (random() < 0.5)
-               {
-                       LOG_TRACE("changing role to offense");
-                       this.havocbot_role = havocbot_role_kh_offense;
-               }
-               else
-               {
-                       LOG_TRACE("changing role to defense");
-                       this.havocbot_role = havocbot_role_kh_defense;
-               }
-               this.havocbot_role_timeout = 0;
-               return;
-       }
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               int key_owner_team = kh_Key_AllOwnedByWhichTeam();
-               if(key_owner_team == this.team)
-                       havocbot_goalrating_kh(this, 10, 0.1, 0.1); // defend anyway
-               else if(key_owner_team == -1)
-                       havocbot_goalrating_kh(this, 1, 10, 4); // prefer dropped keys
-               else
-                       havocbot_goalrating_kh(this, 0.1, 0.1, 10); // ATTACK ANYWAY
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-
-// register this as a mutator
-
-MUTATOR_HOOKFUNCTION(kh, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       kh_Key_DropAll(player, true);
-}
-
-MUTATOR_HOOKFUNCTION(kh, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       kh_Key_DropAll(player, true);
-}
-
-MUTATOR_HOOKFUNCTION(kh, PlayerDies)
-{
-       entity frag_attacker = M_ARGV(1, entity);
-       entity frag_target = M_ARGV(2, entity);
-
-       if(frag_target == frag_attacker)
-               kh_Key_DropAll(frag_target, true);
-       else if(IS_PLAYER(frag_attacker))
-               kh_Key_DropAll(frag_target, false);
-       else
-               kh_Key_DropAll(frag_target, true);
-}
-
-MUTATOR_HOOKFUNCTION(kh, GiveFragsForKill, CBC_ORDER_FIRST)
-{
-       entity frag_attacker = M_ARGV(0, entity);
-       entity frag_target = M_ARGV(1, entity);
-       float frag_score = M_ARGV(2, float);
-       M_ARGV(2, float) = kh_HandleFrags(frag_attacker, frag_target, frag_score);
-}
-
-MUTATOR_HOOKFUNCTION(kh, MatchEnd)
-{
-       kh_finalize();
-}
-
-MUTATOR_HOOKFUNCTION(kh, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(0, float) = kh_teams;
-}
-
-MUTATOR_HOOKFUNCTION(kh, SpectateCopy)
-{
-       entity spectatee = M_ARGV(0, entity);
-       entity client = M_ARGV(1, entity);
-
-       STAT(KH_KEYS, client) = STAT(KH_KEYS, spectatee);
-}
-
-MUTATOR_HOOKFUNCTION(kh, PlayerUseKey)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(MUTATOR_RETURNVALUE == 0)
-       {
-               entity k = player.kh_next;
-               if(k)
-               {
-                       kh_Key_DropOne(k);
-                       return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(kh, HavocBot_ChooseRole)
-{
-    entity bot = M_ARGV(0, entity);
-
-       if(IS_DEAD(bot))
-               return true;
-
-       float r = random() * 3;
-       if (r < 1)
-               bot.havocbot_role = havocbot_role_kh_offense;
-       else if (r < 2)
-               bot.havocbot_role = havocbot_role_kh_defense;
-       else
-               bot.havocbot_role = havocbot_role_kh_freelancer;
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(kh, DropSpecialItems)
-{
-       entity frag_target = M_ARGV(0, entity);
-
-       kh_Key_DropAll(frag_target, false);
-}
-
-MUTATOR_HOOKFUNCTION(kh, reset_map_global)
-{
-       kh_WaitForPlayers(); // takes care of killing the "missing teams" message
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_keyhunt.qh b/qcsrc/server/mutators/mutator/gamemode_keyhunt.qh
deleted file mode 100644 (file)
index 77d7c06..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-#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_STATIC();
-       MUTATOR_ONADD
-       {
-               GameRules_teams(true);
-        GameRules_spawning_teams(autocvar_g_keyhunt_team_spawns);
-        GameRules_limit_score(autocvar_g_keyhunt_point_limit);
-        GameRules_limit_lead(autocvar_g_keyhunt_point_leadlimit);
-
-               kh_Initialize();
-       }
-       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:
-bool kh_tracking_enabled;
-.entity kh_next;
-
-USING(kh_Think_t, void());
-void kh_StartRound();
-void kh_Controller_SetThink(float t, kh_Think_t func);
diff --git a/qcsrc/server/mutators/mutator/gamemode_lms.qc b/qcsrc/server/mutators/mutator/gamemode_lms.qc
deleted file mode 100644 (file)
index 94c4a99..0000000
+++ /dev/null
@@ -1,429 +0,0 @@
-#include "gamemode_lms.qh"
-
-#include <common/mutators/mutator/instagib/items.qh>
-#include <server/campaign.qh>
-#include <server/command/_mod.qh>
-
-int autocvar_g_lms_extra_lives;
-bool autocvar_g_lms_join_anytime;
-int autocvar_g_lms_last_join;
-bool autocvar_g_lms_regenerate;
-
-// main functions
-float LMS_NewPlayerLives()
-{
-       float fl;
-       fl = autocvar_fraglimit;
-       if(fl == 0)
-               fl = 999;
-
-       // first player has left the game for dying too much? Nobody else can get in.
-       if(lms_lowest_lives < 1)
-               return 0;
-
-       if(!autocvar_g_lms_join_anytime)
-               if(lms_lowest_lives < fl - autocvar_g_lms_last_join)
-                       return 0;
-
-       return bound(1, lms_lowest_lives, fl);
-}
-
-void ClearWinners();
-
-// LMS winning condition: game terminates if and only if there's at most one
-// one player who's living lives. Top two scores being equal cancels the time
-// limit.
-int WinningCondition_LMS()
-{
-       entity first_player = NULL;
-       int total_players = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               if (!total_players)
-                       first_player = it;
-               ++total_players;
-       });
-
-       if (total_players)
-       {
-               if (total_players > 1)
-               {
-                       // two or more active players - continue with the game
-
-                       if (autocvar_g_campaign)
-                       {
-                               FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-                                       float pl_lives = GameRules_scoring_add(it, LMS_LIVES, 0);
-                                       if (!pl_lives)
-                                               return WINNING_YES; // human player lost, game over
-                                       break;
-                               });
-                       }
-               }
-               else
-               {
-                       // exactly one player?
-
-                       ClearWinners();
-                       SetWinners(winning, 0); // NOTE: exactly one player is still "player", so this works out
-
-                       if (LMS_NewPlayerLives())
-                       {
-                               // game still running (that is, nobody got removed from the game by a frag yet)? then continue
-                               return WINNING_NO;
-                       }
-                       else
-                       {
-                               // a winner!
-                               // and assign him his first place
-                               GameRules_scoring_add(first_player, LMS_RANK, 1);
-                               if(warmup_stage)
-                                       return WINNING_NO;
-                               else
-                                       return WINNING_YES;
-                       }
-               }
-       }
-       else
-       {
-               // nobody is playing at all...
-               if (LMS_NewPlayerLives())
-               {
-                       // wait for players...
-               }
-               else
-               {
-                       // SNAFU (maybe a draw game?)
-                       ClearWinners();
-                       LOG_TRACE("No players, ending game.");
-                       return WINNING_YES;
-               }
-       }
-
-       // When we get here, we have at least two players who are actually LIVING,
-       // now check if the top two players have equal score.
-       WinningConditionHelper(NULL);
-
-       ClearWinners();
-       if(WinningConditionHelper_winner)
-               WinningConditionHelper_winner.winning = true;
-       if(WinningConditionHelper_topscore == WinningConditionHelper_secondscore)
-               return WINNING_NEVER;
-
-       // Top two have different scores? Way to go for our beloved TIMELIMIT!
-       return WINNING_NO;
-}
-
-// mutator hooks
-MUTATOR_HOOKFUNCTION(lms, reset_map_global)
-{
-       lms_lowest_lives = 999;
-}
-
-MUTATOR_HOOKFUNCTION(lms, reset_map_players)
-{
-       FOREACH_CLIENT(true, {
-               TRANSMUTE(Player, it);
-               it.frags = FRAGS_PLAYER;
-               GameRules_scoring_add(it, LMS_LIVES, LMS_NewPlayerLives());
-               PutClientInServer(it);
-       });
-}
-
-MUTATOR_HOOKFUNCTION(lms, PutClientInServer)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.frags == FRAGS_SPECTATOR)
-               TRANSMUTE(Observer, player);
-       else
-       {
-               float tl = GameRules_scoring_add(player, LMS_LIVES, 0);
-               if(tl < lms_lowest_lives)
-                       lms_lowest_lives = tl;
-               if(tl <= 0)
-                       TRANSMUTE(Observer, player);
-               if(warmup_stage)
-                       GameRules_scoring_add(player, LMS_RANK, -GameRules_scoring_add(player, LMS_RANK, 0));
-       }
-}
-
-MUTATOR_HOOKFUNCTION(lms, ForbidSpawn)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(warmup_stage)
-               return false;
-       if(player.frags == FRAGS_SPECTATOR)
-               return true;
-       if(GameRules_scoring_add(player, LMS_LIVES, 0) <= 0)
-       {
-               Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_LMS_NOLIVES);
-               return true;
-       }
-       return false;
-}
-
-MUTATOR_HOOKFUNCTION(lms, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       frag_target.respawn_flags |= RESPAWN_FORCE;
-}
-
-void lms_RemovePlayer(entity player)
-{
-       static int quitters = 0;
-       float player_rank = GameRules_scoring_add(player, LMS_RANK, 0);
-       if (!player_rank)
-       {
-               int pl_cnt = 0;
-               FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
-               if (player.lms_spectate_warning != 2)
-               {
-                       if(IS_BOT_CLIENT(player))
-                               bot_clear(player);
-                       player.frags = FRAGS_LMS_LOSER;
-                       GameRules_scoring_add(player, LMS_RANK, pl_cnt + 1);
-               }
-               else
-               {
-                       lms_lowest_lives = 999;
-                       FOREACH_CLIENT(true, {
-                               if (it.frags == FRAGS_LMS_LOSER)
-                               {
-                                       float it_rank = GameRules_scoring_add(it, LMS_RANK, 0);
-                                       if (it_rank > player_rank && it_rank <= 256)
-                                               GameRules_scoring_add(it, LMS_RANK, -1);
-                                       lms_lowest_lives = 0;
-                               }
-                               else if (it.frags != FRAGS_SPECTATOR)
-                               {
-                                       float tl = GameRules_scoring_add(it, LMS_LIVES, 0);
-                                       if(tl < lms_lowest_lives)
-                                               lms_lowest_lives = tl;
-                               }
-                       });
-                       GameRules_scoring_add(player, LMS_RANK, 665 - quitters); // different from 666
-                       if(!warmup_stage)
-                       {
-                               GameRules_scoring_add(player, LMS_LIVES, -GameRules_scoring_add(player, LMS_LIVES, 0));
-                               ++quitters;
-                       }
-                       player.frags = FRAGS_LMS_LOSER;
-                       TRANSMUTE(Observer, player);
-               }
-               if (pl_cnt == 2 && !warmup_stage) // a player is forfeiting leaving only one player
-                       lms_lowest_lives = 0; // end the game now!
-       }
-
-       if(CS(player).killcount != FRAGS_SPECTATOR)
-               if(GameRules_scoring_add(player, LMS_RANK, 0) > 0 && player.lms_spectate_warning != 2)
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_NOLIVES, player.netname);
-               else
-                       Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_LMS_FORFEIT, player.netname);
-}
-
-MUTATOR_HOOKFUNCTION(lms, ClientDisconnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       lms_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(lms, MakePlayerObserver)
-{
-    entity player = M_ARGV(0, entity);
-
-       lms_RemovePlayer(player);
-       return true;  // prevent team reset
-}
-
-MUTATOR_HOOKFUNCTION(lms, ClientConnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       TRANSMUTE(Player, player);
-       campaign_bots_may_start = true;
-
-       if(GameRules_scoring_add(player, LMS_LIVES, LMS_NewPlayerLives()) <= 0)
-       {
-               GameRules_scoring_add(player, LMS_RANK, 666); // mark as forced spectator for the hud code
-               player.frags = FRAGS_SPECTATOR;
-       }
-}
-
-MUTATOR_HOOKFUNCTION(lms, PlayerPreThink)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.deadflag == DEAD_DYING)
-               player.deadflag = DEAD_RESPAWNING;
-}
-
-MUTATOR_HOOKFUNCTION(lms, PlayerRegen)
-{
-       if(autocvar_g_lms_regenerate)
-               return false;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, ForbidThrowCurrentWeapon)
-{
-       // forbode!
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, GiveFragsForKill)
-{
-       entity frag_target = M_ARGV(1, entity);
-
-       if (!warmup_stage)
-       {
-               // remove a life
-               int tl = GameRules_scoring_add(frag_target, LMS_LIVES, -1);
-               if(tl < lms_lowest_lives)
-                       lms_lowest_lives = tl;
-               if(tl <= 0)
-               {
-                       int pl_cnt = 0;
-                       FOREACH_CLIENT(IS_PLAYER(it), { pl_cnt++; });
-                       if(IS_BOT_CLIENT(frag_target))
-                               bot_clear(frag_target);
-                       frag_target.frags = FRAGS_LMS_LOSER;
-                       GameRules_scoring_add(frag_target, LMS_RANK, pl_cnt);
-               }
-       }
-       M_ARGV(2, float) = 0; // frag score
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, SetStartItems)
-{
-       start_items &= ~IT_UNLIMITED_AMMO;
-       start_health       = warmup_start_health       = cvar("g_lms_start_health");
-       start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
-       start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
-       start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
-       start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
-       start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
-       start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
-       start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
-}
-
-MUTATOR_HOOKFUNCTION(lms, ForbidPlayerScore_Clear)
-{
-       // don't clear player score
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, FilterItem)
-{
-       entity item = M_ARGV(0, entity);
-
-       if(autocvar_g_lms_extra_lives)
-       if(item.itemdef == ITEM_ExtraLife)
-               return false;
-
-       return true;
-}
-
-void lms_extralife(entity this)
-{
-       StartItem(this, ITEM_ExtraLife);
-}
-
-MUTATOR_HOOKFUNCTION(lms, OnEntityPreSpawn)
-{
-       if (!autocvar_g_powerups) return false;
-       if (!autocvar_g_lms_extra_lives) return false;
-
-       entity ent = M_ARGV(0, entity);
-
-       // Can't use .itemdef here
-       if (ent.classname != "item_health_mega") return false;
-
-       entity e = spawn();
-       setthink(e, lms_extralife);
-
-       e.nextthink = time + 0.1;
-       e.spawnflags = ent.spawnflags;
-       e.noalign = ent.noalign;
-       setorigin(e, ent.origin);
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, ItemTouch)
-{
-       entity item = M_ARGV(0, entity);
-       entity toucher = M_ARGV(1, entity);
-
-       if(item.itemdef == ITEM_ExtraLife)
-       {
-               Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_EXTRALIVES);
-               GameRules_scoring_add(toucher, LMS_LIVES, autocvar_g_lms_extra_lives);
-               return MUT_ITEMTOUCH_PICKUP;
-       }
-
-       return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(lms, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
-{
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               ++M_ARGV(0, int); // activerealplayers
-               ++M_ARGV(1, int); // realplayers
-       });
-
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, ClientCommand_Spectate)
-{
-    entity player = M_ARGV(0, entity);
-
-       if(warmup_stage || player.lms_spectate_warning)
-       {
-               // for the forfeit message...
-               player.lms_spectate_warning = 2;
-       }
-       else
-       {
-               if(player.frags != FRAGS_SPECTATOR && player.frags != FRAGS_LMS_LOSER)
-               {
-                       player.lms_spectate_warning = 1;
-                       sprint(player, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");
-               }
-               return MUT_SPECCMD_RETURN;
-       }
-       return MUT_SPECCMD_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(lms, CheckRules_World)
-{
-       M_ARGV(0, float) = WinningCondition_LMS();
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, WantWeapon)
-{
-       M_ARGV(2, bool) = true; // all weapons
-}
-
-MUTATOR_HOOKFUNCTION(lms, GetPlayerStatus)
-{
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(lms, AddPlayerScore)
-{
-       if(game_stopped)
-       if(M_ARGV(0, entity) == SP_LMS_RANK) // score field
-               return true; // allow writing to this field in intermission as it is needed for newly joining players
-}
-
-void lms_Initialize()
-{
-       lms_lowest_lives = 9999;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_lms.qh b/qcsrc/server/mutators/mutator/gamemode_lms.qh
deleted file mode 100644 (file)
index c69113a..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-.float lms_spectate_warning;
-#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
-void lms_Initialize();
-
-REGISTER_MUTATOR(lms, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-        GameRules_limit_score(((!autocvar_g_lms_lives_override) ? -1 : autocvar_g_lms_lives_override));
-        GameRules_limit_lead(0);
-        GameRules_score_enabled(false);
-        GameRules_scoring(0, 0, 0, {
-            field(SP_LMS_LIVES, "lives", SFL_SORT_PRIO_SECONDARY);
-            field(SP_LMS_RANK, "rank", SFL_LOWER_IS_BETTER | SFL_RANK | SFL_SORT_PRIO_PRIMARY | SFL_ALLOW_HIDE);
-        });
-
-               lms_Initialize();
-       }
-       return 0;
-}
-
-// lives related defs
-float lms_lowest_lives;
-float LMS_NewPlayerLives();
diff --git a/qcsrc/server/mutators/mutator/gamemode_race.qc b/qcsrc/server/mutators/mutator/gamemode_race.qc
deleted file mode 100644 (file)
index aa6d12a..0000000
+++ /dev/null
@@ -1,488 +0,0 @@
-#include "gamemode_race.qh"
-
-#include <server/race.qh>
-
-#define autocvar_g_race_laps_limit cvar("g_race_laps_limit")
-float autocvar_g_race_qualifying_timelimit;
-float autocvar_g_race_qualifying_timelimit_override;
-int autocvar_g_race_teams;
-
-// legacy bot roles
-.float race_checkpoint;
-void havocbot_role_race(entity this)
-{
-       if(IS_DEAD(this))
-               return;
-
-       if (navigation_goalrating_timeout(this))
-       {
-               navigation_goalrating_start(this);
-
-               bool raw_touch_check = true;
-               int cp = this.race_checkpoint;
-
-               LABEL(search_racecheckpoints)
-               IL_EACH(g_racecheckpoints, true,
-               {
-                       if(it.cnt == cp || cp == -1)
-                       {
-                               // redirect bot to next goal if it touched the waypoint of an untouchable checkpoint
-                               // e.g. checkpoint in front of Stormkeep's warpzone
-                               // the same workaround is applied in CTS game mode
-                               if (raw_touch_check && vdist(this.origin - it.nearestwaypoint.origin, <, 30))
-                               {
-                                       cp = race_NextCheckpoint(cp);
-                                       raw_touch_check = false;
-                                       goto search_racecheckpoints;
-                               }
-                               navigation_routerating(this, it, 1000000, 5000);
-                       }
-               });
-
-               navigation_goalrating_end(this);
-
-               navigation_goalrating_timeout_set(this);
-       }
-}
-
-void race_ScoreRules()
-{
-    GameRules_score_enabled(false);
-       GameRules_scoring(race_teams, 0, 0, {
-        if (race_teams) {
-            field_team(ST_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
-            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
-            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
-        } else if (g_race_qualifying) {
-            field(SP_RACE_FASTEST, "fastest", SFL_SORT_PRIO_PRIMARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-        } else {
-            field(SP_RACE_LAPS, "laps", SFL_SORT_PRIO_PRIMARY);
-            field(SP_RACE_TIME, "time", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER | SFL_TIME);
-            field(SP_RACE_FASTEST, "fastest", SFL_LOWER_IS_BETTER | SFL_TIME);
-        }
-       });
-}
-
-void race_EventLog(string mode, entity actor) // use an alias for easy changing and quick editing later
-{
-       if(autocvar_sv_eventlog)
-               GameLogEcho(strcat(":race:", mode, ":", ((actor != NULL) ? (strcat(":", ftos(actor.playerid))) : "")));
-}
-
-float WinningCondition_Race(float fraglimit)
-{
-       float wc;
-       float n, c;
-
-       n = 0;
-       c = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               ++n;
-               if(CS(it).race_completed)
-                       ++c;
-       });
-       if(n && (n == c))
-               return WINNING_YES;
-       wc = WinningCondition_Scores(fraglimit, 0);
-
-       // ALWAYS initiate overtime, unless EVERYONE has finished the race!
-       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
-       // do NOT support equality when the laps are all raced!
-               return WINNING_STARTSUDDENDEATHOVERTIME;
-       else
-               return WINNING_NEVER;
-}
-
-float WinningCondition_QualifyingThenRace(float limit)
-{
-       float wc;
-       wc = WinningCondition_Scores(limit, 0);
-
-       // NEVER initiate overtime
-       if(wc == WINNING_YES || wc == WINNING_STARTSUDDENDEATHOVERTIME)
-       {
-               return WINNING_YES;
-       }
-
-       return wc;
-}
-
-MUTATOR_HOOKFUNCTION(rc, ClientKill)
-{
-       if(g_race_qualifying)
-               M_ARGV(1, float) = 0; // killtime
-}
-
-MUTATOR_HOOKFUNCTION(rc, AbortSpeedrun)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(autocvar_g_allow_checkpoints)
-               race_PreparePlayer(player); // nice try
-}
-
-MUTATOR_HOOKFUNCTION(rc, PlayerPhysics)
-{
-       entity player = M_ARGV(0, entity);
-       float dt = M_ARGV(1, float);
-
-       player.race_movetime_frac += dt;
-       float f = floor(player.race_movetime_frac);
-       player.race_movetime_frac -= f;
-       player.race_movetime_count += f;
-       player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
-
-#ifdef SVQC
-       if(IS_PLAYER(player))
-       {
-               if (player.race_penalty)
-                       if (time > player.race_penalty)
-                               player.race_penalty = 0;
-               if(player.race_penalty)
-               {
-                       player.velocity = '0 0 0';
-                       set_movetype(player, MOVETYPE_NONE);
-                       player.disableclientprediction = 2;
-               }
-       }
-#endif
-
-       // force kbd movement for fairness
-       float wishspeed;
-       vector wishvel;
-
-       // if record times matter
-       // ensure nothing EVIL is being done (i.e. div0_evade)
-       // this hinders joystick users though
-       // but it still gives SOME analog control
-       wishvel.x = fabs(CS(player).movement.x);
-       wishvel.y = fabs(CS(player).movement.y);
-       if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
-       {
-               wishvel.z = 0;
-               wishspeed = vlen(wishvel);
-               if(wishvel.x >= 2 * wishvel.y)
-               {
-                       // pure X motion
-                       if(CS(player).movement.x > 0)
-                               CS(player).movement_x = wishspeed;
-                       else
-                               CS(player).movement_x = -wishspeed;
-                       CS(player).movement_y = 0;
-               }
-               else if(wishvel.y >= 2 * wishvel.x)
-               {
-                       // pure Y motion
-                       CS(player).movement_x = 0;
-                       if(CS(player).movement.y > 0)
-                               CS(player).movement_y = wishspeed;
-                       else
-                               CS(player).movement_y = -wishspeed;
-               }
-               else
-               {
-                       // diagonal
-                       if(CS(player).movement.x > 0)
-                               CS(player).movement_x = M_SQRT1_2 * wishspeed;
-                       else
-                               CS(player).movement_x = -M_SQRT1_2 * wishspeed;
-                       if(CS(player).movement.y > 0)
-                               CS(player).movement_y = M_SQRT1_2 * wishspeed;
-                       else
-                               CS(player).movement_y = -M_SQRT1_2 * wishspeed;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, reset_map_global)
-{
-       float s;
-
-       Score_NicePrint(NULL);
-
-       race_ClearRecords();
-       PlayerScore_Sort(race_place, 0, 1, 0);
-
-       FOREACH_CLIENT(true, {
-               if(it.race_place)
-               {
-                       s = GameRules_scoring_add(it, RACE_FASTEST, 0);
-                       if(!s)
-                               it.race_place = 0;
-               }
-               race_EventLog(ftos(it.race_place), it);
-       });
-
-       if(g_race_qualifying == 2)
-       {
-               g_race_qualifying = 0;
-               independent_players = 0;
-               cvar_set("fraglimit", ftos(race_fraglimit));
-               cvar_set("leadlimit", ftos(race_leadlimit));
-               cvar_set("timelimit", ftos(race_timelimit));
-               race_ScoreRules();
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, ClientConnect)
-{
-       entity player = M_ARGV(0, entity);
-
-       race_PreparePlayer(player);
-       player.race_checkpoint = -1;
-
-       string rr = RACE_RECORD;
-
-       if(IS_REAL_CLIENT(player))
-       {
-               msg_entity = player;
-               race_send_recordtime(MSG_ONE);
-               race_send_speedaward(MSG_ONE);
-
-               speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
-               speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
-               race_send_speedaward_alltimebest(MSG_ONE);
-
-               float i;
-               for (i = 1; i <= RANKINGS_CNT; ++i)
-               {
-                       race_SendRankings(i, 0, 0, MSG_ONE);
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, MakePlayerObserver)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(g_race_qualifying)
-       if(GameRules_scoring_add(player, RACE_FASTEST, 0))
-               player.frags = FRAGS_LMS_LOSER;
-       else
-               player.frags = FRAGS_SPECTATOR;
-
-       race_PreparePlayer(player);
-       player.race_checkpoint = -1;
-}
-
-MUTATOR_HOOKFUNCTION(rc, PlayerSpawn)
-{
-       entity player = M_ARGV(0, entity);
-       entity spawn_spot = M_ARGV(1, entity);
-
-       if(spawn_spot.target == "")
-               // Emergency: this wasn't a real spawnpoint. Can this ever happen?
-               race_PreparePlayer(player);
-
-       // if we need to respawn, do it right
-       player.race_respawn_checkpoint = player.race_checkpoint;
-       player.race_respawn_spotref = spawn_spot;
-
-       player.race_place = 0;
-}
-
-MUTATOR_HOOKFUNCTION(rc, PutClientInServer)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(IS_PLAYER(player))
-       if(!game_stopped)
-       {
-               if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
-                       race_PreparePlayer(player);
-               else // respawn
-                       race_RetractPlayer(player);
-
-               race_AbandonRaceCheck(player);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, PlayerDies)
-{
-       entity frag_target = M_ARGV(2, entity);
-
-       frag_target.respawn_flags |= RESPAWN_FORCE;
-       race_AbandonRaceCheck(frag_target);
-}
-
-MUTATOR_HOOKFUNCTION(rc, HavocBot_ChooseRole)
-{
-       entity bot = M_ARGV(0, entity);
-
-       bot.havocbot_role = havocbot_role_race;
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(rc, GetPressedKeys)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
-       {
-               if (!player.stored_netname)
-                       player.stored_netname = strzone(uid2name(player.crypto_idfp));
-               if(player.stored_netname != player.netname)
-               {
-                       db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
-                       strunzone(player.stored_netname);
-                       player.stored_netname = strzone(player.netname);
-               }
-       }
-
-       if (!IS_OBSERVER(player))
-       {
-               if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
-               {
-                       speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
-                       speedaward_holder = player.netname;
-                       speedaward_uid = player.crypto_idfp;
-                       speedaward_lastupdate = time;
-               }
-               if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
-               {
-                       string rr = RACE_RECORD;
-                       race_send_speedaward(MSG_ALL);
-                       speedaward_lastsent = speedaward_speed;
-                       if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
-                       {
-                               speedaward_alltimebest = speedaward_speed;
-                               speedaward_alltimebest_holder = speedaward_holder;
-                               speedaward_alltimebest_uid = speedaward_uid;
-                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
-                               db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
-                               race_send_speedaward_alltimebest(MSG_ALL);
-                       }
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, ForbidPlayerScore_Clear)
-{
-       if(g_race_qualifying)
-               return true; // in qualifying, you don't lose score by observing
-}
-
-MUTATOR_HOOKFUNCTION(rc, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(0, float) = race_teams;
-}
-
-MUTATOR_HOOKFUNCTION(rc, Scores_CountFragsRemaining)
-{
-       // announce remaining frags if not in qualifying mode
-       if(!g_race_qualifying)
-               return true;
-}
-
-MUTATOR_HOOKFUNCTION(rc, GetRecords)
-{
-       int record_page = M_ARGV(0, int);
-       string ret_string = M_ARGV(1, string);
-
-       for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
-       {
-               if(MapInfo_Get_ByID(i))
-               {
-                       float r = race_readTime(MapInfo_Map_bspname, 1);
-
-                       if(!r)
-                               continue;
-
-                       string h = race_readName(MapInfo_Map_bspname, 1);
-                       ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
-               }
-       }
-
-       M_ARGV(1, string) = ret_string;
-}
-
-MUTATOR_HOOKFUNCTION(rc, HideTeamNagger)
-{
-       return true; // doesn't work so well
-}
-
-MUTATOR_HOOKFUNCTION(rc, FixClientCvars)
-{
-       entity player = M_ARGV(0, entity);
-
-       stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
-}
-
-MUTATOR_HOOKFUNCTION(rc, CheckRules_World)
-{
-       float checkrules_timelimit = M_ARGV(1, float);
-       float checkrules_fraglimit = M_ARGV(2, float);
-
-       if(checkrules_timelimit >= 0)
-       {
-               if(!g_race_qualifying)
-               {
-                       M_ARGV(0, float) = WinningCondition_Race(checkrules_fraglimit);
-                       return true;
-               }
-               else if(g_race_qualifying == 2)
-               {
-                       M_ARGV(0, float) = WinningCondition_QualifyingThenRace(checkrules_fraglimit);
-                       return true;
-               }
-       }
-}
-
-MUTATOR_HOOKFUNCTION(rc, ReadLevelCvars)
-{
-       if(g_race_qualifying == 2)
-               warmup_stage = 0;
-}
-
-void race_Initialize()
-{
-       race_ScoreRules();
-       if(g_race_qualifying == 2)
-               warmup_stage = 0;
-}
-
-void rc_SetLimits()
-{
-       int fraglimit_override, leadlimit_override;
-       float timelimit_override, qualifying_override;
-
-       if(autocvar_g_race_teams)
-       {
-               GameRules_teams(true);
-               race_teams = BITS(bound(2, autocvar_g_race_teams, 4));
-       }
-       else
-               race_teams = 0;
-
-       qualifying_override = autocvar_g_race_qualifying_timelimit_override;
-       fraglimit_override = autocvar_g_race_laps_limit;
-       leadlimit_override = 0; // currently not supported by race
-       timelimit_override = autocvar_timelimit_override;
-
-       float want_qualifying = ((qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit) > 0;
-
-       if(autocvar_g_campaign)
-       {
-               g_race_qualifying = 1;
-               independent_players = 1;
-       }
-       else if(want_qualifying)
-       {
-               g_race_qualifying = 2;
-               independent_players = 1;
-               race_fraglimit = (fraglimit_override >= 0) ? fraglimit_override : autocvar_fraglimit;
-               race_leadlimit = (leadlimit_override >= 0) ? leadlimit_override : autocvar_leadlimit;
-               race_timelimit = (timelimit_override >= 0) ? timelimit_override : autocvar_timelimit;
-               qualifying_override = (qualifying_override >= 0) ? qualifying_override : autocvar_g_race_qualifying_timelimit;
-               fraglimit_override = 0;
-               leadlimit_override = 0;
-               timelimit_override = qualifying_override;
-       }
-       else
-               g_race_qualifying = 0;
-    GameRules_limit_score(fraglimit_override);
-    GameRules_limit_lead(leadlimit_override);
-    GameRules_limit_time(timelimit_override);
-    GameRules_limit_time_qualifying(qualifying_override);
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_race.qh b/qcsrc/server/mutators/mutator/gamemode_race.qh
deleted file mode 100644 (file)
index 1e475e3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#pragma once
-
-#include "../gamemode.qh"
-
-void rc_SetLimits();
-void race_Initialize();
-
-REGISTER_MUTATOR(rc, false)
-{
-    MUTATOR_STATIC();
-       MUTATOR_ONADD
-       {
-               rc_SetLimits();
-
-               race_Initialize();
-       }
-       return 0;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_tdm.qc b/qcsrc/server/mutators/mutator/gamemode_tdm.qc
deleted file mode 100644 (file)
index aad3193..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-#include "gamemode_tdm.qh"
-
-int autocvar_g_tdm_teams;
-int autocvar_g_tdm_teams_override;
-
-/*QUAKED spawnfunc_tdm_team (0 .5 .8) (-16 -16 -24) (16 16 32)
-Team declaration for TDM gameplay, this allows you to decide what team names and control point models are used in your map.
-Note: If you use spawnfunc_tdm_team entities you must define at least 2!  However, unlike domination, you don't need to make a blank one too.
-Keys:
-"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
-"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
-spawnfunc(tdm_team)
-{
-       if(!g_tdm || !this.cnt) { delete(this); return; }
-
-       this.classname = "tdm_team";
-       this.team = this.cnt + 1;
-}
-
-// code from here on is just to support maps that don't have team entities
-void tdm_SpawnTeam (string teamname, int teamcolor)
-{
-       entity this = new_pure(tdm_team);
-       this.netname = teamname;
-       this.cnt = teamcolor - 1;
-       this.team = teamcolor;
-       this.spawnfunc_checked = true;
-       //spawnfunc_tdm_team(this);
-}
-
-void tdm_DelayedInit(entity this)
-{
-       // if no teams are found, spawn defaults
-       if(find(NULL, classname, "tdm_team") == NULL)
-       {
-               LOG_TRACE("No \"tdm_team\" entities found on this map, creating them anyway.");
-
-               int numteams = autocvar_g_tdm_teams_override;
-               if(numteams < 2) { numteams = autocvar_g_tdm_teams; }
-
-               int teams = BITS(bound(2, numteams, 4));
-               if(teams & BIT(0))
-                       tdm_SpawnTeam("Red", NUM_TEAM_1);
-               if(teams & BIT(1))
-                       tdm_SpawnTeam("Blue", NUM_TEAM_2);
-               if(teams & BIT(2))
-                       tdm_SpawnTeam("Yellow", NUM_TEAM_3);
-               if(teams & BIT(3))
-                       tdm_SpawnTeam("Pink", NUM_TEAM_4);
-       }
-}
-
-MUTATOR_HOOKFUNCTION(tdm, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
-       M_ARGV(1, string) = "tdm_team";
-       return true;
-}
-
-MUTATOR_HOOKFUNCTION(tdm, Scores_CountFragsRemaining)
-{
-       // announce remaining frags
-       return true;
-}
diff --git a/qcsrc/server/mutators/mutator/gamemode_tdm.qh b/qcsrc/server/mutators/mutator/gamemode_tdm.qh
deleted file mode 100644 (file)
index c163962..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-#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_STATIC();
-       MUTATOR_ONADD
-       {
-               GameRules_teams(true);
-        GameRules_spawning_teams(autocvar_g_tdm_team_spawns);
-               GameRules_limit_score(autocvar_g_tdm_point_limit);
-        GameRules_limit_lead(autocvar_g_tdm_point_leadlimit);
-
-               InitializeEntity(NULL, tdm_DelayedInit, INITPRIO_GAMETYPE);
-       }
-       return 0;
-}
index b84ae6414e20ba637d8f81c86bf946040bf37cb5..13dbda5200b7fbbb48a7329a8d4b1407a4922892 100644 (file)
@@ -8,9 +8,7 @@ MODEL(SQUARE_BAD,   "models/pathlib/badsquare.md3");
 MODEL(EDGE,         "models/pathlib/edge.md3");
 
 #ifdef TURRET_DEBUG
-void mark_error(vector where,float lifetime);
-void mark_info(vector where,float lifetime);
-entity mark_misc(vector where,float lifetime);
+#include <common/turrets/util.qh>
 #endif
 
 void pathlib_showpath(entity start)
index 811c031aff3d968a056e6dffa974179a409ce321..6f1bd989502c7b3ac086655f74a6f5806d3fb33f 100644 (file)
@@ -1,2 +1,8 @@
 #pragma once
 #include "pathlib.qh"
+
+#if DEBUGPATHING
+void pathlib_showpath(entity start);
+void pathlib_showpath2(entity path);
+void pathlib_showsquare(vector where,float goodsquare,float _lifetime);
+#endif
index c2f33260302c7899dbba85212c3df2eeece69172..1aeae109c34610f31e05c6a6e174f684d2223e9f 100644 (file)
@@ -30,9 +30,7 @@ void dumpnode(entity n)
 }
 
 #if DEBUGPATHING
-void pathlib_showpath(entity start);
-void pathlib_showpath2(entity path);
-void pathlib_showsquare(vector where,float goodsquare,float _lifetime);
+#include "debug.qh"
 #endif
 
 
index 21ef8b3cbc5286f50a89ca72dde12a3454c7f7a1..d1bafe392a892e2fae67b165eb9c8b32d1a41a9a 100644 (file)
@@ -15,11 +15,6 @@ const vector PLIB_FORWARD = '0 1 0';
 const vector PLIB_RIGHT = '1 0 0';
 //#define PLIB_LEFT    '-1 0 0'
 
-#if DEBUGPATHING
-void pathlib_showpath(entity start);
-void pathlib_showpath2(entity path);
-#endif
-
 entity openlist;
 entity closedlist;
 
index 06bdb1428f869439244afd76f9e836eef8000945..4d59943b682dfb89a81d68e274100e2b1f1d0a86 100644 (file)
@@ -5,7 +5,6 @@
 #include "cheats.qh"
 #include "g_damage.qh"
 #include "handicap.qh"
-#include "g_subs.qh"
 #include "miscfunctions.qh"
 #include "portals.qh"
 #include "teamplay.qh"
@@ -15,8 +14,9 @@
 #include "../common/anim.qh"
 #include "../common/animdecide.qh"
 #include "../common/csqcmodel_settings.qh"
+#include "../common/gamemodes/sv_rules.qh"
 #include "../common/deathtypes/all.qh"
-#include "../common/triggers/subs.qh"
+#include "../common/mapobjects/subs.qh"
 #include "../common/playerstats.qh"
 #include "../lib/csqcmodel/sv_model.qh"
 
@@ -25,7 +25,7 @@
 #include "../common/physics/player.qh"
 #include "../common/effects/qc/_mod.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
-#include "../common/triggers/include.qh"
+#include "../common/mapobjects/_mod.qh"
 #include "../common/wepent.qh"
 
 #include "weapons/weaponstats.qh"
@@ -679,60 +679,6 @@ bool MoveToTeam(entity client, int team_colour, int type)
        return true;
 }
 
-/** print(), but only print if the server is not local */
-void dedicated_print(string input)
-{
-       if (server_is_dedicated) print(input);
-}
-
-void PrintToChat(entity player, string text)
-{
-       text = strcat("\{1}^7", text, "\n");
-       sprint(player, text);
-}
-
-void DebugPrintToChat(entity player, string text)
-{
-       if (autocvar_developer)
-       {
-               PrintToChat(player, text);
-       }
-}
-
-void PrintToChatAll(string text)
-{
-       text = strcat("\{1}^7", text, "\n");
-       bprint(text);
-}
-
-void DebugPrintToChatAll(string text)
-{
-       if (autocvar_developer)
-       {
-               PrintToChatAll(text);
-       }
-}
-
-void PrintToChatTeam(int teamnum, string text)
-{
-       text = strcat("\{1}^7", text, "\n");
-       FOREACH_CLIENT(IS_REAL_CLIENT(it),
-       {
-               if (it.team == teamnum)
-               {
-                       sprint(it, text);
-               }
-       });
-}
-
-void DebugPrintToChatTeam(int teamnum, string text)
-{
-       if (autocvar_developer)
-       {
-               PrintToChatTeam(teamnum, text);
-       }
-}
-
 /**
  * message "": do not say, just test flood control
  * return value:
@@ -969,7 +915,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
        if (privatesay && source && !IS_PLAYER(source))
        {
                if (!game_stopped)
-               if ((privatesay && !IS_PLAYER(privatesay)) || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
+               if ((privatesay && IS_PLAYER(privatesay)) && ((autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage)))
                        ret = -1; // just hide the message completely
        }
 
index ee073ccb4498a960b757409fd055cec5d3c8062d..5e6642e0471a78220a1af579a705e7b50d74b76b 100644 (file)
@@ -9,45 +9,6 @@
 void CopyBody_Think(entity this);
 void CopyBody(entity this, float keepvelocity);
 
-void dedicated_print(string input);
-
-/// \brief Print the string to player's chat.
-/// \param[in] player Player to print to.
-/// \param[in] text Text to print.
-/// \return No return.
-void PrintToChat(entity player, string text);
-
-/// \brief Print the string to player's chat if the server cvar "developer" is
-/// not 0.
-/// \param[in] player Player to print to.
-/// \param[in] text Text to print.
-/// \return No return.
-void DebugPrintToChat(entity player, string text);
-
-/// \brief Prints the string to all players' chat.
-/// \param[in] text Text to print.
-/// \return No return.
-void PrintToChatAll(string text);
-
-/// \brief Prints the string to all players' chat if the server cvar "developer"
-/// is not 0.
-/// \param[in] text Text to print.
-/// \return No return.
-void DebugPrintToChatAll(string text);
-
-/// \brief Print the string to chat of all players of the specified team.
-/// \param[in] teamnum Team to print to. See NUM_TEAM constants.
-/// \param[in] text Text to print.
-/// \return No return.
-void PrintToChatTeam(int teamnum, string text);
-
-/// \brief Print the string to chat of all players of the specified team if the
-/// server cvar "developer" is not 0.
-/// \param[in] teamnum Team to print to. See NUM_TEAM constants.
-/// \param[in] text Text to print.
-/// \return No return.
-void DebugPrintToChatTeam(int teamnum, string text);
-
 void player_setupanimsformodel(entity this);
 
 void player_anim(entity this);
index ca0dc20fd70225f02a97826e2403ca1b699e83f5..64d7f0a8e0a94aa53cfa8d13541a1895438d375a 100644 (file)
@@ -6,8 +6,8 @@
 #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/mapobjects/teleporters.qh"
+#include "../common/mapobjects/subs.qh"
 #include "../common/util.qh"
 #include <common/weapons/_all.qh>
 #include "../lib/csqcmodel/sv_model.qh"
@@ -323,7 +323,6 @@ void Portal_Touch(entity this, entity toucher)
                                toucher.effects += EF_BLUE - EF_RED;
 }
 
-void Portal_Think(entity this);
 void Portal_MakeBrokenPortal(entity portal)
 {
        portal.skin = 2;
index f3528d081072ce7e4314a5ca80b4a6a03bdff8ee..20a2bd930c6f23b4e40b76159943f9fb6d12d24f 100644 (file)
@@ -11,3 +11,5 @@ void Portal_ClearWithID(entity own, float id);
 
 vector Portal_ApplyTransformToPlayerAngle(vector transform, vector vangle);
 void Portal_ClearAll_PortalsOnly(entity own);
+
+void Portal_Think(entity this);
index 7f7f19b518912d5b56db30c60e2fcb447c347074..5286032fb5715900836945008816d06f2e987241 100644 (file)
@@ -14,7 +14,9 @@
 #include <common/gamemodes/rules.qh>
 #include <common/net_linked.qh>
 #include <common/state.qh>
-#include "../common/triggers/subs.qh"
+#include <common/weapons/weapon/porto.qh>
+#include "../common/mapobjects/subs.qh"
+#include <common/mapobjects/triggers.qh>
 #include "../lib/warpzone/util_server.qh"
 #include "../lib/warpzone/common.qh"
 #include "../common/mutators/mutator/waypoints/waypointsprites.qh"
@@ -29,8 +31,6 @@ void race_InitSpectator()
                        race_SendNextCheckpoint(msg_entity.enemy, 1);
 }
 
-void W_Porto_Fail(entity this, float failhard);
-
 float race_readTime(string map, float pos)
 {
        string rr = ((g_cts) ? CTS_RECORD : ((g_ctf) ? CTF_RECORD : RACE_RECORD));
@@ -104,8 +104,6 @@ string race_readName(string map, float pos)
 
 const float MAX_CHECKPOINTS = 255;
 
-spawnfunc(target_checkpoint);
-
 .float race_penalty;
 .float race_penalty_accumulator;
 .string race_penalty_reason;
@@ -224,6 +222,14 @@ void race_send_speedaward_alltimebest(float msg)
        WriteString(msg, speedaward_alltimebest_holder);
 }
 
+void race_send_rankings_cnt(float msg)
+{
+       WriteHeader(msg, TE_CSQC_RACE);
+       WriteByte(msg, RACE_NET_RANKINGS_CNT);
+       int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+       WriteByte(msg, m);
+}
+
 void race_SendRankings(float pos, float prevpos, float del, float msg)
 {
        WriteHeader(msg, TE_CSQC_RACE);
@@ -316,9 +322,7 @@ void race_setTime(string map, float t, string myuid, string mynetname, entity e,
        }
 
        race_SendRankings(newpos, player_prevpos, 0, MSG_ALL);
-       if(rankings_reply)
-               strunzone(rankings_reply);
-       rankings_reply = strzone(getrankings());
+       strcpy(rankings_reply, getrankings());
 
        if(newpos == player_prevpos)
        {
@@ -366,9 +370,7 @@ void race_deleteTime(string map, float pos)
        if(pos == 1)
                race_send_recordtime(MSG_ALL);
 
-       if(rankings_reply)
-               strunzone(rankings_reply);
-       rankings_reply = strzone(getrankings());
+       strcpy(rankings_reply, getrankings());
 }
 
 void race_SendTime(entity e, float cp, float t, float tvalid)
@@ -442,9 +444,7 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                                if(t < recordtime || recordtime == 0)
                                {
                                        race_checkpoint_records[cp] = t;
-                                       if(race_checkpoint_recordholders[cp])
-                                               strunzone(race_checkpoint_recordholders[cp]);
-                                       race_checkpoint_recordholders[cp] = strzone(e.netname);
+                                       strcpy(race_checkpoint_recordholders[cp], e.netname);
                                        if(g_race_qualifying)
                                                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it) && it.race_checkpoint == cp, { race_SendNextCheckpoint(it, 0); });
                                }
@@ -995,7 +995,7 @@ spawnfunc(target_checkpoint) // defrag entity
        defrag_ents = 1;
 
        // if this is targeted, then it probably isn't a trigger
-       bool is_trigger = !boolean(!this.nottargeted && this.targetname != "");
+       bool is_trigger = this.targetname == "";
 
        if(is_trigger)
                EXACTTRIGGER_INIT;
@@ -1089,9 +1089,7 @@ void race_ClearRecords()
        for(int j = 0; j < MAX_CHECKPOINTS; ++j)
        {
                race_checkpoint_records[j] = 0;
-               if(race_checkpoint_recordholders[j])
-                       strunzone(race_checkpoint_recordholders[j]);
-               race_checkpoint_recordholders[j] = string_null;
+               strfree(race_checkpoint_recordholders[j]);
        }
 
        FOREACH_CLIENT(true, {
index 472827efa4a81d13a014ae84d998f1b88d62628f..4402e22568ce1f027c26f93e6cba1a0e339f278c 100644 (file)
@@ -5,6 +5,8 @@ float race_teams;
 // scores
 const float ST_RACE_LAPS = 1;
 
+int autocvar_g_cts_send_rankings_cnt = 15;
+
 bool g_race_qualifying;
 
 float speedaward_lastsent;
@@ -61,8 +63,12 @@ void race_send_speedaward(float msg);
 
 void race_send_speedaward_alltimebest(float msg);
 
+void race_send_rankings_cnt(float msg);
+
 void race_SendRankings(float pos, float prevpos, float del, float msg);
 
 void race_RetractPlayer(entity this);
 
 void race_InitSpectator();
+
+spawnfunc(target_checkpoint);
index a2a1358b97856196366b7dc95c909c620f2152ec..4ad66bb98ed2169380e7074ea23147a503e652cf 100644 (file)
@@ -83,17 +83,24 @@ void SetResourceAmount(entity e, int resource_type, float amount)
        }
        resource_type = M_ARGV(1, int);
        amount = M_ARGV(2, float);
-       .float resource_field = GetResourceField(resource_type);
-       if (e.(resource_field) == amount)
-       {
-               return;
-       }
        float max_amount = GetResourceLimit(e, resource_type);
+       float amount_wasted = 0;
        if (amount > max_amount)
        {
+               amount_wasted = amount - max_amount;
                amount = max_amount;
        }
-       e.(resource_field) = amount;
+       .float resource_field = GetResourceField(resource_type);
+       if (e.(resource_field) != amount)
+       {
+               e.(resource_field) = amount;
+               MUTATOR_CALLHOOK(ResourceAmountChanged, e, resource_type, amount);
+       }
+       if (amount_wasted == 0)
+       {
+               return;
+       }
+       MUTATOR_CALLHOOK(ResourceWasted, e, resource_type, amount_wasted);
 }
 
 void GiveResource(entity receiver, int resource_type, float amount)
@@ -144,6 +151,19 @@ void GiveResource(entity receiver, int resource_type, float amount)
 void GiveResourceWithLimit(entity receiver, int resource_type, float amount,
        float limit)
 {
+       if (amount == 0)
+       {
+               return;
+       }
+       bool forbid = MUTATOR_CALLHOOK(GiveResourceWithLimit, receiver,
+               resource_type, amount, limit);
+       if (forbid)
+       {
+               return;
+       }
+       resource_type = M_ARGV(1, int);
+       amount = M_ARGV(2, float);
+       limit = M_ARGV(3, float);
        if (amount == 0)
        {
                return;
index c9948660efe1165c7ed8654dac1ba770e6763277..2cb40a83492d88f454622f2c6dc9a6a47b7a7d15 100644 (file)
@@ -1,11 +1,18 @@
 #include "scores.qh"
 
 #include "command/common.qh"
-#include "mutators/_mod.qh"
+#include "defs.qh"
+#include <server/g_world.qh>
+#include <server/miscfunctions.qh>
+#include <server/mutators/_mod.qh>
 #include <common/net_linked.qh>
 #include "../common/playerstats.qh"
 #include "../common/teams.qh"
+#include <common/mapinfo.qh>
+#include <common/mutators/base.qh>
 #include <common/scores.qh>
+#include <common/state.qh>
+#include <common/stats.qh>
 
 .entity scorekeeper;
 entity teamscorekeepers[16];
@@ -353,6 +360,28 @@ float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score)
        return s.(scores(scorefield));
 }
 
+float PlayerScore_Set(entity player, PlayerScoreField scorefield, float score)
+{
+       if(!scores_initialized) return 0; // FIXME remove this when everything uses this system
+       entity s = CS(player).scorekeeper;
+       if(!s)
+       {
+               if(game_stopped)
+                       return 0;
+               LOG_WARN("Setting score of unknown player!");
+               return 0;
+       }
+
+       float oldscore = s.(scores(scorefield));
+       if(oldscore == score)
+               return oldscore;
+
+       if(scores_label(scorefield) != "")
+               s.SendFlags |= (2 ** (scorefield.m_id % 16));
+       s.(scores(scorefield)) = score;
+       return s.(scores(scorefield));
+}
+
 float PlayerTeamScore_Add(entity player, PlayerScoreField pscorefield, float tscorefield, float score)
 {
        float r;
@@ -513,9 +542,7 @@ void WinningConditionHelper(entity this)
                }
        }
 
-       if(worldstatus)
-               strunzone(worldstatus);
-       worldstatus = strzone(s);
+       strcpy(worldstatus, s);
 
        FOREACH_CLIENT(true, {
                string s = "";
@@ -534,9 +561,7 @@ void WinningConditionHelper(entity this)
                                s = "-666";
                }
 
-               if(it.clientstatus)
-                       strunzone(it.clientstatus);
-               it.clientstatus = strzone(s);
+               strcpy(it.clientstatus, s);
        });
 }
 
index e2a57f43fb4a3ffaf36b6a5d33f1d475d793e9db..ad406196635a55b1ecf60667d653eba8a21c27bc 100644 (file)
@@ -24,6 +24,14 @@ void PlayerScore_Detach(entity player);
  */
 float PlayerScore_Add(entity player, PlayerScoreField scorefield, float score);
 
+/**
+ * Sets the player's score to the score parameter.
+ * NEVER call this if PlayerScore_Attach has not been called yet!
+ * Means: FIXME make players unable to join the game when not called ClientConnect yet.
+ * Returns the new (or old if unchanged) score.
+ */
+float PlayerScore_Set(entity player, PlayerScoreField scorefield, float score);
+
 /**
  * \brief Returns the player's score.
  * \param[in] player Player to inspect.
index 8d87407e64ebd3bc165efe3e27b53c6ceef25f0b..160b5df5e4cfb21c279b96c39d28dbe6965b27d4 100644 (file)
@@ -9,8 +9,6 @@
 
 int ScoreRules_teams;
 
-void CheckAllowedTeams (entity for_whom);
-
 int NumTeams(int teams)
 {
        return boolean(teams & BIT(0)) + boolean(teams & BIT(1)) + boolean(teams & BIT(2)) + boolean(teams & BIT(3));
@@ -55,6 +53,9 @@ void ScoreRules_basics(int teams, float sprio, float stprio, float score_enabled
        ScoreInfo_SetLabel_PlayerScore(SP_DMG, "dmg", 0);
        ScoreInfo_SetLabel_PlayerScore(SP_DMGTAKEN, "dmgtaken", SFL_LOWER_IS_BETTER);
        ScoreInfo_SetLabel_PlayerScore(SP_ELO, "elo", 0);
+
+       if(STAT(SHOWFPS))
+               ScoreInfo_SetLabel_PlayerScore(SP_FPS, "fps", 0);
 }
 void ScoreRules_basics_end()
 {
index e48840883a589658796b693585badd2d7e4d9bf8..dcf6016c5e326b902e8c59f06519ab86215ee707 100644 (file)
@@ -1,16 +1,18 @@
 #include "spawnpoints.qh"
 
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "g_world.qh"
 #include "race.qh"
+#include "defs.qh"
 #include "../common/constants.qh"
 #include <common/net_linked.qh>
 #include "../common/teams.qh"
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/target/spawnpoint.qh"
+#include "../common/mapobjects/subs.qh"
+#include "../common/mapobjects/target/spawnpoint.qh"
 #include "../common/util.qh"
 #include "../lib/warpzone/common.qh"
 #include "../lib/warpzone/util_server.qh"
+#include <server/utils.qh>
 
 bool SpawnPoint_Send(entity this, entity to, int sf)
 {
index 3418a2c4e375a80c0506dcf58400018c918297fd..92c918f00ca2281d360282312cfc3b3b9e1fc5df 100644 (file)
@@ -29,11 +29,8 @@ vector steerlib_push(entity this, vector point)
 **/
 vector steerlib_arrive(entity this, vector point, float maximal_distance)
 {
-    float distance;
-    vector direction;
-
-    distance = bound(0.001,vlen(this.origin - point),maximal_distance);
-    direction = normalize(point - this.origin);
+    float distance = bound(0.001,vlen(this.origin - point),maximal_distance);
+    vector direction = normalize(point - this.origin);
     return  direction * (distance / maximal_distance);
 }
 
@@ -42,25 +39,18 @@ vector steerlib_arrive(entity this, vector point, float maximal_distance)
 **/
 vector steerlib_attract(entity this, vector point, float maximal_distance)
 {
-    float distance;
-    vector direction;
-
-    distance = bound(0.001,vlen(this.origin - point),maximal_distance);
-    direction = normalize(point - this.origin);
+    float distance = bound(0.001,vlen(this.origin - point),maximal_distance);
+    vector direction = normalize(point - this.origin);
 
     return  direction * (1-(distance / maximal_distance));
 }
 
 vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
 {
-    float distance;
-    vector direction;
-    float influense;
+    float distance  = bound(0.00001,vlen(this.origin - point),max_distance);
+    vector direction = normalize(point - this.origin);
 
-    distance  = bound(0.00001,vlen(this.origin - point),max_distance);
-    direction = normalize(point - this.origin);
-
-    influense = 1 - (distance / max_distance);
+    float influense = 1 - (distance / max_distance);
     influense = min_influense + (influense * (max_influense - min_influense));
 
     return  direction * influense;
@@ -447,176 +437,3 @@ vector steerlib_beamsteer(entity this, vector dir, float length, float step, flo
     return normalize(vr + vl);
 
 }
-
-
-//////////////////////////////////////////////
-//     Testting                             //
-// Everything below this point is a mess :D //
-//////////////////////////////////////////////
-//#define TLIBS_TETSLIBS
-#ifdef TLIBS_TETSLIBS
-void flocker_die(entity this)
-{
-       Send_Effect(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
-
-    this.owner.cnt += 1;
-    this.owner = NULL;
-
-    this.nextthink = time;
-    setthink(this, SUB_Remove);
-}
-
-
-void flocker_think(entity this)
-{
-    vector dodgemove,swarmmove;
-    vector reprellmove,wandermove,newmove;
-
-    this.angles_x = this.angles.x * -1;
-    makevectors(this.angles);
-    this.angles_x = this.angles.x * -1;
-
-    dodgemove   = steerlib_traceavoid(this, 0.35,1000);
-    swarmmove   = steerlib_flock(this, 500,75,700,500);
-    reprellmove = steerlib_repell(this, this.owner.enemy.origin+this.enemy.velocity,2000) * 700;
-
-    if(dodgemove == '0 0 0')
-    {
-        this.pos1 = steerlib_wander(this, 0.5,0.1,this.pos1);
-        wandermove  = this.pos1 * 50;
-    }
-    else
-        this.pos1 = normalize(this.velocity);
-
-    dodgemove = dodgemove * vlen(this.velocity) * 5;
-
-    newmove = swarmmove + reprellmove + wandermove + dodgemove;
-    this.velocity = movelib_inertmove_byspeed(this, newmove,300,0.2,0.9);
-    //this.velocity  = movelib_inertmove(this, dodgemove,0.65);
-
-    this.velocity = movelib_dragvec(this, 0.01,0.6);
-
-    this.angles = vectoangles(this.velocity);
-
-    if(this.health <= 0)
-        flocker_die(this);
-    else
-        this.nextthink = time + 0.1;
-}
-
-MODEL(FLOCKER, "models/turrets/rocket.md3");
-
-void spawn_flocker(entity this)
-{
-    entity flocker = new(flocker);
-
-    setorigin(flocker, this.origin + '0 0 32');
-    setmodel (flocker, MDL_FLOCKER);
-    setsize (flocker, '-3 -3 -3', '3 3 3');
-
-    flocker.flock_id   = this.flock_id;
-    flocker.owner      = this;
-    setthink(flocker, flocker_think);
-    flocker.nextthink  = time + random() * 5;
-    PROJECTILE_MAKETRIGGER(flocker);
-    set_movetype(flocker, MOVETYPE_BOUNCEMISSILE);
-    flocker.effects    = EF_LOWPRECISION;
-    flocker.velocity   = randomvec() * 300;
-    flocker.angles     = vectoangles(flocker.velocity);
-    flocker.health     = 10;
-    flocker.pos1      = normalize(flocker.velocity + randomvec() * 0.1);
-
-    IL_PUSH(g_flockers, flocker);
-
-    this.cnt = this.cnt -1;
-
-}
-
-void flockerspawn_think(entity this)
-{
-    if(this.cnt > 0)
-        spawn_flocker(this);
-
-    this.nextthink = time + this.delay;
-
-}
-
-void flocker_hunter_think(entity this)
-{
-    vector dodgemove,attractmove,newmove;
-    entity ee;
-
-    this.angles_x = this.angles.x * -1;
-    makevectors(this.angles);
-    this.angles_x = this.angles.x * -1;
-
-    if(this.enemy)
-    if(vdist(this.enemy.origin - this.origin, <, 64))
-    {
-        ee = this.enemy;
-        ee.health = -1;
-        this.enemy = NULL;
-
-    }
-
-    if(!this.enemy)
-    {
-        IL_EACH(g_flockers, it.flock_id == this.flock_id,
-        {
-            if(it == this.owner || it == ee)
-                continue;
-
-            if(!this.enemy || vlen2(this.origin - it.origin) > vlen2(this.origin - this.enemy.origin))
-                this.enemy = it;
-        });
-    }
-
-    if(this.enemy)
-        attractmove = steerlib_attract(this, this.enemy.origin+this.enemy.velocity * 0.1,5000) * 1250;
-    else
-        attractmove = normalize(this.velocity) * 200;
-
-    dodgemove = steerlib_traceavoid(this, 0.35,1500) * vlen(this.velocity);
-
-    newmove = dodgemove + attractmove;
-    this.velocity = movelib_inertmove_byspeed(this, newmove,1250,0.3,0.7);
-    this.velocity = movelib_dragvec(this, 0.01,0.5);
-
-    this.angles = vectoangles(this.velocity);
-    this.nextthink = time + 0.1;
-}
-
-
-float globflockcnt;
-spawnfunc(flockerspawn)
-{
-    ++globflockcnt;
-
-    if(!this.cnt)      this.cnt = 20;
-    if(!this.delay)    this.delay = 0.25;
-    if(!this.flock_id) this.flock_id = globflockcnt;
-
-    setthink(this, flockerspawn_think);
-    this.nextthink = time + 0.25;
-
-    this.enemy = new(FLock Hunter);
-
-    setmodel(this.enemy, MDL_FLOCKER);
-    setorigin(this.enemy, this.origin + '0 0 768' + (randomvec() * 128));
-
-    this.enemy.scale     = 3;
-    this.enemy.effects   = EF_LOWPRECISION;
-    set_movetype(this.enemy, MOVETYPE_BOUNCEMISSILE);
-    PROJECTILE_MAKETRIGGER(this.enemy);
-    setthink(this.enemy, flocker_hunter_think);
-    this.enemy.nextthink = time + 10;
-    this.enemy.flock_id  = this.flock_id;
-    this.enemy.owner     = this;
-
-    IL_PUSH(g_flockers, this);
-    IL_PUSH(g_flockers, this.enemy);
-}
-#endif
-
-
-
index 89ffb698ec6ca763d97f8ad899ddec5a6ed82ae8..4beb69f6328ba6c337d3b34e803104464e8a73d3 100644 (file)
@@ -5,6 +5,3 @@
 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);
-
-IntrusiveList g_flockers;
-STATIC_INIT(g_flockers) { g_flockers = IL_NEW(); }
index 1130b6a4e5dd349abdf935a81039e0334c22c443..539b30d294ce0c68e43e80d81f9b0d7732353199 100644 (file)
@@ -2,14 +2,16 @@
 
 #include "anticheat.qh"
 #include "g_hook.qh"
+#include "g_damage.qh"
 #include "g_world.qh"
 
 #include "bot/api.qh"
 
 #include "command/common.qh"
 
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "weapons/csqcprojectile.qh"
+#include <server/compat/quake3.qh>
 
 #include "../common/constants.qh"
 #include "../common/deathtypes/all.qh"
@@ -18,6 +20,7 @@
 #include "../common/util.qh"
 
 #include "../common/vehicles/all.qh"
+#include <common/monsters/sv_monsters.qh>
 #include <common/weapons/_all.qh>
 
 #include "../lib/csqcmodel/sv_model.qh"
@@ -165,7 +168,6 @@ Called before each frame by the server
 bool game_delay_last;
 
 bool autocvar_sv_autopause = false;
-float RedirectionThink();
 void systems_update();
 void sys_phys_update(entity this, float dt);
 void StartFrame()
@@ -246,7 +248,6 @@ void StartFrame()
 .float anglejitter;
 .string gametypefilter;
 .string cvarfilter;
-bool DoesQ3ARemoveThisEntity(entity this);
 
 /**
  * Evaluate an expression of the form: [+ | -]? [var[op]val | [op]var | val | var] ...
@@ -360,7 +361,7 @@ void SV_OnEntityPreSpawnFunction(entity this)
        }
        return;
 LABEL(cleanup)
-    builtin_remove(this);
+    delete(this);
 }
 
 void WarpZone_PostInitialize_Callback()
@@ -383,3 +384,15 @@ void WarpZone_PostInitialize_Callback()
        }
        delete(tracetest_ent);
 }
+
+/*
+==================
+main
+
+unused but required by the engine
+==================
+*/
+void main ()
+{
+
+}
index 7f86d19c01a47bc83cfd2870c0f0c170a0e93b99..93480cf282ec6c5377ac13197eea0dbe009ddfd2 100644 (file)
@@ -1,3 +1,12 @@
 #pragma once
 
 bool expr_evaluate(string s);
+
+/*
+==================
+main
+
+unused but required by the engine
+==================
+*/
+void main ();
index cf21de4bfd3978ac2942e03eb0e7ccafa6234318..d9bab5d7f894cd1346f60c507becb6d4009586eb 100644 (file)
@@ -9,10 +9,10 @@
 
 #include "command/vote.qh"
 
-#include "mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 
 #include "../common/deathtypes/all.qh"
-#include "../common/gamemodes/_mod.qh"
+#include <common/gamemodes/_mod.qh>
 #include "../common/teams.qh"
 
 void TeamchangeFrags(entity e)
@@ -105,7 +105,7 @@ string getwelcomemessage(entity this)
        if(g_weaponarena)
        {
                if(g_weaponarena_random)
-                       modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena");
+                       modifications = strcat(modifications, ", ", ftos(g_weaponarena_random), " of ", g_weaponarena_list, " Arena"); // TODO: somehow get this into the mutator
                else
                        modifications = strcat(modifications, ", ", g_weaponarena_list, " Arena");
        }
@@ -131,12 +131,8 @@ string getwelcomemessage(entity this)
 
        if(cache_lastmutatormsg != autocvar_g_mutatormsg)
        {
-               if(cache_lastmutatormsg)
-                       strunzone(cache_lastmutatormsg);
-               if(cache_mutatormsg)
-                       strunzone(cache_mutatormsg);
-               cache_lastmutatormsg = strzone(autocvar_g_mutatormsg);
-               cache_mutatormsg = strzone(cache_lastmutatormsg);
+               strcpy(cache_lastmutatormsg, autocvar_g_mutatormsg);
+               strcpy(cache_mutatormsg, cache_lastmutatormsg);
        }
 
        if (cache_mutatormsg != "") {
index 1eda4e25b1066c86831ef2cb679bccd7993a6ce8..2d553ba1685b1a62bb6f6dade746acd9042c72b2 100644 (file)
@@ -1,6 +1,6 @@
 #include "accuracy.qh"
 
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include <common/constants.qh>
 #include <common/net_linked.qh>
 #include <common/teams.qh>
index 90aca172cc83f600e77c7d19e6a52405e7222547..06615c4eac8575465aed85fe57cbe5181c423940 100644 (file)
@@ -30,7 +30,7 @@ void W_GiveWeapon(entity e, int wep)
 {
        if (!wep) return;
 
-       e.weapons |= WepSet_FromWeapon(Weapons_from(wep));
+       STAT(WEAPONS, e) |= WepSet_FromWeapon(Weapons_from(wep));
 
        if (IS_PLAYER(e)) {
            Send_Notification(NOTIF_ONE, e, MSG_MULTI, ITEM_WEAPON_GOT, wep);
index e6bdd00d2b8e3163f2e51f090584fbd37008dd80..e79e9ddb6413bb2b86e98e84e4e04793fa1ca5a5 100644 (file)
@@ -3,7 +3,6 @@
 #include <server/defs.qh>
 #include <server/miscfunctions.qh>
 #include "../antilag.qh"
-#include "../g_subs.qh"
 #include <common/weapons/_all.qh>
 #include <common/state.qh>
 #include <common/wepent.qh>
index f059dfba9bccd79a97da944a5c9eaea77a98e0be..c2a9c32acdef778fac3191045753e8ee80032c60 100644 (file)
@@ -52,7 +52,7 @@ bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andam
 
        // ignore hook button when using other offhand equipment
        if (this.offhand != OFFHAND_HOOK)
-       if (wpn == WEP_HOOK && !((this.weapons | weaponsInMap) & WepSet_FromWeapon(wpn)))
+       if (wpn == WEP_HOOK && !((STAT(WEAPONS, this) | weaponsInMap) & WepSet_FromWeapon(wpn)))
            complain = 0;
 
        if (complain)
@@ -66,7 +66,7 @@ bool client_hasweapon(entity this, Weapon wpn, .entity weaponentity, float andam
        }
        if (autocvar_g_weaponswitch_debug == 2 && weaponslot(weaponentity) > 0 && !(wpn.spawnflags & WEP_FLAG_DUALWIELD) && !(PS(this).dual_weapons & wpn.m_wepset))
                return false; // no complaints needed
-       if (this.weapons & WepSet_FromWeapon(wpn))
+       if (STAT(WEAPONS, this) & WepSet_FromWeapon(wpn))
        {
                if (andammo)
                {
@@ -161,12 +161,12 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl
                FOREACH(Weapons, it != WEP_Null, {
                        if(i != weaponwant)
                        if(it.impulse == imp || imp < 0)
-                       if((this.weapons & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
+                       if((STAT(WEAPONS, this) & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
                                have_other = true;
                });
 
                // skip weapons we don't own that aren't normal and aren't in the map
-               if(!(this.weapons & wepset))
+               if(!(STAT(WEAPONS, this) & wepset))
                if(!(weaponsInMap & wepset))
                if((wep.spawnflags & WEP_FLAG_MUTATORBLOCKED) || have_other)
                        continue;
@@ -217,12 +217,12 @@ float W_GetCycleWeapon(entity this, string weaponorder, float dir, float imp, fl
                        FOREACH(Weapons, it != WEP_Null, {
                                if(i != weaponwant)
                                if(it.impulse == imp || imp < 0)
-                               if((this.weapons & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
+                               if((STAT(WEAPONS, this) & (it.m_wepset)) || (weaponsInMap & (it.m_wepset)))
                                        have_other = true;
                        });
 
                        // skip weapons we don't own that aren't normal and aren't in the map
-                       if(!(this.weapons & wepset))
+                       if(!(STAT(WEAPONS, this) & wepset))
                        if(!(weaponsInMap & wepset))
                        if((wep.spawnflags & WEP_FLAG_MUTATORBLOCKED) || have_other)
                                continue;
@@ -252,11 +252,11 @@ void W_SwitchToOtherWeapon(entity this, .entity weaponentity)
        // hack to ensure it switches to an OTHER weapon (in case the other fire mode still has ammo, we want that anyway)
        Weapon ww;
        WepSet set = WepSet_FromWeapon(this.(weaponentity).m_weapon);
-       if (this.weapons & set)
+       if (STAT(WEAPONS, this) & set)
        {
-               this.weapons &= ~set;
+               STAT(WEAPONS, this) &= ~set;
                ww = w_getbestweapon(this, weaponentity);
-               this.weapons |= set;
+               STAT(WEAPONS, this) |= set;
        }
        else
        {
index d47351cb37a727aab87f100d2ccb61ddd98a5824..204b5a7633669ffeac43adcf5c6da6013939d703 100644 (file)
@@ -2,7 +2,7 @@
 
 #include "weaponsystem.qh"
 #include "../resources.qh"
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include <common/t_items.qh>
 #include <server/items.qh>
 #include <common/weapons/_all.qh>
@@ -88,6 +88,13 @@ void weapon_defaultspawnfunc(entity this, Weapon e)
                }
        }
 
+       if (!Item_IsDefinitionAllowed(wpn.m_pickup))
+       {
+               delete(this);
+               startitem_failed = true;
+               return;
+       }
+
        if (!this.respawntime)
        {
                if (wpn.spawnflags & WEP_FLAG_SUPERWEAPON)
index ae745efd6fdaa90f6ed39b9d8b59e4736a3c26fa..462af14d8e0ca151f366f9daa611f1caf3c00cc7 100644 (file)
@@ -3,13 +3,13 @@
 #include "weaponsystem.qh"
 #include "../resources.qh"
 #include "../items.qh"
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include <common/t_items.qh>
 #include "../g_damage.qh"
 #include <common/items/item.qh>
 #include <common/mapinfo.qh>
 #include <common/notifications/all.qh>
-#include <common/triggers/subs.qh>
+#include <common/mapobjects/subs.qh>
 #include <common/util.qh>
 #include <common/weapons/_all.qh>
 #include <common/state.qh>
@@ -65,7 +65,7 @@ string W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vecto
                        int superweapons = 1;
                        FOREACH(Weapons, it != WEP_Null, {
                                WepSet set = it.m_wepset;
-                               if((set & WEPSET_SUPERWEAPONS) && (own.weapons & set)) ++superweapons;
+                               if((set & WEPSET_SUPERWEAPONS) && (STAT(WEAPONS, own) & set)) ++superweapons;
                        });
                        if(superweapons <= 1)
                        {
@@ -152,19 +152,7 @@ bool W_IsWeaponThrowable(entity this, int w)
     if(w == WEP_Null.m_id)
         return false;
 
-       #if 0
-       if(start_weapons & WepSet_FromWeapon(Weapons_from(w)))
-       {
-               // start weapons that take no ammo can't be dropped (this prevents dropping the laser, as long as it continues to use no ammo)
-               if(start_items & IT_UNLIMITED_WEAPON_AMMO)
-                       return false;
-               if((Weapons_from(w)).ammo_type == RESOURCE_NONE)
-                       return false;
-       }
-       return true;
-       #else
        return (Weapons_from(w)).weaponthrowable;
-       #endif
 }
 
 // toss current weapon
@@ -183,8 +171,8 @@ void W_ThrowWeapon(entity this, .entity weaponentity, vector velo, vector delta,
                return;
 
        WepSet set = WepSet_FromWeapon(w);
-       if(!(this.weapons & set)) return;
-       this.weapons &= ~set;
+       if(!(STAT(WEAPONS, this) & set)) return;
+       STAT(WEAPONS, this) &= ~set;
 
        W_SwitchWeapon_Force(this, w_getbestweapon(this, weaponentity), weaponentity);
        string a = W_ThrowNewWeapon(this, w.m_id, doreduce, this.origin + delta, velo, weaponentity);
@@ -197,7 +185,7 @@ void SpawnThrownWeapon(entity this, vector org, Weapon wep, .entity weaponentity
 {
        //entity wep = this.(weaponentity).m_weapon;
 
-       if(this.weapons & WepSet_FromWeapon(wep))
+       if(STAT(WEAPONS, this) & WepSet_FromWeapon(wep))
                if(W_IsWeaponThrowable(this, wep.m_id))
                        W_ThrowNewWeapon(this, wep.m_id, false, org, randomvec() * 125 + '0 0 200', weaponentity);
 }
index 60a5c3ba7011f81c0e6a2ce7ff9942e7653fed0f..b023180a138b1a9cca08235f950e8e81d633b17b 100644 (file)
@@ -8,7 +8,6 @@
 #include "weaponsystem.qh"
 
 #include "../g_damage.qh"
-#include "../g_subs.qh"
 #include "../antilag.qh"
 
 #include <common/constants.qh>
@@ -81,7 +80,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
                tracebox(w_shotorg, mi, ma, w_shotorg + v_forward * (vecs.x + nudge), MOVE_NORMAL, ent);
        w_shotorg = trace_endpos - v_forward * nudge;
        // calculate the shotdir from the chosen shotorg
-       w_shotdir = normalize(w_shotend - w_shotorg);
+       if(W_DualWielding(ent))
+               w_shotdir = s_forward;
+       else
+               w_shotdir = normalize(w_shotend - w_shotorg);
 
        //vector prevdir = w_shotdir;
        //vector prevorg = w_shotorg;
index 809db42710815711c3da5177035c0a1cc1affe2c..ab600f33172af58fcf220fe200917d269eaa3174 100644 (file)
@@ -3,9 +3,9 @@
 #include "selection.qh"
 
 #include "../command/common.qh"
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
 #include "../round_handler.qh"
-#include "../resources.qh"
+#include <server/resources.qh>
 #include <common/t_items.qh>
 #include <common/animdecide.qh>
 #include <common/constants.qh>
@@ -332,8 +332,6 @@ bool weapon_prepareattack(Weapon thiswep, entity actor, .entity weaponentity, bo
        return false;
 }
 
-void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim);
-
 /**
  * @param t defer thinking until time + t
  * @param func next think function
@@ -559,7 +557,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
        // server framerate is very low and the weapon fire rate very high
        for (int c = 0; c < W_TICSPERFRAME; ++c)
        {
-               if (w != WEP_Null && !(actor.weapons & WepSet_FromWeapon(w)))
+               if (w != WEP_Null && !(STAT(WEAPONS, actor) & WepSet_FromWeapon(w)))
                {
                        if (this.m_weapon == this.m_switchweapon) W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
                        w = WEP_Null;
@@ -576,7 +574,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
                                key_pressed = false;
 
                        Weapon off = actor.offhand;
-                       if (off && !(actor.weapons & WEPSET(HOOK)))
+                       if (off && (!(STAT(WEAPONS, actor) & WEPSET(HOOK)) || off != OFFHAND_HOOK))
                        {
                                if (off.offhand_think) off.offhand_think(off, actor, key_pressed);
                        }
@@ -660,9 +658,11 @@ void W_AttachToShotorg(entity actor, .entity weaponentity, entity flash, vector
 
 void W_DecreaseAmmo(Weapon wep, entity actor, float ammo_use, .entity weaponentity)
 {
-       if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor, actor.(weaponentity))) return;
+       if (MUTATOR_CALLHOOK(W_DecreaseAmmo, actor, actor.(weaponentity), ammo_use)) return;
        if ((actor.items & IT_UNLIMITED_WEAPON_AMMO) && !wep.reloading_ammo) return;
 
+       ammo_use = M_ARGV(2, float);
+
        entity w_ent = actor.(weaponentity);
 
        // if this weapon is reloadable, decrease its load. Else decrease the player's ammo
@@ -741,8 +741,7 @@ void W_Reload(entity actor, .entity weaponentity, float sent_ammo_min, Sound sen
        this.reload_ammo_min = sent_ammo_min;
        this.reload_ammo_amount = e.reloading_ammo;
        this.reload_time = e.reloading_time;
-       if (actor.reload_sound) strunzone(actor.reload_sound);
-       actor.reload_sound = strzone(Sound_fixpath(sent_sound));
+       strcpy(actor.reload_sound, Sound_fixpath(sent_sound));
 
        // don't reload weapons that don't have the RELOADABLE flag
        if (!(e.spawnflags & WEP_FLAG_RELOADABLE))
index 15cbfc4aab5a222f8a06da9091884057c5f84fe3..865e6e592ca48c037932fa643ec80e9dd1b20f83 100755 (executable)
@@ -32,7 +32,7 @@ function qpp() {
     err=$?
     set -e
     if [ ${err} -ne 0 ]; then return ${err}; fi
-    sed 's/^#\(line\)\? \([[:digit:]]\+\) "\(.*\)".*/\n#pragma file(\3)\n#pragma line(\2)/g' "${WORKDIR}/${MODE}.txt"
+    sed -E 's/^#(line)? ([[:digit:]]+) "(.*)".*/'$'\\\n''#pragma file(\3)'$'\\\n''#pragma line(\2)/g' "${WORKDIR}/${MODE}.txt"
 }
 
 function qcc() {
diff --git a/randomitems-overkill.cfg b/randomitems-overkill.cfg
new file mode 100644 (file)
index 0000000..e2a2617
--- /dev/null
@@ -0,0 +1,21 @@
+// Random items mutator config for Overkill ruleset
+
+// Map items
+
+set g_random_items_item_health_mega_probability 1 "Probability of random mega health spawning in the map during overkill."
+set g_random_items_item_armor_small_probability 10 "Probability of random small armor spawning in the map during overkill."
+set g_random_items_item_armor_medium_probability 4 "Probability of random medium armor spawning in the map during overkill."
+set g_random_items_item_armor_big_probability 2 "Probability of random big armor spawning in the map during overkill."
+set g_random_items_item_armor_mega_probability 1 "Probability of random mega armor spawning in the map during overkill."
+set g_random_items_weapon_okhmg_probability 0.5 "Probability of random overkill HMG spawning in the map during overkill."
+set g_random_items_weapon_okrpc_probability 0.5 "Probability of random overkill RPC spawning in the map during overkill."
+
+// Loot
+
+set g_random_loot_item_health_mega_probability 1 "Probability of random mega health spawning as loot during overkill."
+set g_random_loot_item_armor_small_probability 10 "Probability of random small armor spawning as loot during overkill."
+set g_random_loot_item_armor_medium_probability 4 "Probability of random medium armor spawning as loot during overkill."
+set g_random_loot_item_armor_big_probability 2 "Probability of random big armor spawning as loot during overkill."
+set g_random_loot_item_armor_mega_probability 1 "Probability of random mega armor spawning as loot during overkill."
+set g_random_loot_weapon_okhmg_probability 1 "Probability of random overkill HMG spawning as loot during overkill."
+set g_random_loot_weapon_okrpc_probability 1 "Probability of random overkill RPC spawning as loot during overkill."
index 803e6c3ae8aa1e83f465a05d28a1ec9bff8a23e0..47611a9e23a5120f20b3663a4abcbd501ec6e58e 100644 (file)
@@ -29,6 +29,9 @@ set g_random_items_replace_weapon_shockwave "random" "Classnames to replace shoc
 set g_random_items_replace_weapon_arc "random" "Classnames to replace arc with."
 set g_random_items_replace_weapon_hook "random" "Classnames to replace hook with."
 set g_random_items_replace_weapon_tuba "random" "Classnames to replace tuba with."
+set g_random_items_replace_weapon_okshotgun "random" "Classnames to replace overkill shotgun with."
+set g_random_items_replace_weapon_okmachinegun "random" "Classnames to replace overkill machinegun with."
+set g_random_items_replace_weapon_oknex "random" "Classnames to replace overkill nex with."
 set g_random_items_replace_weapon_porto "random" "Classnames to replace port-o-launch with."
 set g_random_items_replace_weapon_fireball "random" "Classnames to replace fireball with."
 set g_random_items_replace_weapon_minelayer "random" "Classnames to replace mine layer with."
@@ -36,8 +39,8 @@ set g_random_items_replace_weapon_hlac "random" "Classnames to replace HLAC with
 set g_random_items_replace_weapon_rifle "random" "Classnames to replace rifle with."
 set g_random_items_replace_weapon_seeker "random" "Classnames to replace TAG seeker with."
 set g_random_items_replace_weapon_vaporizer "random" "Classnames to replace vaporizer with."
-set g_random_items_replace_weapon_hmg "random" "Classnames to replace HMG with."
-set g_random_items_replace_weapon_rpc "random" "Classnames to replace RPC with."
+set g_random_items_replace_weapon_okhmg "random" "Classnames to replace overkill HMG with."
+set g_random_items_replace_weapon_okrpc "random" "Classnames to replace overkill RPC with."
 set g_random_items_replace_item_strength "random" "Classnames to replace strength with."
 set g_random_items_replace_item_shield "random" "Classnames to replace shield with."
 set g_random_items_replace_item_fuel_regen "random" "Classnames to replace fuel regeneration with."
@@ -78,6 +81,9 @@ set g_random_items_weapon_shockwave_probability 0 "Probability of random shockwa
 set g_random_items_weapon_arc_probability 0 "Probability of random arc spawning in the map."
 set g_random_items_weapon_hook_probability 0 "Probability of random hook spawning in the map."
 set g_random_items_weapon_tuba_probability 0 "Probability of random tuba spawning in the map."
+set g_random_items_weapon_okshotgun_probability 0 "Probability of random overkill shotgun spawning in the map."
+set g_random_items_weapon_okmachinegun_probability 0 "Probability of random overkill machinegun spawning in the map."
+set g_random_items_weapon_oknex_probability 0 "Probability of random overkill nex spawning in the map."
 set g_random_items_weapon_porto_probability 0 "Probability of random port-o-launch spawning in the map."
 set g_random_items_weapon_fireball_probability 0 "Probability of random fireball spawning in the map."
 set g_random_items_weapon_minelayer_probability 0 "Probability of random mine layer spawning in the map."
@@ -85,6 +91,11 @@ set g_random_items_weapon_hlac_probability 0 "Probability of random HLAC spawnin
 set g_random_items_weapon_rifle_probability 0 "Probability of random rifle spawning in the map."
 set g_random_items_weapon_seeker_probability 0 "Probability of random TAG seeker spawning in the map."
 set g_random_items_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning in the map."
+set g_random_items_weapon_okshotgun_probability 0 "Probability of random overkill shotgun spawning in the map."
+set g_random_items_weapon_okmachinegun_probability 0 "Probability of random overkill machinegun spawning in the map."
+set g_random_items_weapon_oknex_probability 0 "Probability of random overkill nex spawning in the map."
+set g_random_items_weapon_okhmg_probability 0 "Probability of random overkill HMG spawning in the map."
+set g_random_items_weapon_okrpc_probability 0 "Probability of random overkill RPC spawning in the map."
 set g_random_items_item_strength_probability 1 "Probability of random strength spawning in the map."
 set g_random_items_item_shield_probability 1 "Probability of random shield spawning in the map."
 set g_random_items_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning in the map."
@@ -93,13 +104,6 @@ set g_random_items_item_vaporizer_cells_probability 20 "Probability of random va
 set g_random_items_item_invisibility_probability 1 "Probability of random invisibility spawning in the map."
 set g_random_items_item_extralife_probability 1 "Probability of random extra life spawning in the map."
 set g_random_items_item_speed_probability 1 "Probability of random speed spawning in the map."
-set g_random_items_overkill_item_health_mega_probability 1 "Probability of random mega health spawning in the map during overkill."
-set g_random_items_overkill_item_armor_small_probability 10 "Probability of random small armor spawning in the map during overkill."
-set g_random_items_overkill_item_armor_medium_probability 4 "Probability of random medium armor spawning in the map during overkill."
-set g_random_items_overkill_item_armor_big_probability 2 "Probability of random big armor spawning in the map during overkill."
-set g_random_items_overkill_item_armor_mega_probability 1 "Probability of random mega armor spawning in the map during overkill."
-set g_random_items_overkill_weapon_hmg_probability 0.5 "Probability of random HMG spawning in the map during overkill."
-set g_random_items_overkill_weapon_rpc_probability 0.5 "Probability of random RPC spawning in the map during overkill."
 
 // Loot
 
@@ -139,6 +143,9 @@ set g_random_loot_weapon_shockwave_probability 0 "Probability of random shockwav
 set g_random_loot_weapon_arc_probability 0 "Probability of random arc spawning as loot."
 set g_random_loot_weapon_hook_probability 0 "Probability of random hook spawning as loot."
 set g_random_loot_weapon_tuba_probability 0 "Probability of random tuba spawning as loot."
+set g_random_loot_weapon_okshotgun_probability 0 "Probability of random overkill shotgun spawning as loot."
+set g_random_loot_weapon_okmachinegun_probability 0 "Probability of random overkill machinegun spawning as loot."
+set g_random_loot_weapon_oknex_probability 0 "Probability of random overkill nex spawning as loot."
 set g_random_loot_weapon_porto_probability 0 "Probability of random port-o-launch spawning as loot."
 set g_random_loot_weapon_fireball_probability 0 "Probability of random fireball spawning as loot."
 set g_random_loot_weapon_minelayer_probability 0 "Probability of random mine layer spawning as loot."
@@ -146,6 +153,11 @@ set g_random_loot_weapon_hlac_probability 0 "Probability of random HLAC spawning
 set g_random_loot_weapon_rifle_probability 0 "Probability of random rifle spawning as loot."
 set g_random_loot_weapon_seeker_probability 0 "Probability of random TAG seeker spawning as loot."
 set g_random_loot_weapon_vaporizer_probability 0 "Probability of random vaporizer spawning as loot."
+set g_random_loot_weapon_okshotgun_probability 0 "Probability of random overkill shotgun spawning as loot."
+set g_random_loot_weapon_okmachinegun_probability 0 "Probability of random overkill machinegun spawning as loot."
+set g_random_loot_weapon_oknex_probability 0 "Probability of random overkill nex spawning as loot."
+set g_random_loot_weapon_okhmg_probability 0 "Probability of random overkill HMG spawning as loot."
+set g_random_loot_weapon_okrpc_probability 0 "Probability of random overkill RPC spawning as loot."
 set g_random_loot_item_strength_probability 1 "Probability of random strength spawning as loot."
 set g_random_loot_item_shield_probability 1 "Probability of random shield spawning as loot."
 set g_random_loot_item_fuel_regen_probability 0 "Probability of random fuel regeneration spawning as loot."
@@ -154,10 +166,3 @@ set g_random_loot_item_vaporizer_cells_probability 20 "Probability of random vap
 set g_random_loot_item_invisibility_probability 1 "Probability of random invisibility spawning as loot."
 set g_random_loot_item_extralife_probability 1 "Probability of random extra life spawning as loot."
 set g_random_loot_item_speed_probability 1 "Probability of random speed spawning as loot."
-set g_random_loot_overkill_item_health_mega_probability 1 "Probability of random mega health spawning as loot during overkill."
-set g_random_loot_overkill_item_armor_small_probability 10 "Probability of random small armor spawning as loot during overkill."
-set g_random_loot_overkill_item_armor_medium_probability 4 "Probability of random medium armor spawning as loot during overkill."
-set g_random_loot_overkill_item_armor_big_probability 2 "Probability of random big armor spawning as loot during overkill."
-set g_random_loot_overkill_item_armor_mega_probability 1 "Probability of random mega armor spawning as loot during overkill."
-set g_random_loot_overkill_weapon_hmg_probability 1 "Probability of random HMG spawning as loot during overkill."
-set g_random_loot_overkill_weapon_rpc_probability 1 "Probability of random RPC spawning as loot during overkill."
index b37f01dcff30513ddf050bc88b2e93e3309aa76f..20740d9a86482beef2dfb4c14e375453ffc71ec0 100644 (file)
@@ -7,7 +7,7 @@ exec balance-xdf.cfg
 exec physicsXDF.cfg
 
 // general gameplay
-set g_jump_grunt 1 // make enemies even easier to hear when they're jumping around
+// set g_jump_grunt 1 // just no
 set g_shootfromcenter 1 // hit where you point at with the crosshair (almost so, no shooteye because it's really ugly)
 set g_balance_kill_antispam 0
 set g_forced_respawn 1
index f3607bb2f86cbc696f06eb2ffe46154b21f38279..eb682aa55ce7a2b2fb3880753146d9833e716a27 100644 (file)
@@ -24,3 +24,4 @@ set g_monsters 0
 set g_turrets 0
 set g_vehicles 0
 set sv_showspectators 0
+set sv_taunt 0
diff --git a/ruleset-nexuiz.cfg b/ruleset-nexuiz.cfg
new file mode 100644 (file)
index 0000000..7441942
--- /dev/null
@@ -0,0 +1,11 @@
+exec xonotic-server.cfg
+
+exec balance-nexuiz25.cfg
+exec physicsNexuiz26.cfg
+
+sv_gameplayfix_delayprojectiles 1
+
+// new toys to restore the weapons
+g_new_toys 1
+g_new_toys_autoreplace 0
+g_new_toys_use_pickupsound 0
index 49eb730c93d2c19c4a6b22eb3313ca547eace313..cc512e0c40dee4247caae0f4dcd920f52c6aa2e7 100644 (file)
@@ -5,6 +5,7 @@
 exec xonotic-server.cfg
 exec balance-overkill.cfg
 exec physicsOverkill.cfg
+exec randomitems-overkill.cfg
 
 // general gameplay
 set g_overkill 1
diff --git a/sound/misc/kill.ogg b/sound/misc/kill.ogg
deleted file mode 100644 (file)
index c1d3b8c..0000000
Binary files a/sound/misc/kill.ogg and /dev/null differ
diff --git a/sound/misc/kill.wav b/sound/misc/kill.wav
new file mode 100644 (file)
index 0000000..139ff57
Binary files /dev/null and b/sound/misc/kill.wav differ
index 2d7eb360d11e93c28bf6cc61e39da40513385f63..b8d865d4df142e4c9158e87853e4d9aac3f7ace6 100644 (file)
@@ -611,13 +611,13 @@ seta menu_mouse_speed 1 "speed multiplier for the mouse in the menu (does not af
 set menu_use_default_hostname 1
 alias sethostname "set menu_use_default_hostname 0; hostname $*"
 
-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 "vaporizer okhmg okrpc oknex vortex fireball mortar okmachinegun machinegun hagar rifle arc electro devastator crylink minelayer okshotgun 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 "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 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_weaponpriority0 "okrpc 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 oknex 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 oknex 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 okhmg oknex vortex rifle okmachinegun machinegun okshotgun 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 okshotgun 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"
@@ -675,7 +675,6 @@ set cl_effects_lightningarc_drift_end 0.1
 set cl_effects_lightningarc_branchfactor_start 0.25
 set cl_effects_lightningarc_branchfactor_add 0.1
 
-set menu_updatecheck 1 "check for updates"
 set menu_updatecheck_getpacks 1 "get update packs from update server"
 
 set cl_loddistance1 1024
@@ -834,11 +833,11 @@ alias menu_sync "menu_cmd sync"
 seta cl_items_nofade 0
 seta cl_animate_items 1
 seta cl_ghost_items 0.45 "enable ghosted items (when between 0 and 1, overrides the alpha value)"
-seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items, 0 0 0 leaves the color unchanged"
+seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)"
 seta cl_simple_items 0 "enable simple items (if server allows)"
 set cl_simpleitems_postfix "_luma" "posfix to add fo model name when simple items are enabled"
 set cl_fullbright_items 0 "enable fullbright items (if server allows, controlled by g_fullbrightitems)"
-set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
+set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0 (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)"
 set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
 
 seta cl_showspectators 0 "Show who's spectating you if server has sv_showspectators enabled"
index 7b6504d5162875ab34d7c6f61710366352c78605..13e38ebe049428928e1b4c57ce3f88125afb4df9 100644 (file)
@@ -43,7 +43,7 @@ set sv_timeout_number 2       "how many timeouts one player is allowed to call (gets r
 set sv_timeout_leadtime 4      "how long the players will be informed that a timeout was called before it starts, in seconds"
 set sv_timeout_resumetime 3    "how long the remaining timeout-time will be after a player called the timein command"
 
-set g_allow_oldvortexbeam 0 "If enabled, clients are allowed to use old v2.3 Vortex beam"
+set g_allow_oldvortexbeam 1 "If enabled, clients are allowed to use old v2.3 Vortex beam"
 
 set g_telefrags 1 "telefragging, i.e. killing someone who stands in the way of someone who is teleporting"
 set g_telefrags_teamplay 1 "never telefrag team mates"
@@ -116,6 +116,7 @@ set skill_auto 0    "when 1, \"skill\" gets adjusted to match the best player on th
 set bot_debug_tracewalk 0 "Enable visual indicators for short-term navigation. Green: Goal Reached / Yellow: Obstacle found / Red: Unsolvable obstacle found"
 set bot_debug_goalstack 0 "Visualize the current path that each bot is following. Use with as few bots as possible."
 set bot_wander_enable 1 "Have bots wander around if they are unable to reach any useful goal. Disable only for debugging purposes."
+set bot_typefrag 0 "Allow bots to shoot players while they're typing"
 // general bot AI cvars
 set bot_ai_thinkinterval 0.05
 set bot_ai_strategyinterval 7 "How often a new objective is chosen"
@@ -137,9 +138,9 @@ set bot_ai_keyboard_threshold 0.57
 set bot_ai_aimskill_offset 0.3 "Amount of error induced to the bots aim"
 set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
 set bot_ai_custom_weapon_priority_distances "300 850"  "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
-set bot_ai_custom_weapon_priority_far   "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun shockwave tuba minelayer"      "Desired weapons for far distances ordered by priority"
-set bot_ai_custom_weapon_priority_mid   "vaporizer devastator vortex fireball seeker mortar electro machinegun arc crylink hlac hagar shotgun shockwave blaster rifle tuba minelayer"  "Desired weapons for middle distances ordered by priority"
-set bot_ai_custom_weapon_priority_close "vaporizer vortex shotgun shockwave machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer"  "Desired weapons for close distances ordered by priority"
+set bot_ai_custom_weapon_priority_far   "vaporizer oknex vortex rifle electro devastator mortar hagar hlac crylink blaster okmachinegun machinegun fireball seeker okshotgun shotgun shockwave tuba minelayer" "Desired weapons for far distances ordered by priority"
+set bot_ai_custom_weapon_priority_mid   "vaporizer devastator oknex vortex fireball seeker mortar electro okmachinegun machinegun arc crylink hlac hagar okshotgun shotgun shockwave blaster rifle tuba minelayer"     "Desired weapons for middle distances ordered by priority"
+set bot_ai_custom_weapon_priority_close "vaporizer oknex vortex okshotgun shotgun shockwave okmachinegun machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer"     "Desired weapons for close distances ordered by priority"
 set bot_ai_weapon_combo 1      "Enable bots to do weapon combos"
 set bot_ai_weapon_combo_threshold 0.4  "Try to make a combo N seconds after the last attack"
 set bot_ai_friends_aware_pickup_radius "500"   "Bots will not pickup items if a team mate is this distance near the item"
@@ -169,6 +170,7 @@ set bot_ai_timeitems_minrespawndelay 25 "bots run to items with this minimum res
 set g_waypointeditor 0
 set g_waypointeditor_auto 0 "Automatically create waypoints for bots while playing; BEWARE, this currently creates too many of them"
 set g_waypointeditor_symmetrical 0 "Enable symmetrical editing of waypoints on symmetrical CTF maps (NOTE: it assumes that the map is perfectly symmetrical). 1: automatically determine origin of symmetry; -1: use custom origin (g_waypointeditor_symmetrical_origin); 2: automatically determine axis of symmetry; -2: use custom axis (g_waypointeditor_symmetrical_axis)"
+set g_waypointeditor_symmetrical_allowload 1 "Allow loading symmetry settings from waypoint files into g_waypointeditor_symmetrical* cvars on map start"
 set g_waypointeditor_symmetrical_origin "0 0" "Custom origin of symmetry (x y)"
 set g_waypointeditor_symmetrical_order 0 "if >= 2 apply rotational symmetry (around origin of symmetry) of this order, otherwise apply autodetected order of symmetry"
 set g_waypointeditor_symmetrical_axis "0 0" "Custom axis of symmetry (m q parameters of y = mx + q)"
@@ -178,7 +180,7 @@ set bot_vs_human 0  "Bots and humans play in different teams when set. positive v
 
 set g_spawnshieldtime 1 "number of seconds you are invincible after you spawned, this shield is lost after you fire"
 set g_spawnshield_blockdamage 1 "how much spawn shield protects you from damage (1 = full protection)"
-set g_antilag 2        "AntiLag (0 = no AntiLag, 1 = verified client side hit scan, 2 = server side hit scan in the past, 3 = unverified client side hit scan)"
+set g_antilag 2        "AntiLag (0 = no AntiLag, 1 = verified client side hit scan, 2 = server side hit scan in the past)"
 set g_antilag_nudge 0 "don't touch"
 set g_shootfromeye 0 "shots are fired from your eye/crosshair; visual gun position can still be influenced by cl_gunalign 1 and 2"
 set g_shootfromcenter 0 "weapon gets moved to the center, shots still come from the barrel of your weapon; visual gun position can still be influenced by cl_gunalign 1 and 2"
@@ -337,13 +339,13 @@ set g_maplist_votable_keeptwotime 15 "show only 2 options after this amount of t
 set g_maplist_votable_timeout 30       "timeout for the map voting; must be below 50 seconds!"
 set g_maplist_votable_suggestions 2
 set g_maplist_votable_suggestions_override_mostrecent 0
-set g_maplist_votable_nodetail 1       "nodetail only shows total count instead of all vote counts per map, so votes don't influence others that much"
+set g_maplist_votable_nodetail 0       "nodetail only shows total count instead of all vote counts per map, so votes don't influence others that much"
 set g_maplist_votable_abstain 0        "when 1, you can abstain from your vote"
 set g_maplist_votable_screenshot_dir "maps levelshots" "where to look for map screenshots"
 
 set sv_vote_gametype 0 "show a vote screen for gametypes before map vote screen"
 set sv_vote_gametype_keeptwotime 10 "show only 2 options after this amount of time during gametype vote screen"
-set sv_vote_gametype_options "dm ctf ca lms tdm ft"
+set sv_vote_gametype_options "dm tdm ctf"
 set sv_vote_gametype_timeout 20
 set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
 
@@ -555,3 +557,5 @@ set sv_simple_items 1 "allow or forbid client use of simple items"
 set sv_showspectators 1 "Show who's spectating who in the player info panel when client has cl_showspectators on. Shouldn't be used on competitive servers, also disable when watching a suspected cheater"
 
 set sv_damagetext 2 "<= 0: disabled, >= 1: visible to spectators, >= 2: visible to attacker, >= 3: all players see everyone's damage"
+
+set sv_showfps 5 "Show player's FPS counters in the scoreboard. This setting acts as a delay in seconds between updates"