]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into martin-t/bullet-trails
authorMartin Taibr <taibr.martin@gmail.com>
Mon, 2 Jul 2018 06:41:18 +0000 (08:41 +0200)
committerMartin Taibr <taibr.martin@gmail.com>
Mon, 2 Jul 2018 06:41:18 +0000 (08:41 +0200)
996 files changed:
.gitattributes
.gitlab-ci.yml
.tx/merge-base
CMakeLists.txt
_hud_common.cfg
_hud_descriptions.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-nexuiz25.cfg
balance-overkill.cfg
balance-samual.cfg
balance-xdf.cfg
balance-xonotic.cfg
balance-xpm.cfg
binds-xonotic.cfg
cmake/qcc.sh
commands.cfg
common.ast.po
common.be.po
common.bg.po
common.ca.po
common.cs.po
common.de.po
common.de_CH.po
common.el.po
common.en_AU.po
common.eo.po
common.es.po
common.es_MX.po
common.fi.po
common.fr.po
common.ga.po
common.gd.po
common.he.po
common.hu.po
common.it.po
common.ja_JP.po
common.jbo.po
common.kk@Cyrl.po
common.ko.po
common.kw.po
common.mk.po
common.ms.po [new file with mode: 0644]
common.nl.po
common.no.po
common.pl.po
common.pt.po
common.pt_BR.po [new file with mode: 0644]
common.ro.po
common.ru.po
common.sq.po
common.sr.po
common.sv.po
common.tr.po
common.uk.po
common.uz@Latn.po
common.zh_CN.po
common.zh_TW.po
crosshairs.cfg
default.cfg
defaultClient.cfg [deleted file]
defaultOverkill.cfg [deleted file]
defaultServer.cfg [deleted file]
defaultXDF.cfg [deleted file]
defaultXPM.cfg [deleted file]
defaultXonotic.cfg [deleted file]
effectinfo.txt
effects-high.cfg
effects-low.cfg
effects-med.cfg
effects-normal.cfg
effects-omg.cfg
effects-ultimate.cfg
effects-ultra.cfg
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]
gfx/menu/luma/skinvalues.txt
gfx/menu/luminos/skinvalues.txt
gfx/menu/wickedx/skinvalues.txt
gfx/menu/xaw/skinvalues.txt
hud_luma.cfg
languages.txt
models/items/a_rockets.md3
models/player/gak.iqm_0.txt
models/player/gakmasked.iqm_0.txt
models/player/ignismasked.iqm_0.txt
models/player/seraphinamasked.iqm_0.txt
mutators.cfg
physics.cfg
physicsX07.cfg
qcsrc/Makefile
qcsrc/client/_mod.inc
qcsrc/client/_mod.qh
qcsrc/client/announcer.qc
qcsrc/client/autocvars.qh
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/miscfunctions.qh
qcsrc/client/mutators/events.qh
qcsrc/client/player_skeleton.qc
qcsrc/client/player_skeleton.qh
qcsrc/client/resources.qc [new file with mode: 0644]
qcsrc/client/resources.qh [new file with mode: 0644]
qcsrc/client/shownames.qc
qcsrc/client/shownames.qh
qcsrc/client/teamradar.qc
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.qc
qcsrc/common/effects/qc/damageeffects.qh
qcsrc/common/effects/qc/globalsound.qc
qcsrc/common/effects/qc/lightningarc.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/nexball/sv_weapon.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_controlpoint.qc
qcsrc/common/gamemodes/gamemode/onslaught/cl_generator.qc
qcsrc/common/gamemodes/gamemode/onslaught/onslaught.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_controlpoint.qc
qcsrc/common/gamemodes/gamemode/onslaught/sv_generator.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.qc
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/mage.qh
qcsrc/common/monsters/monster/shambler.qc
qcsrc/common/monsters/monster/spider.qc
qcsrc/common/monsters/monster/spider.qh
qcsrc/common/monsters/monster/wyvern.qc
qcsrc/common/monsters/monster/wyvern.qh
qcsrc/common/monsters/monster/zombie.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/events.qh
qcsrc/common/mutators/mutator/_mod.inc
qcsrc/common/mutators/mutator/_mod.qh
qcsrc/common/mutators/mutator/bloodloss/sv_bloodloss.qc
qcsrc/common/mutators/mutator/breakablehook/sv_breakablehook.qc
qcsrc/common/mutators/mutator/buffs/buffs.qh
qcsrc/common/mutators/mutator/buffs/cl_buffs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qc
qcsrc/common/mutators/mutator/buffs/sv_buffs.qh
qcsrc/common/mutators/mutator/campcheck/sv_campcheck.qc
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/invincibleproj/sv_invincibleproj.qc
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/nades/net.qc
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.inc [new file with mode: 0644]
qcsrc/common/mutators/mutator/offhand_blaster/_mod.qh [new file with mode: 0644]
qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc [new file with mode: 0644]
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.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.qc [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/physical_items/sv_physical_items.qc
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/spawn_near_teammate/sv_spawn_near_teammate.qc
qcsrc/common/mutators/mutator/touchexplode/sv_touchexplode.qc
qcsrc/common/mutators/mutator/vampire/sv_vampire.qc
qcsrc/common/mutators/mutator/vampirehook/sv_vampirehook.qc
qcsrc/common/mutators/mutator/waypoints/all.inc
qcsrc/common/mutators/mutator/waypoints/all.qh
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/movetypes/movetypes.qc
qcsrc/common/physics/player.qc
qcsrc/common/physics/player.qh
qcsrc/common/playerstats.qc
qcsrc/common/resources.qh
qcsrc/common/scores.qh
qcsrc/common/sounds/sound.qh
qcsrc/common/state.qc
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/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/cl_turrets.qc
qcsrc/common/turrets/sv_turrets.qc
qcsrc/common/turrets/sv_turrets.qh
qcsrc/common/turrets/turret/ewheel.qc
qcsrc/common/turrets/turret/ewheel_weapon.qc
qcsrc/common/turrets/turret/ewheel_weapon.qh
qcsrc/common/turrets/turret/flac_weapon.qc
qcsrc/common/turrets/turret/flac_weapon.qh
qcsrc/common/turrets/turret/hellion_weapon.qc
qcsrc/common/turrets/turret/hellion_weapon.qh
qcsrc/common/turrets/turret/hk_weapon.qc
qcsrc/common/turrets/turret/hk_weapon.qh
qcsrc/common/turrets/turret/machinegun_weapon.qc
qcsrc/common/turrets/turret/machinegun_weapon.qh
qcsrc/common/turrets/turret/mlrs_weapon.qc
qcsrc/common/turrets/turret/mlrs_weapon.qh
qcsrc/common/turrets/turret/phaser_weapon.qc
qcsrc/common/turrets/turret/phaser_weapon.qh
qcsrc/common/turrets/turret/plasma.qc
qcsrc/common/turrets/turret/plasma_dual.qc
qcsrc/common/turrets/turret/plasma_dual.qh
qcsrc/common/turrets/turret/plasma_weapon.qc
qcsrc/common/turrets/turret/plasma_weapon.qh
qcsrc/common/turrets/turret/tesla_weapon.qc
qcsrc/common/turrets/turret/tesla_weapon.qh
qcsrc/common/turrets/turret/walker.qc
qcsrc/common/turrets/turret/walker_weapon.qc
qcsrc/common/turrets/turret/walker_weapon.qh
qcsrc/common/turrets/util.qc
qcsrc/common/turrets/util.qh
qcsrc/common/util.qc
qcsrc/common/util.qh
qcsrc/common/vehicles/cl_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qc
qcsrc/common/vehicles/sv_vehicles.qh
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/vehicles/vehicle/bumblebee_weapons.qc
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/vehicles/vehicle/racer_weapon.qc
qcsrc/common/vehicles/vehicle/racer_weapon.qh
qcsrc/common/vehicles/vehicle/raptor.qc
qcsrc/common/vehicles/vehicle/raptor_weapons.qc
qcsrc/common/vehicles/vehicle/raptor_weapons.qh
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/common/vehicles/vehicle/spiderbot_weapons.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/arc.qh
qcsrc/common/weapons/weapon/blaster.qc
qcsrc/common/weapons/weapon/blaster.qh
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/electro.qc
qcsrc/common/weapons/weapon/fireball.qc
qcsrc/common/weapons/weapon/hagar.qc
qcsrc/common/weapons/weapon/hlac.qc
qcsrc/common/weapons/weapon/hook.qc
qcsrc/common/weapons/weapon/machinegun.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/common/weapons/weapon/mortar.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/seeker.qc
qcsrc/common/weapons/weapon/shockwave.qc
qcsrc/common/weapons/weapon/shotgun.qc
qcsrc/common/weapons/weapon/tuba.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/cl_physics.qc
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/csqcmodel/cl_player.qc
qcsrc/lib/csqcmodel/common.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/client.qc
qcsrc/lib/warpzone/mathlib.qc
qcsrc/lib/warpzone/server.qc
qcsrc/menu/anim/animation.qc
qcsrc/menu/anim/animation.qh
qcsrc/menu/command/menu_cmd.qc
qcsrc/menu/draw.qc
qcsrc/menu/item.qc
qcsrc/menu/item.qh
qcsrc/menu/item/button.qc
qcsrc/menu/item/button.qh
qcsrc/menu/item/container.qc
qcsrc/menu/item/container.qh
qcsrc/menu/item/image.qc
qcsrc/menu/item/inputbox.qc
qcsrc/menu/item/inputbox.qh
qcsrc/menu/item/inputcontainer.qc
qcsrc/menu/item/inputcontainer.qh
qcsrc/menu/item/label.qc
qcsrc/menu/item/listbox.qc
qcsrc/menu/item/listbox.qh
qcsrc/menu/item/nexposee.qc
qcsrc/menu/item/nexposee.qh
qcsrc/menu/item/slider.qc
qcsrc/menu/item/slider.qh
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/skin-customizables.inc
qcsrc/menu/xonotic/_mod.inc
qcsrc/menu/xonotic/_mod.qh
qcsrc/menu/xonotic/campaign.qc
qcsrc/menu/xonotic/colorpicker.qc
qcsrc/menu/xonotic/colorpicker.qh
qcsrc/menu/xonotic/colorpicker_string.qc
qcsrc/menu/xonotic/colorpicker_string.qh
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/dialog_settings_effects.qc
qcsrc/menu/xonotic/dialog_settings_game.qc
qcsrc/menu/xonotic/dialog_settings_game.qh
qcsrc/menu/xonotic/dialog_settings_game_hud.qc
qcsrc/menu/xonotic/dialog_settings_game_view.qc
qcsrc/menu/xonotic/dialog_settings_misc_reset.qc
qcsrc/menu/xonotic/dialog_settings_user.qc
qcsrc/menu/xonotic/dialog_settings_video.qc
qcsrc/menu/xonotic/hudskinlist.qc
qcsrc/menu/xonotic/keybinder.qc
qcsrc/menu/xonotic/listbox.qh
qcsrc/menu/xonotic/mainwindow.qc
qcsrc/menu/xonotic/maplist.qc
qcsrc/menu/xonotic/picker.qc
qcsrc/menu/xonotic/picker.qh
qcsrc/menu/xonotic/playermodel.qc
qcsrc/menu/xonotic/screenshotimage.qc
qcsrc/menu/xonotic/screenshotimage.qh
qcsrc/menu/xonotic/screenshotlist.qc
qcsrc/menu/xonotic/scrollpanel.qc [new file with mode: 0644]
qcsrc/menu/xonotic/scrollpanel.qh [new file with mode: 0644]
qcsrc/menu/xonotic/serverlist.qc
qcsrc/menu/xonotic/serverlist.qh
qcsrc/menu/xonotic/slider.qh
qcsrc/menu/xonotic/slider_particles.qc
qcsrc/menu/xonotic/slider_picmip.qc
qcsrc/menu/xonotic/soundlist.qc
qcsrc/menu/xonotic/statslist.qc
qcsrc/menu/xonotic/textslider.qh
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/playerdemo.qc [deleted file]
qcsrc/server/playerdemo.qh [deleted file]
qcsrc/server/portals.qc
qcsrc/server/portals.qh
qcsrc/server/race.qc
qcsrc/server/race.qh
qcsrc/server/resources.qc
qcsrc/server/resources.qh
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/tests.qc
qcsrc/server/weapons/accuracy.qc
qcsrc/server/weapons/common.qc
qcsrc/server/weapons/common.qh
qcsrc/server/weapons/csqcprojectile.qc
qcsrc/server/weapons/hitplot.qc
qcsrc/server/weapons/hitplot.qh
qcsrc/server/weapons/selection.qc
qcsrc/server/weapons/spawning.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/weapons/tracing.qc
qcsrc/server/weapons/tracing.qh
qcsrc/server/weapons/weaponsystem.qc
qcsrc/tools/qcc.sh
randomitems-overkill.cfg [new file with mode: 0644]
randomitems-xonotic.cfg
ruleset-XDF.cfg [new file with mode: 0644]
ruleset-XPM.cfg [new file with mode: 0644]
ruleset-nexuiz.cfg [new file with mode: 0644]
ruleset-overkill.cfg [new file with mode: 0644]
ruleset-xonotic.cfg [new file with mode: 0644]
scripts/explosiveammo.shader [new file with mode: 0644]
sound/misc/kill.ogg [deleted file]
sound/misc/kill.wav [new file with mode: 0644]
textures/items/a_rocket_bottom.jpg [deleted file]
textures/items/a_rocket_box.jpg [deleted file]
textures/items/a_rocket_gre.jpg [deleted file]
textures/items/a_rocket_gre_glow.jpg [deleted file]
textures/items/a_rocket_roc.jpg [deleted file]
textures/items/a_rocket_roc_gloss.jpg [deleted file]
textures/items/a_rocket_roc_glow.jpg [deleted file]
textures/items/a_rocket_roc_norm.jpg [deleted file]
textures/items/a_rocket_tag.jpg [deleted file]
textures/items/explosiveammo.tga [new file with mode: 0644]
textures/items/explosiveammo_gloss.tga [new file with mode: 0644]
textures/items/explosiveammo_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_01.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_01_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_02.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_02_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_03.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_03_glow.tga [new file with mode: 0644]
textures/items/explosiveammo_icon_blank.tga [new file with mode: 0644]
textures/items/explosiveammo_norm.tga [new file with mode: 0644]
textures/items/explosiveammo_reflect.tga [new file with mode: 0644]
tx.sh
xonotic-client.cfg [new file with mode: 0644]
xonotic-common.cfg [new file with mode: 0644]
xonotic-server.cfg [new file with mode: 0644]

index 0a63b24a2fb6e01bb1ae1d4482111d47d612a0a1..14c10a42706a302437fa270fa570effabcf67fdd 100644 (file)
@@ -2,42 +2,42 @@
 *.inc linguist-language=C
 
 * -crlf
-*.0 -diff -crlf
+*.0 -crlf
 *.1 crlf=input
 *.3 crlf=input
-*.7z -diff -crlf
+*.7z -crlf
 *.ac crlf=input
-*.a -diff -crlf
+*.a -crlf
 *.afm crlf=input
 *.aft crlf=input
-*.ai -diff -crlf
+*.ai -crlf
 *.aliases crlf=input
 all crlf=input
 *.am crlf=input
 *.animinfo crlf=input
-*.aps -diff -crlf
-*.asc -diff -crlf
+*.aps -crlf
+*.asc -crlf
 *.ase -crlf
 *.bat -crlf
 *.bgs crlf=input
-*.blend1 -diff -crlf
-*.blend -diff -crlf
-blind_id -diff -crlf
-*.bmp -diff -crlf
+*.blend1 -crlf
+*.blend -crlf
+blind_id -crlf
+*.bmp -crlf
 branch-manager crlf=input
 *.brand crlf=input
 BSDmakefile crlf=input
 bsp2ent crlf=input
-*.bsp -diff -crlf
+*.bsp -crlf
 *.cache crlf=input
 *.cbp -crlf
-*.cbp -diff -crlf
+*.cbp -crlf
 *.c crlf=input
 *.cfg crlf=input
 *.cg crlf=input
 ChangeLog crlf=input
 CHANGES crlf=input
-cjpeg -diff -crlf
+cjpeg -crlf
 COMPILING crlf=input
 compress-texture crlf=input
 *.conf crlf=input
@@ -46,48 +46,48 @@ COPYING crlf=input
 *.cpp crlf=input
 create crlf=input
 *.cron crlf=input
-crypto-keygen-standalone -diff -crlf
+crypto-keygen-standalone -crlf
 *.css crlf=input
 *.cvswrappers crlf=input
 *.d0ir crlf=input
-*.d0pk -diff -crlf
+*.d0pk -crlf
 *.db crlf=input
 *.db.* crlf=input
 *.def2ent crlf=input
 *.default crlf=input
 *.def crlf=input
-*.dem -diff -crlf
+*.dem -crlf
 *.dev -crlf
-dir -diff -crlf
+dir -crlf
 *.directory crlf=input
-djpeg -diff -crlf
-*.dll -diff -crlf
-DOCS -diff -crlf
+djpeg -crlf
+*.dll -crlf
+DOCS -crlf
 *.dot crlf=input
 DoxyConfig crlf=input
 doxyfile crlf=input
 Doxyfile crlf=input
 *.doxygen crlf=input
-*.dpm -diff -crlf
+*.dpm -crlf
 *.dsp -crlf
 *.dsw -crlf
 *.dtd crlf=input
-*.dylib -diff -crlf
-empty -diff -crlf
+*.dylib -crlf
+empty -crlf
 *.EncoderPlugin crlf=input
 *.ent crlf=input
 etc_svc_git-daemon_run crlf=input
-*.flac -diff -crlf
-*.flp -diff -crlf
+*.flac -crlf
+*.flp -crlf
 *.form crlf=input
 *.framegroups crlf=input
-*.fteqccfail -diff -crlf
+*.fteqccfail -crlf
 *.game crlf=input
 *.gdb crlf=input
 gendox crlf=input
 gendoxfunctions crlf=input
 genDoxyfile crlf=input
-*.gif -diff -crlf
+*.gif -crlf
 *.gitattributes crlf=input
 git-branch-manager crlf=input
 git-filter-index crlf=input
@@ -112,30 +112,30 @@ GPL crlf=input
 *.htaccess crlf=input
 *.html crlf=input
 *.html-part crlf=input
-*.icns -diff -crlf
-*.ico -diff -crlf
+*.icns -crlf
+*.ico -crlf
 *.idl crlf=input
 *.idsoftware crlf=input
 *.inc crlf=input
 *.in crlf=input
-*.info-1 -diff -crlf
-*.info-2 -diff -crlf
-*.info -diff -crlf
+*.info-1 -crlf
+*.info-2 -crlf
+*.info -crlf
 *.inl crlf=input
 *.iOS crlf=input
-*.iqm -diff -crlf
+*.iqm -crlf
 *.java crlf=input
 *.jhm crlf=input
 *.jnlp crlf=input
-jpegtran -diff -crlf
-*.jpg -diff -crlf
+jpegtran -crlf
+*.jpg -crlf
 *.jsmooth crlf=input
 *.la crlf=input
 LGPL crlf=input
 LICENSE crlf=input
-*.lmp -diff -crlf
+*.lmp -crlf
 *.loaders crlf=input
-*.lso -diff -crlf
+*.lso -crlf
 *.m4 crlf=input
 makefile crlf=input
 Makefile crlf=input
@@ -143,81 +143,81 @@ makespr32 crlf=input
 *.map -crlf filter=mapclean
 *.mapinfo crlf=input
 *.m crlf=input
-*.md3 -diff -crlf
+*.md3 -crlf
 *.md5anim -crlf
 *.md5mesh -crlf
-*.mdl -diff -crlf
+*.mdl -crlf
 *.med crlf=input
 *.mf crlf=input
-*.mid -diff -crlf
+*.mid -crlf
 *.mk crlf=input
-*.mkdir -diff -crlf
-*.mmpz -diff -crlf
+*.mkdir -crlf
+*.mmpz -crlf
 *.modules crlf=input
-*.mp3 -diff -crlf
+*.mp3 -crlf
 *.nib -crlf
 *.obj -crlf
-OFFSETS -diff -crlf
-*.ogg -diff -crlf
+OFFSETS -crlf
+*.ogg -crlf
 *.options crlf=input
-*.otf -diff -crlf
+*.otf -crlf
 pangorc crlf=input
 *.part crlf=input
 *.patch crlf=input
 *.patchsets crlf=input
 *.pbxproj crlf=input
 *.pc crlf=input
-*.pfb -diff -crlf
-*.pfm -diff -crlf
+*.pfb -crlf
+*.pfm -crlf
 *.php crlf=input
-*.pk3 -diff -crlf
+*.pk3 -crlf
 PkgInfo crlf=input
 *.pl crlf=input
 *.plist crlf=input
 *.pm crlf=input
-*.png -diff -crlf
+*.png -crlf
 *.po crlf=input
-POSITIONS -diff -crlf
+POSITIONS -crlf
 *.pot crlf=input
 *.proj -crlf
 *.properties crlf=input
-*.psd -diff -crlf
+*.psd -crlf
 *.py crlf=input
 *.q3map1 crlf=input
 *.qc crlf=input
 *.qdt crlf=input
 *.qh crlf=input
-*.rar -diff -crlf
+*.rar -crlf
 *.rb crlf=input
 *.rc2 crlf=input
 *.rc -crlf
-rdjpgcom -diff -crlf
+rdjpgcom -crlf
 *.readme crlf=input
 README crlf=input
 *.rtlights crlf=input
 SCHEMA crlf=input
 *.scm crlf=input
 sdl-config crlf=input
-SDL -diff -crlf
-*.sfd -diff -crlf
+SDL -crlf
+*.sfd -crlf
 *.shader crlf=input
 *.sh crlf=input
 *.skin crlf=input
 *.sln -crlf
 *.sounds crlf=input
-*.sp2 -diff -crlf
-*.spr32 -diff -crlf
-*.spr -diff -crlf
+*.sp2 -crlf
+*.spr32 -crlf
+*.spr -crlf
 *.src crlf=input
 *.strings crlf=input
 strip crlf=input
-*.svg -diff -crlf
-*.TAB -diff -crlf
-*.tga -diff -crlf
-TMAP -diff -crlf
+*.svg -crlf
+*.TAB -crlf
+*.tga -crlf
+TMAP -crlf
 todo crlf=input
 TODO crlf=input
-*.ttf -diff -crlf
+*.ttf -crlf
 *.txt crlf=input
 *.txt.* crlf=input
 update-shaderlists crlf=input
@@ -226,12 +226,12 @@ update-shaderlists crlf=input
 *.vcxproj crlf=input
 versionbuilder crlf=input
 *.vhost crlf=input
-*.wav -diff -crlf
+*.wav -crlf
 *.waypoints crlf=input
 *.width crlf=input
 *.workspace -crlf
-wrjpgcom -diff -crlf
-*.xcf -diff -crlf
+wrjpgcom -crlf
+*.xcf -crlf
 *.xlink crlf=input
 *.xml crlf=input
 xonotic-map-compiler-autobuild crlf=input
@@ -239,7 +239,7 @@ xonotic-map-compiler crlf=input
 xonotic-map-screenshot crlf=input
 xonotic-osx-sdl crlf=input
 *.xpm crlf=input
-*.xrns -diff -crlf
-*.zip -diff -crlf
+*.xrns -crlf
+*.zip -crlf
 zipdiff crlf=input
-*.zym -diff -crlf
+*.zym -crlf
index bf43d891ded1096871f26547a3ce70d201afaee0..153b172f2bc2986096b04662f7ec1e011bfe617f 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=29a3c5d84ed37810d674c2c176b21e04
+    - EXPECT=b8f4fa5002af1f9f2d5ac3d1809ed188
     - 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 efe8262cb690e24a55eb2e0ea36348e8f7685b5d..ca7140deb4f39043ced90c760624d498c0f1b2a1 100644 (file)
@@ -1 +1 @@
-Sat Jul  8 07:24:47 CEST 2017
+Wed Jun 20 07:24:25 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 9a1654f83abd1a177f392a12fd6d785ce883a706..30e5a8bee9a8756fe9fafe883306260e1e4025aa 100644 (file)
@@ -62,7 +62,7 @@ seta hud_panel_weapons_label "" "1 = show number of weapon, 2 = show bound key o
 seta hud_panel_weapons_label_scale "" "scale of the weapon text label"
 seta hud_panel_weapons_accuracy "" "show accuracy color as the weapon icon background; colors can be configured with accuracy_color* cvars"
 seta hud_panel_weapons_ammo "" "show ammo as a status bar"
-seta hud_panel_weapons_onlyowned "" "show only owned weapons"
+seta hud_panel_weapons_onlyowned "" "show only owned weapons, set it to 2 to show only the held weapon"
 seta hud_panel_weapons_noncurrent_alpha "" "alpha of noncurrent weapons"
 seta hud_panel_weapons_noncurrent_scale "" "scale of noncurrent weapons, relative to the current weapon"
 seta hud_panel_weapons_selection_radius "" "number of weapons that get partially highlighted on each side of the currently selected weapon"
index 57d5d745df29da9d5b3dfc3cd8f0a7611bbeeeb5..d2ff12f6bc81cf2e13051600315fd4fb78f9c2ca 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,18 +251,18 @@ 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
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
-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 50
+set g_balance_crylink_secondary_edgedamage 15
+set g_balance_crylink_secondary_force -400
 set g_balance_crylink_secondary_joindelay 0
 set g_balance_crylink_secondary_joinexplode 0
 set g_balance_crylink_secondary_joinexplode_damage 0
@@ -275,11 +275,11 @@ 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_radius 70
+set g_balance_crylink_secondary_refire 0.8
+set g_balance_crylink_secondary_shots 1
 set g_balance_crylink_secondary_speed 3000
-set g_balance_crylink_secondary_spread 0.01
+set g_balance_crylink_secondary_spread 0
 set g_balance_crylink_secondary_spreadtype 1
 set g_balance_crylink_switchdelay_drop 0.2
 set g_balance_crylink_switchdelay_raise 0.2
@@ -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
@@ -456,7 +459,7 @@ 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 0
+set g_balance_vaporizer_weaponthrowable 1
 // }}}
 // {{{ #13: Grappling Hook
 set g_balance_hook_primary_ammo 5
@@ -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..1816f3f2e921ce4de93ceabcc2bad978861fcdd4 100644 (file)
@@ -322,7 +322,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
@@ -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..2e0e74aa3d7a993b7a97f1ac1b43f9ead3bbc797 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0
 set g_balance_crylink_secondary_bounces 0
@@ -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
@@ -390,7 +392,7 @@ set g_balance_devastator_guiderate 0
 set g_balance_devastator_guideratedelay 999
 set g_balance_devastator_guidestop 1
 set g_balance_devastator_health 30
-set g_balance_devastator_lifetime 100
+set g_balance_devastator_lifetime 20
 set g_balance_devastator_radius 110
 set g_balance_devastator_refire 0.9
 set g_balance_devastator_reload_ammo 0
@@ -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..5c6ace7abd7c6649f82b9998570e562154431a8e 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
@@ -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 63
+set g_balance_okmachinegun_primary_spread_add 0.012
+set g_balance_okmachinegun_primary_spread_max 0.05
+set g_balance_okmachinegun_primary_spread_min 0
+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..a5438d1b7c65a39ebe33f27da62dfb47e3c5e359 100644 (file)
@@ -256,7 +256,7 @@ set g_balance_crylink_primary_spread 0.08
 set g_balance_crylink_reload_ammo 0
 set g_balance_crylink_reload_time 2
 set g_balance_crylink_secondary 1
-set g_balance_crylink_secondary_ammo 2
+set g_balance_crylink_secondary_ammo 3
 set g_balance_crylink_secondary_animtime 0.2
 set g_balance_crylink_secondary_bouncedamagefactor 0.5
 set g_balance_crylink_secondary_bounces 0
@@ -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 28100182ea5fe41b0b1d028b020a93503228c9f5..1974ad6c811d130e2ad129424d24e5824b5135c9 100644 (file)
@@ -101,6 +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 1
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -131,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
@@ -198,6 +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 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
index 37099c1226dfa6ff992a97b74ef1217b91111b31..73c63df9b7277014a78e9be149afa5dd222e9a23 100644 (file)
@@ -101,6 +101,7 @@ set g_pickup_respawntime_powerup 120
 set g_pickup_respawntime_weapon 15
 set g_pickup_respawntime_superweapon 120
 set g_pickup_respawntime_ammo 15
+set g_pickup_respawntime_initial_random 2
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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.2
+set g_balance_powerup_invincible_takeforce 1
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 4
index 3a321ce53d461b2eca19452f5ad420975f9f2c12..18d862d747808a987ea24b1946a8eb5b39c11096 100644 (file)
@@ -101,6 +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 0
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
@@ -237,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 48c68d81be66e77c96cf8f55c417fd4b8565fe0f..9bcb976b60853f8dda7a81c66d22806766eaac02 100644 (file)
@@ -101,6 +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_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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.25 // only 1/4th damage is taken
+set g_balance_powerup_invincible_takeforce 1
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
index 562506283c44ad965d5d7d0f641a96a910aa11d3..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
@@ -101,6 +101,7 @@ set g_pickup_respawntime_powerup 0.1
 set g_pickup_respawntime_weapon 0.1
 set g_pickup_respawntime_superweapon 0.1
 set g_pickup_respawntime_ammo 0.1
+set g_pickup_respawntime_initial_random 2
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
index 32924a72d2cee7cca9d636330661abe49047f404..e19872454fa57d9b9cdfdd77ac6319763f390432 100644 (file)
@@ -101,6 +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 1
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
index 6901eda28a8c130622dc43db632f7475965050d3..5b8c67d2f5f9395af13f8fadde4a28c613a930e8 100644 (file)
@@ -101,6 +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 1
 set g_pickup_respawntimejitter_short 0
 set g_pickup_respawntimejitter_medium 0
 set g_pickup_respawntimejitter_long 0
@@ -198,6 +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 0.33
 set g_balance_powerup_invincible_time 30
 set g_balance_powerup_strength_damage 3
 set g_balance_powerup_strength_force 3
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 66ca90e2aa25dcb0aab5f659ba07b2c722b2e44b..b2edf84788332b7da31d681a318c19d6fd2e807d 100644 (file)
@@ -212,7 +212,6 @@ alias lockteams            "qc_cmd_sv     lockteams            ${* ?}" // Disabl
 alias make_mapinfo         "qc_cmd_sv     make_mapinfo         ${* ?}" // Automatically rebuild mapinfo files
 alias moveplayer           "qc_cmd_sv     moveplayer           ${* ?}" // Change the team/status of a player
 alias nospectators         "qc_cmd_sv     nospectators         ${* ?}" // Automatically remove spectators from a match
-alias playerdemo           "qc_cmd_sv     playerdemo           ${* ?}" // Control the ability to save demos of players
 alias printstats           "qc_cmd_sv     printstats           ${* ?}" // Dump eventlog player stats and other score information
 alias radarmap             "qc_cmd_sv     radarmap             ${* ?}" // Generate a radar image of the map
 alias reducematchtime      "qc_cmd_sv     reducematchtime      ${* ?}" // Decrease the timelimit value incrementally
@@ -302,6 +301,11 @@ set sv_vote_command_restriction_movetoyellow "1;"
 set sv_vote_command_restriction_movetopink "1;"
 set sv_vote_command_restriction_movetospec "1;"
 
+// help messages for votes that aren't implemeneted in the game code
+// examples used here are based on the usage output of implemented votes
+set sv_vote_command_help_restart "\nUsage:^3 vcall restart\n^7  No arguments required."
+set sv_vote_command_help_gotomap "\nUsage:^3 vcall gotomap mapname\n^7  Where 'mapname' is the name of the map to go to.\n  Type ^3lsmaps^7 to get a list of available maps to vote for."
+
 // =================================
 //  voting - server/command/vote.qc
 // =================================
@@ -317,7 +321,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)"
@@ -337,7 +341,7 @@ alias vabstain  "qc_cmd_cmd vote abstain"
 
 // aliases for both client and server
 alias vcall     "qc_cmd_svcmd vote call ${* ?}"
-alias vhelp     "qc_cmd_svcmd vote help"
+alias vhelp     "qc_cmd_svcmd vote help ${* ?}"
 alias vstatus   "qc_cmd_svcmd vote status"
 alias vstop     "qc_cmd_svcmd vote stop"
 
index b7d36a76dda307da245017df709b176630f6aa0f..53f62c26adab20665312e12e9cfe0b58808bd960 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-23 19:56+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Asturian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/ast/)\n"
@@ -2886,7 +2886,7 @@ msgstr "^BG%s%s^K1 comió'l cohete de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 573d5d10f9352b965cd5d659946906c22d002573..270efb79207009b69fae58227697ba33f8a744b7 100644 (file)
@@ -10,7 +10,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 20:14+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Belarusian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/be/)\n"
@@ -234,7 +234,7 @@ msgstr "Працягваць..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Чат"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2866,7 +2866,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9190,3 +9190,6 @@ msgstr "Колер каманды:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Уключыць панэль"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Чат"
index d3f3ed0dce7d1848b4d59062d90d5020e6bba4c0..233e9cac0a4d7d2b2d4025019a945087dc7013ec 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-20 00:10+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Bulgarian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/bg/)\n"
@@ -2912,8 +2912,8 @@ msgstr "^BG%s%s^K1 изяде ракета%s%s на ^BG%s^K1"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 бе твърде близо до ракета%s%s на ^BG%s^K1 "
+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
@@ -9278,3 +9278,6 @@ msgstr "Цвят на отбора:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Включване на панела"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 бе твърде близо до ракета%s%s на ^BG%s^K1 "
index c6a63212c9107eaf064a3406d2fc6703723fd2bc..6af876d891e489d0e8dc31df33df4e0e5ec10168 100644 (file)
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-20 04:19+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Catalan (http://www.transifex.com/team-xonotic/xonotic/"
 "language/ca/)\n"
@@ -2846,7 +2846,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 4fe3433a79b0c6e01dcc6552a964b31eed63a704..149ddc5c83009b35febcc87fd30218d524d06148 100644 (file)
@@ -3,24 +3,26 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# a b <taibr.martin@gmail.com>, 2017
+# 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-07-09 23:06+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
@@ -30,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."
@@ -58,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
@@ -68,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
@@ -83,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
@@ -122,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
@@ -2849,7 +2851,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 63a19e75af69f42e3a31d47841452d0a436457f0..f248daf3c81d93d5dc60c1ff11f49083d0c378a0 100644 (file)
@@ -24,8 +24,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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2017-09-23 19:12+0000\n"
+"Last-Translator: Wuzzy <almikes@aol.com>\n"
 "Language-Team: German (http://www.transifex.com/team-xonotic/xonotic/"
 "language/de/)\n"
 "Language: de\n"
@@ -92,7 +92,7 @@ msgstr "vorherige Waffe"
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
 msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
-msgstr "^1Benutze ^3%s^1 oder ^3%s^1 zum Ã¤ndern der Geschwindigkeit"
+msgstr "^1Benutze ^3%s^1 oder ^3%s^1 zum Ã\84ndern der Geschwindigkeit"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
@@ -131,7 +131,7 @@ msgstr "^1Du hast keine Leben mehr übrig"
 #: qcsrc/client/hud/panel/infomessages.qc:131
 #, c-format
 msgid "^1Press ^3%s^1 to join"
-msgstr "^1Drücke ^3%s^1 zum mitspielen"
+msgstr "^1Drücke ^3%s^1 zum Mitspielen"
 
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
@@ -185,7 +185,7 @@ msgstr "Die Teams sind unausgeglichen!"
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #, c-format
 msgid " Press ^3%s%s to adjust"
-msgstr " Drücke ^3%s%s zum anpassen"
+msgstr " Drücke ^3%s%s zum Anpassen"
 
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #: qcsrc/menu/xonotic/keybinder.qc:102
@@ -248,7 +248,7 @@ msgstr "Fortfahren…"
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -357,7 +357,7 @@ msgstr "Flaggenträger getötet (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "Flaggenträger getötet, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -370,11 +370,11 @@ msgstr "Flagge fallen gelassen, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "Waffe wegwerfen, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "Waffe fallen gelassen %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -2963,8 +2963,8 @@ msgstr "^BG%s%s^K1 hat ^BG%s^K1s Rakete gefressen%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 kam ^BG%s^K1s Rakete zu nahe%s%s"
+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
@@ -4123,7 +4123,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:788
 msgid "^F2Intruder detected, disabling shields!"
-msgstr ""
+msgstr "^F2Eindringling entdeckt, deaktiviere Schilde!"
 
 #: qcsrc/common/notifications/all.qh:188
 msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
@@ -5043,7 +5043,7 @@ msgstr "Ungarisch"
 
 #: qcsrc/menu/xonotic/credits.qc:231
 msgid "Irish"
-msgstr ""
+msgstr "Irisch"
 
 #: qcsrc/menu/xonotic/credits.qc:234
 msgid "Italian"
@@ -5075,7 +5075,7 @@ msgstr "Russisch"
 
 #: qcsrc/menu/xonotic/credits.qc:279
 msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Schottisch-Gälisch"
 
 #: qcsrc/menu/xonotic/credits.qc:282
 msgid "Serbian"
@@ -5293,7 +5293,7 @@ msgstr "Engine-Info-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
 msgid "Combine health and armor"
-msgstr "Kombiniere Gesundheit und Rüstung"
+msgstr "Gesundheit und Rüstung kombinieren"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
@@ -5331,7 +5331,7 @@ msgstr "Gesundheit und Rüstung tauschen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh:6
 msgid "Health/Armor Panel"
-msgstr "Gesundheit/Rüstungs-Panel"
+msgstr "Gesundheits-/Rüstungs-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
 msgid "Info messages:"
@@ -7791,7 +7791,7 @@ msgstr "Nur in Fadenkreuznähe"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
 msgid "Display health and armor"
-msgstr "Geunsdheit und Rüstung anzeigen"
+msgstr "Gesundheit und Rüstung anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:157
 msgid "Damage overlay:"
@@ -9501,3 +9501,9 @@ msgstr "Teamfarbe:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Panel aktivieren"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Chat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 kam ^BG%s^K1s Rakete zu nahe%s%s"
index ce4be4356e971c9d025d37c3f9397260bd56ce70..d5c87645f5f5fca211aba727c93dcf7eaa11a7e5 100644 (file)
@@ -24,8 +24,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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2017-09-23 19:12+0000\n"
+"Last-Translator: Wuzzy <almikes@aol.com>\n"
 "Language-Team: German (http://www.transifex.com/team-xonotic/xonotic/"
 "language/de/)\n"
 "Language: de\n"
@@ -92,7 +92,7 @@ msgstr "vorherige Waffe"
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
 msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
-msgstr "^1Benutze ^3%s^1 oder ^3%s^1 zum Ã¤ndern der Geschwindigkeit"
+msgstr "^1Benutze ^3%s^1 oder ^3%s^1 zum Ã\84ndern der Geschwindigkeit"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #, c-format
@@ -131,7 +131,7 @@ msgstr "^1Du hast keine Leben mehr übrig"
 #: qcsrc/client/hud/panel/infomessages.qc:131
 #, c-format
 msgid "^1Press ^3%s^1 to join"
-msgstr "^1Drücke ^3%s^1 zum mitspielen"
+msgstr "^1Drücke ^3%s^1 zum Mitspielen"
 
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
@@ -185,7 +185,7 @@ msgstr "Die Teams sind unausgeglichen!"
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #, c-format
 msgid " Press ^3%s%s to adjust"
-msgstr " Drücke ^3%s%s zum anpassen"
+msgstr " Drücke ^3%s%s zum Anpassen"
 
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #: qcsrc/menu/xonotic/keybinder.qc:102
@@ -248,7 +248,7 @@ msgstr "Fortfahren…"
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -357,7 +357,7 @@ msgstr "Flaggenträger getötet (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "Flaggenträger getötet, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -370,11 +370,11 @@ msgstr "Flagge fallen gelassen, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "Waffe wegwerfen, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "Waffe fallen gelassen %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -2963,8 +2963,8 @@ msgstr "^BG%s%s^K1 hat ^BG%s^K1s Rakete gefressen%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 kam ^BG%s^K1s Rakete zu nahe%s%s"
+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
@@ -4124,7 +4124,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:788
 msgid "^F2Intruder detected, disabling shields!"
-msgstr ""
+msgstr "^F2Eindringling entdeckt, deaktiviere Schilde!"
 
 #: qcsrc/common/notifications/all.qh:188
 msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
@@ -5044,7 +5044,7 @@ msgstr "Ungarisch"
 
 #: qcsrc/menu/xonotic/credits.qc:231
 msgid "Irish"
-msgstr ""
+msgstr "Irisch"
 
 #: qcsrc/menu/xonotic/credits.qc:234
 msgid "Italian"
@@ -5076,7 +5076,7 @@ msgstr "Russisch"
 
 #: qcsrc/menu/xonotic/credits.qc:279
 msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Schottisch-Gälisch"
 
 #: qcsrc/menu/xonotic/credits.qc:282
 msgid "Serbian"
@@ -5294,7 +5294,7 @@ msgstr "Engine-Info-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
 msgid "Combine health and armor"
-msgstr "Kombiniere Gesundheit und Rüstung"
+msgstr "Gesundheit und Rüstung kombinieren"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
@@ -5332,7 +5332,7 @@ msgstr "Gesundheit und Rüstung tauschen"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qh:6
 msgid "Health/Armor Panel"
-msgstr "Gesundheit/Rüstungs-Panel"
+msgstr "Gesundheits-/Rüstungs-Panel"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
 msgid "Info messages:"
@@ -7792,7 +7792,7 @@ msgstr "Nur in Fadenkreuznähe"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:152
 msgid "Display health and armor"
-msgstr "Geunsdheit und Rüstung anzeigen"
+msgstr "Gesundheit und Rüstung anzeigen"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:157
 msgid "Damage overlay:"
@@ -9502,3 +9502,9 @@ msgstr "Teamfarbe:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Panel aktivieren"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Chat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 kam ^BG%s^K1s Rakete zu nahe%s%s"
index 4be71747c8aed5d564230b9bee65272b8d694e9f..81195ec58cd9243a309a1fc4f2ee9916a8b558ec 100644 (file)
@@ -14,7 +14,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:54+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Greek (http://www.transifex.com/team-xonotic/xonotic/language/"
 "el/)\n"
@@ -2853,7 +2853,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 52653fe613d8530d8bb18e5a18feea91be4a1166..5c921689911761487664ecd30e2a2d9b058aebae 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-21 21:53+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: English (Australia) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/en_AU/)\n"
@@ -233,7 +233,7 @@ msgstr "Continue..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2907,8 +2907,8 @@ msgstr "^BG%s%s^K1 ate ^BG%s^K1's rocket%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+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
@@ -9273,3 +9273,9 @@ msgstr "Team Colour:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Enable panel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Chat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
index 298a775a2832273ca48fd48db781746c1ba0e3ac..d04c9328d23592b6f74da55314e3dbe1c2ec044e 100644 (file)
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-22 11:16+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Esperanto (http://www.transifex.com/team-xonotic/xonotic/"
 "language/eo/)\n"
@@ -2846,7 +2846,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 24d55d2755d21a02faaecf538edbcee63c6db4af..2d4350a35f0c325b54ada8cc8a5c7c072366b5a6 100644 (file)
@@ -8,14 +8,16 @@
 # Ari_tent <xonotic@outlook.com>, 2014
 # brunodeleo <bruno.laurenzano@gmail.com>, 2014
 # brunodeleo <bruno.laurenzano@gmail.com>, 2014
-# Starfire24680 <starfire24680@gmail.com>, 2017
+# starfire24680 <starfire24680@gmail.com>, 2017
 # roader_gentoo <ivanviso123@gmail.com>, 2014
 # kammy smb <kammysmb@gmail.com>, 2013
 # kammy smb <kammysmb@gmail.com>, 2013
 # 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
 # Yllelder, 2016
@@ -25,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-07-09 23:06+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"
@@ -47,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
@@ -96,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
@@ -111,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
@@ -247,7 +249,7 @@ msgstr "Continuar..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -356,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
@@ -369,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"
@@ -522,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
@@ -1117,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"
@@ -1131,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"
@@ -1250,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 ""
@@ -1678,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"
@@ -1813,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
@@ -1911,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
@@ -1931,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"
@@ -2084,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
@@ -2868,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"
@@ -2907,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
@@ -2959,8 +2961,8 @@ msgstr "^BG%s%s^K1 se comió el misil de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 se acercó demasiado al misil de ^BG%s^K1%s%s"
+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
@@ -3105,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
@@ -3214,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
@@ -4119,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"
@@ -4532,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"
@@ -5040,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"
@@ -5072,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"
@@ -7389,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)"
@@ -9465,3 +9467,9 @@ msgstr "Color del equipo:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Activar panel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Chat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 se acercó demasiado al misil de ^BG%s^K1%s%s"
index 0d6cbf874a7469e4dd88a84c7808cde088c28e16..71bbb2f1e225ade890454471df13413a78bde5ca 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Spanish (Mexico) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/es_MX/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 0780b4813a9f9f35c02e0dfe0a46b49afaffdcab..11b7c2c3394ba63d325664fb62142f0675831802 100644 (file)
@@ -10,7 +10,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:54+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Finnish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/fi/)\n"
@@ -2847,7 +2847,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 1b9b2a0f548951fd99af4455bb29a366617deeb1..84391e6114ea7ba0d9010dd5dee41ed46820185b 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: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-14 13:32+0000\n"
 "Last-Translator: Yannick Le Guen <leguen.yannick@gmail.com>\n"
 "Language-Team: French (http://www.transifex.com/team-xonotic/xonotic/"
 "language/fr/)\n"
@@ -245,7 +245,7 @@ msgstr "Continuer..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Tchat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2971,8 +2971,8 @@ msgstr "^BG%s%s^K1 a goûté à la roquette de ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 s'est approché trop près de la roquette de ^BG%s^K1%s%s"
+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
@@ -5173,7 +5173,7 @@ msgstr "Nom :"
 #: 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 "Pseudonyme utilisé pour vous reconnaître dans le jeu"
+msgstr "Nom sous lequel vous apparaîtrez dans le jeu"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:69
 msgid "Text language:"
@@ -6381,7 +6381,7 @@ msgstr "Les joueurs lâchent toutes leurs armes quand ils meurent"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
 msgid "Weapons stay after they are picked up"
-msgstr "Les armes restent où elles sont lorsqu'elles sont ramassées"
+msgstr "Les armes restent présentes après avoir été ramassées"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
 msgid "Regular (no arena)"
@@ -9499,3 +9499,9 @@ msgstr "Couleur de l'Équipe :"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Afficher le tableau de bord"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Tchat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 s'est approché trop près de la roquette de ^BG%s^K1%s%s"
index 8ba0c0bc5bf03fd20b74a22bcf84d4ebcc148982..14001ab9df18992a447faea36260fba0efb1eb27 100644 (file)
@@ -9,7 +9,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-23 14:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Irish (http://www.transifex.com/team-xonotic/xonotic/language/"
 "ga/)\n"
@@ -233,7 +233,7 @@ msgstr "Lean ar aghaidh..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Comhrá"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2849,7 +2849,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9157,3 +9157,6 @@ msgstr "Dath na Foirne:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Cumasaigh an painéal"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Comhrá"
index 2ff68b34b5b0a0ca039bb629d375cafeaf372405..d8a7b894d1a45f21b8a19837945fb2ee5c512ab0 100644 (file)
@@ -3,7 +3,7 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# GunChleoc, 2017
+# GunChleoc, 2017-2018
 # GunChleoc, 2017
 # GunChleoc, 2017
 msgid ""
@@ -11,8 +11,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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-02-28 14:07+0000\n"
+"Last-Translator: GunChleoc\n"
 "Language-Team: Gaelic, Scottish (http://www.transifex.com/team-xonotic/"
 "xonotic/language/gd/)\n"
 "Language: gd\n"
@@ -93,7 +93,7 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 msgid "drop weapon"
-msgstr ""
+msgstr "leig às an arm"
 
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/menu/xonotic/keybinder.qc:41
@@ -240,7 +240,7 @@ msgstr "Lean air adhart…"
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Cabadaich"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -1318,7 +1318,7 @@ msgstr "An geama làithreach"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:403
 msgid "Exit Menu"
-msgstr ""
+msgstr "Fàg an clàr-taice"
 
 #: qcsrc/common/minigames/cl_minigames_hud.qc:415
 #: qcsrc/menu/xonotic/dialog_multiplayer.qc:16
@@ -2860,7 +2860,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9168,3 +9168,6 @@ msgstr ""
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr ""
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Cabadaich"
index 11ccacf612c0b230f258f1e2ceb78870bf628af4..593e684a646c9714c90d90cbf02bf197633a270b 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Hebrew (http://www.transifex.com/team-xonotic/xonotic/"
 "language/he/)\n"
@@ -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
@@ -2845,7 +2846,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 2d8dd58f8c40729560dd458017519771be3667e7..605d51a6fc4ff7439c391bbe8ce2f429871ae3c7 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Hungarian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/hu/)\n"
@@ -2880,7 +2880,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 8c542b9da3050e71fb4901fae468a397e688ad1a..cefbf86272dfcf337ffe83c47e47daa8a6195f0a 100644 (file)
@@ -14,8 +14,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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
+"Last-Translator: Antonio <piuntn@gmail.com>\n"
 "Language-Team: Italian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/it/)\n"
 "Language: it\n"
@@ -235,7 +235,7 @@ msgstr "Continua..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -1626,7 +1626,7 @@ msgstr "Battaglia"
 
 #: qcsrc/common/mutators/mutator/buffs/buffs.qh:7
 msgid "Buff"
-msgstr "Colpetto"
+msgstr "Bonus"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
 msgid "Damage text"
@@ -2037,12 +2037,12 @@ msgstr "^F2Sarai spettatore il prossimo round"
 #: 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 è stato ucciso dal colpetto di ^BG%s^K1's ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 è stato ucciso dal bonus di ^BG%s^K1's ^BG%s^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 è stato segnato dal colpetto di ^BG%s^K1's ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 è stato segnato dal bonus di ^BG%s^K1's ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:275
 #, c-format
@@ -2590,24 +2590,24 @@ msgstr "^BGLa modalità Dio ti ha evitato %s unità di danno, imbroglione!"
 #: qcsrc/common/notifications/all.inc:377
 #, c-format
 msgid "^BG%s^BG got the %s^BG buff!"
-msgstr "^BG%s^BG ha il colpetto %s^BG!"
+msgstr "^BG%s^BG ha il bonus %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:378
 #, c-format
 msgid "^BG%s^BG lost the %s^BG buff!"
-msgstr "^BG%s^BG ha perso il colpetto %s^BG!"
+msgstr "^BG%s^BG ha perso il bonus %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:379
 #: qcsrc/common/notifications/all.inc:692
 #, c-format
 msgid "^BGYou dropped the %s^BG buff!"
-msgstr "^BGHai lasciato il colpetto %s^BG!"
+msgstr "^BGHai lasciato il bonus %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:380
 #: qcsrc/common/notifications/all.inc:693
 #, c-format
 msgid "^BGYou got the %s^BG buff!"
-msgstr "^BGHai preso il colpetto %s^BG!"
+msgstr "^BGHai preso il bonus %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:382
 #: qcsrc/common/notifications/all.inc:696
@@ -2967,8 +2967,8 @@ msgstr "^BG%s%s^K1 ha mangiato il razzo di ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 si è avvicinato troppo al razzo di ^BG%s^K1%s%s"
+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
@@ -6299,7 +6299,7 @@ msgstr "Jet pack"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:95
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:170
 msgid "Buffs"
-msgstr "Colpetti"
+msgstr "Bonus"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:97
 msgid "Overkill"
@@ -9490,3 +9490,9 @@ msgstr "Colore squadra:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Abilita pannello"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Chat"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 si è avvicinato troppo al razzo di ^BG%s^K1%s%s"
index e3e973291622afc4215af59b9ff545d5361704b4..5597171eab31ddaede4af0bd8bbd5707c2062b47 100644 (file)
@@ -10,7 +10,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-23 20:38+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Japanese (Japan) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/ja_JP/)\n"
@@ -2847,7 +2847,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index b9ef45c2429241bae32fd126bb37607803ce7227..dc7f687b782c2276ce78981ef186f1b1a703f3f0 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Lojban (http://www.transifex.com/team-xonotic/xonotic/"
 "language/jbo/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index ffc38825b357a2c5f26d9f6a7561caa6053ecb12..6738cdd3ec480efde886411cf0b8458e485f9cd8 100644 (file)
@@ -12,15 +12,15 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-22 14:22+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Kazakh (Cyrillic) (http://www.transifex.com/team-xonotic/"
-"xonotic/language/kk@Cyrl/)\n"
+"xonotic/language/kk%40Cyrl/)\n"
 "Language: kk@Cyrl\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"
+"Plural-Forms: nplurals=2; plural=(n!=1);\n"
 
 #: qcsrc/client/hud/hud_config.qc:239
 #, c-format
@@ -2849,7 +2849,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index dfc4ea454a976c1d17adf38c7b4a7d6571e95278..4d65b27123a4b82371ab71c2651b0b7184ef1083 100644 (file)
@@ -3,15 +3,18 @@
 # This file is distributed under the same license as the PACKAGE package.
 #
 # Translators:
-# Kuff Lee <coughingmouse@gmail.com>, 2016
-# Kuff Lee <coughingmouse@gmail.com>, 2016-2017
+# Jisoo Lim <liminj0719@gmail.com>, 2017
+# Kyf Lee <coughingmouse@gmail.com>, 2016
+# Kyf Lee <coughingmouse@gmail.com>, 2016-2017
+# Kyf Lee <coughingmouse@gmail.com>, 2016-2017
+# Kyf Lee <coughingmouse@gmail.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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2017-12-05 10:37+0000\n"
+"Last-Translator: Jisoo Lim <liminj0719@gmail.com>\n"
 "Language-Team: Korean (http://www.transifex.com/team-xonotic/xonotic/"
 "language/ko/)\n"
 "Language: ko\n"
@@ -231,7 +234,7 @@ msgstr "계속..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "채팅"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -260,31 +263,31 @@ msgstr "QMCMD^팀 채팅"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:803
 msgid "QMCMD^quad soon"
-msgstr ""
+msgstr "쿼드는 머지않아"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item %x^7 (l:%y^7)"
-msgstr ""
+msgstr "QMCMD^가져갈 수 있는 아이템 %x^7 (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:804
 msgid "QMCMD^free item, icon"
-msgstr ""
+msgstr "QMCMD^가져갈 수 있는 아이템, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^아이템 가져감 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:805
 msgid "QMCMD^took item, icon"
-msgstr ""
+msgstr "QMCMD^아이템 가져감, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:806
 msgid "QMCMD^negative"
-msgstr ""
+msgstr "QMCMD^아님"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:807
 msgid "QMCMD^positive"
-msgstr ""
+msgstr "QMCMD^맞음"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:808
 msgid "QMCMD^need help (l:%l^7) (h:%h^7 a:%a^7 w:%w^7)"
@@ -340,36 +343,36 @@ msgstr "QMCMD^죽인 깃발 운반자 (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "QMCMD^죽인 깃발 운반자, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
 msgid "QMCMD^dropped flag (l:%d^7)"
-msgstr ""
+msgstr "QMCMD^깃발 떨어뜨림 (l:%d^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 msgid "QMCMD^dropped flag, icon"
-msgstr ""
+msgstr "QMCMD^깃발 떨어뜨림, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "QMCMD^무기 떨구기, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^무기 떨어뜨림 %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
-msgstr ""
+msgstr "QMCMD^깃발/열쇠 떨어뜨리기, 아이콘"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^깃발/열쇠 떨어뜨림 %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:821
 msgid "QMCMD^Send private message to"
-msgstr ""
+msgstr "QMCMD^비밀 메세지 받는 사람:"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:823
 #: qcsrc/client/hud/panel/quickmenu.qc:860
@@ -403,7 +406,7 @@ msgstr "QMCMD^FPS"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:830
 msgid "QMCMD^Net graph"
-msgstr ""
+msgstr "넷차트"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:833
 #: qcsrc/client/hud/panel/quickmenu.qc:836
@@ -555,7 +558,7 @@ msgstr "SCO^파괴"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:84
 msgid "SCO^damage"
-msgstr ""
+msgstr "SCO^데미지"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:85
 msgid "SCO^dmgtaken"
@@ -583,15 +586,15 @@ msgstr "SCO^열쇠 운반자 킬"
 
 #: 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"
@@ -607,7 +610,7 @@ msgstr "SCO^목숨"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:97
 msgid "SCO^losses"
-msgstr ""
+msgstr "SCO^패배"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:98
 msgid "SCO^name"
@@ -615,7 +618,7 @@ msgstr "SCO^이름"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:99
 msgid "SCO^sum"
-msgstr ""
+msgstr "SCO^합"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:100
 msgid "SCO^nick"
@@ -627,7 +630,7 @@ msgstr "SCO^목표"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:102
 msgid "SCO^pickups"
-msgstr ""
+msgstr "SCO^픽업"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:103
 msgid "SCO^ping"
@@ -635,11 +638,11 @@ msgstr "SCO^핑"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:104
 msgid "SCO^pl"
-msgstr ""
+msgstr "SCO^패킷 손실"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:105
 msgid "SCO^pushes"
-msgstr ""
+msgstr "SCO^밀어냄"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:106
 msgid "SCO^rank"
@@ -655,7 +658,7 @@ 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"
@@ -667,7 +670,7 @@ msgstr "SCO^자살"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:112
 msgid "SCO^takes"
-msgstr ""
+msgstr "SCO^가져감"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:113
 msgid "SCO^ticks"
@@ -2625,7 +2628,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:405
 #, c-format
 msgid "^BG%s^F3 forfeited"
-msgstr ""
+msgstr "^BG%s^F3는 몰수당하다"
 
 #: qcsrc/common/notifications/all.inc:406
 #, c-format
@@ -2697,7 +2700,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:425
 #, c-format
 msgid "^BG%s^F3 is now spectating"
-msgstr ""
+msgstr "^BG%s^F3는 지켜보다"
 
 #: qcsrc/common/notifications/all.inc:427
 #, c-format
@@ -2858,7 +2861,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -3984,11 +3987,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.qh:410
 msgid "point"
-msgstr ""
+msgstr "포인트"
 
 #: qcsrc/common/notifications/all.qh:410
 msgid "points"
-msgstr ""
+msgstr "포인트"
 
 #: qcsrc/common/notifications/all.qh:419
 msgid "drop flag"
@@ -4015,7 +4018,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.qh:444
 msgid "TRIPLE FRAG! "
-msgstr ""
+msgstr "트리플 킬!"
 
 #: qcsrc/common/notifications/all.qh:445
 #, c-format
@@ -4029,7 +4032,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.qh:445
 msgid "RAGE! "
-msgstr ""
+msgstr "레이지!"
 
 #: qcsrc/common/notifications/all.qh:446
 #, c-format
@@ -4043,7 +4046,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.qh:446
 msgid "MASSACRE! "
-msgstr ""
+msgstr "대학살!"
 
 #: qcsrc/common/notifications/all.qh:447
 #, c-format
@@ -4276,141 +4279,141 @@ msgstr ""
 
 #: qcsrc/common/turrets/turret.qh:11
 msgid "Turret"
-msgstr ""
+msgstr "터렛"
 
 #: qcsrc/common/turrets/turret/ewheel.qh:15
 msgid "eWheel Turret"
-msgstr ""
+msgstr "eWheel 터렛"
 
 #: qcsrc/common/turrets/turret/ewheel_weapon.qh:7
 msgid "eWheel"
-msgstr ""
+msgstr "eWheel"
 
 #: qcsrc/common/turrets/turret/flac.qh:13
 msgid "FLAC Cannon"
-msgstr ""
+msgstr "FLAC 캐논"
 
 #: qcsrc/common/turrets/turret/flac_weapon.qh:7
 msgid "FLAC"
-msgstr ""
+msgstr "FLAC"
 
 #: qcsrc/common/turrets/turret/fusionreactor.qh:11
 msgid "Fusion Reactor"
-msgstr ""
+msgstr "퓨전 리액터"
 
 #: qcsrc/common/turrets/turret/hellion.qh:13
 msgid "Hellion Missile Turret"
-msgstr ""
+msgstr "헬리온 유도탄 터렛"
 
 #: qcsrc/common/turrets/turret/hellion_weapon.qh:7
 msgid "Hellion"
-msgstr ""
+msgstr "헬리온"
 
 #: qcsrc/common/turrets/turret/hk.qh:15
 msgid "Hunter-Killer Turret"
-msgstr ""
+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"
-msgstr ""
+msgstr "기관총"
 
 #: qcsrc/common/turrets/turret/mlrs.qh:13
 msgid "MLRS Turret"
-msgstr ""
+msgstr "MLRS 터렛"
 
 #: 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
 msgid "Tesla Coil"
-msgstr ""
+msgstr "테슬라 코일"
 
 #: qcsrc/common/turrets/turret/walker.qh:15
 msgid "Walker Turret"
-msgstr ""
+msgstr "걷기 터렛"
 
 #: qcsrc/common/turrets/turret/walker_weapon.qh:7
 msgid "Walker"
-msgstr ""
+msgstr "걷기"
 
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 #, c-format
 msgid "Press %s"
-msgstr ""
+msgstr "%s는 누릅니다"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
 msgid "No right gunner!"
-msgstr ""
+msgstr "옳은 사수없어요!"
 
 #: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
 msgid "No left gunner!"
-msgstr ""
+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"
-msgstr ""
+msgstr "라프토 캐논"
 
 #: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:17
 msgid "Raptor bomb"
-msgstr ""
+msgstr "라프토 폭탄"
 
 #: qcsrc/common/vehicles/vehicle/raptor_weapons.qh:25
 msgid "Raptor flare"
-msgstr ""
+msgstr "라프토 신호탄"
 
 #: qcsrc/common/vehicles/vehicle/spiderbot.qh:19
 msgid "Spiderbot"
-msgstr ""
+msgstr "거미봇"
 
 #: qcsrc/common/weapons/all.qh:78
 msgid "Weapons dump command only works with sv_cmd.\n"
@@ -4821,139 +4824,139 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/credits.qc:151
 msgid "Asturian"
-msgstr ""
+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"
-msgstr ""
+msgstr "프랑스어"
 
 #: qcsrc/menu/xonotic/credits.qc:210
 msgid "German"
-msgstr ""
+msgstr "독일어"
 
 #: qcsrc/menu/xonotic/credits.qc:221
 msgid "Greek"
-msgstr ""
+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"
-msgstr ""
+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"
-msgstr ""
+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"
-msgstr ""
+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"
-msgstr ""
+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"
-msgstr ""
+msgstr "비밀"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:95
 msgid "engine setting"
-msgstr ""
+msgstr "엔진 설정"
 
 #: qcsrc/menu/xonotic/cvarlist.qc:97
 msgid "read only"
-msgstr ""
+msgstr "읽기 전용"
 
 #: qcsrc/menu/xonotic/dialog_credits.qc:13
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:38
@@ -4962,11 +4965,11 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:75
 #: qcsrc/menu/xonotic/dialog_singleplayer_winner.qc:14
 msgid "OK"
-msgstr ""
+msgstr "OK"
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:7
 msgid "Credits"
-msgstr ""
+msgstr "크레딧"
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:8
 msgid "The Xonotic credits"
@@ -4984,12 +4987,12 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:45
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:28
 msgid "Name:"
-msgstr ""
+msgstr "이름:"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:53
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:60
 msgid "Name under which you will appear in the game"
-msgstr ""
+msgstr "게임 내 이름"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:69
 msgid "Text language:"
@@ -5003,23 +5006,23 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:84
 msgid "Undecided"
-msgstr ""
+msgstr "미정"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qc:88
 msgid "Save settings"
-msgstr ""
+msgstr "저장 설정"
 
 #: qcsrc/menu/xonotic/dialog_firstrun.qh:6
 msgid "Welcome"
-msgstr ""
+msgstr "환영합니다"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
 msgid "Ammunition display:"
-msgstr ""
+msgstr "탄약 표시:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:19
 msgid "Show only current ammo type"
-msgstr ""
+msgstr "현재 탄약 종류만 보이기"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:22
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:44
@@ -5034,7 +5037,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:30
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:24
 msgid "Align icon:"
-msgstr ""
+msgstr "아이콘 정렬하기:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:31
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:30
@@ -5045,7 +5048,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:33
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:18
 msgid "Left"
-msgstr ""
+msgstr "왼쪽으로"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:32
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:32
@@ -5056,7 +5059,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:34
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:20
 msgid "Right"
-msgstr ""
+msgstr "오른쪽으로"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qh:6
 msgid "Ammo Panel"
@@ -5064,15 +5067,15 @@ msgstr "탄환 제어반"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:17
 msgid "Message duration:"
-msgstr ""
+msgstr "메세지 표시 시간"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:21
 msgid "Fade time:"
-msgstr ""
+msgstr "사라지는 시간:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:25
 msgid "Flip messages order"
-msgstr ""
+msgstr "메시지 순서 뒤바꾸기"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:27
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:15
@@ -5083,11 +5086,11 @@ msgstr "텍스트 배열:"
 #: qcsrc/menu/xonotic/dialog_hudpanel_quickmenu.qc:19
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:71
 msgid "Center"
-msgstr ""
+msgstr "중앙으로"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:35
 msgid "Font scale:"
-msgstr ""
+msgstr "글자 크기:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qh:6
 msgid "Centerprint Panel"
@@ -5095,19 +5098,19 @@ msgstr "중심점 제어반"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
 msgid "Chat entries:"
-msgstr ""
+msgstr "체팅 입력:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
 msgid "Chat size:"
-msgstr ""
+msgstr "체팅 사이즈:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
 msgid "Chat lifetime:"
-msgstr ""
+msgstr "체팅창 시간:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
 msgid "Chat beep sound"
-msgstr ""
+msgstr "체팅 알림 소리"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
 msgid "Chat Panel"
@@ -5115,11 +5118,11 @@ msgstr "채팅 제어반"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
 msgid "Engine info:"
-msgstr ""
+msgstr "엔진 정보:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:17
 msgid "Use an averaging algorithm for fps"
-msgstr ""
+msgstr "fps에 평균 알고리즘 사용하기"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qh:6
 msgid "Engine Info Panel"
@@ -5127,37 +5130,37 @@ msgstr "엔진 정보 제어반"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
 msgid "Combine health and armor"
-msgstr ""
+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 ""
+msgstr "상태 창 켜기"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:19
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:17
 msgid "Status bar alignment:"
-msgstr ""
+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 ""
+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 ""
+msgstr "바깥쪽으로"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:32
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:30
 msgid "Icon alignment:"
-msgstr ""
+msgstr "아이콘 정렬:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:40
 msgid "Flip health and armor positions"
@@ -5169,7 +5172,7 @@ msgstr "체력/보호구 제어반"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
 msgid "Info messages:"
-msgstr ""
+msgstr "정보 메세지:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:17
 msgid "Flip align"
@@ -6352,7 +6355,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:217
 msgid "Hostname:"
-msgstr ""
+msgstr "호스트이름:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:231
 msgid "Gametype:"
@@ -6360,19 +6363,19 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:236
 msgid "Map:"
-msgstr ""
+msgstr "맵:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:241
 msgid "Mod:"
-msgstr ""
+msgstr "모드:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:246
 msgid "Version:"
-msgstr ""
+msgstr "버전:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:251
 msgid "Settings:"
-msgstr ""
+msgstr "설정:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:258
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:290
@@ -6381,7 +6384,7 @@ msgstr "플레이어:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:263
 msgid "Bots:"
-msgstr ""
+msgstr "봇:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:268
 msgid "Free slots:"
@@ -6393,11 +6396,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:279
 msgid "ID:"
-msgstr ""
+msgstr "아이디:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:284
 msgid "Key:"
-msgstr ""
+msgstr "키:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qh:7
 msgid "Server Information"
@@ -6405,7 +6408,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:25
 msgid "Demos"
-msgstr ""
+msgstr "데모들"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:26
 msgid "Screenshots"
@@ -6429,7 +6432,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qc:62
 msgid "DEMO^Play"
-msgstr ""
+msgstr "데모^플레이"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:13
 msgid "Playing a demo will disconnect you from the current match."
@@ -6467,7 +6470,7 @@ 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"
@@ -6511,7 +6514,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:139
 msgid "Reset"
-msgstr ""
+msgstr "리셋"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot_viewer.qc:144
 msgid "Previous"
@@ -6536,7 +6539,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
 msgid "Name"
-msgstr ""
+msgstr "이름"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:77
 msgid "Model"
@@ -6564,7 +6567,7 @@ msgstr "플레이어 통계에서 당신의 별칭을 이용하는 걸 허용하
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
 msgid "Country"
-msgstr ""
+msgstr "국가"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
 msgid "Gender:"
@@ -6578,24 +6581,24 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:162
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:172
 msgid "Female"
-msgstr ""
+msgstr "음성"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:163
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:173
 msgid "Male"
-msgstr ""
+msgstr "남성"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:166
 msgid "Gender"
-msgstr ""
+msgstr "성별"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:11
 msgid "Are you sure you want to quit?"
-msgstr ""
+msgstr "게임에서 나가시겠습니까?"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:15
 msgid "Back to work..."
-msgstr ""
+msgstr "직장으로 복귀하다..."
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:17
 msgid "I got some more fragging to do!"
@@ -6603,23 +6606,23 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_quit.qh:7
 msgid "Quit the game"
-msgstr ""
+msgstr "게임이 종료됩니다"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:15
 msgid "Model:"
-msgstr ""
+msgstr "모델:"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:21
 msgid "Remove *"
-msgstr ""
+msgstr "삭제 *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:23
 msgid "Copy *"
-msgstr ""
+msgstr "복사 *"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:24
 msgid "Paste"
-msgstr ""
+msgstr "붙여넣기"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:26
 msgid "Bone:"
@@ -6735,32 +6738,32 @@ msgstr "비디오"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:19
 msgid "Effects"
-msgstr ""
+msgstr "그래픽"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:20
 msgid "Audio"
-msgstr ""
+msgstr "소리"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:22
 msgid "Game"
-msgstr ""
+msgstr "게임"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:23
 msgid "Input"
-msgstr ""
+msgstr "입력"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:24
 msgid "User"
-msgstr ""
+msgstr "유저"
 
 #: qcsrc/menu/xonotic/dialog_settings.qc:25
 #: qcsrc/menu/xonotic/keybinder.qc:105
 msgid "Misc"
-msgstr ""
+msgstr "다른"
 
 #: qcsrc/menu/xonotic/dialog_settings.qh:6
 msgid "Settings"
-msgstr ""
+msgstr "설정"
 
 #: qcsrc/menu/xonotic/dialog_settings.qh:7
 msgid "Change the game settings"
@@ -6768,7 +6771,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
 msgid "Master:"
-msgstr ""
+msgstr "마스터:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:35
 msgid "Music:"
@@ -6800,11 +6803,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:85
 msgid "Voice:"
-msgstr ""
+msgstr "음성:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:93
 msgid "Weapons:"
-msgstr ""
+msgstr "무기들:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:99
 msgid "New style sound attenuation"
@@ -6824,39 +6827,39 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:108
 msgid "8 kHz"
-msgstr ""
+msgstr "8 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:109
 msgid "11.025 kHz"
-msgstr ""
+msgstr "11.025 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:110
 msgid "16 kHz"
-msgstr ""
+msgstr "16 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:111
 msgid "22.05 kHz"
-msgstr ""
+msgstr "22.05 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:112
 msgid "24 kHz"
-msgstr ""
+msgstr "24 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:113
 msgid "32 kHz"
-msgstr ""
+msgstr "32 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:114
 msgid "44.1 kHz"
-msgstr ""
+msgstr "44.1 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:115
 msgid "48 kHz"
-msgstr ""
+msgstr "48 kHz"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:119
 msgid "Channels:"
-msgstr ""
+msgstr "채널:"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:121
 msgid "Number of channels for the sound output"
@@ -6864,35 +6867,35 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:122
 msgid "Mono"
-msgstr ""
+msgstr "모노"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:123
 msgid "Stereo"
-msgstr ""
+msgstr "스테레오"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:124
 msgid "2.1"
-msgstr ""
+msgstr "2.1"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:125
 msgid "4"
-msgstr ""
+msgstr "4"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:126
 msgid "5"
-msgstr ""
+msgstr "5"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:127
 msgid "5.1"
-msgstr ""
+msgstr "5.1"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:128
 msgid "6.1"
-msgstr ""
+msgstr "6.1"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:129
 msgid "7.1"
-msgstr ""
+msgstr "7.1"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:134
 msgid "Swap stereo output channels"
@@ -7214,7 +7217,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:176
 msgid "Time:"
-msgstr ""
+msgstr "시간:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:179
 msgid "Time in seconds before decals fade away (default: 2)"
@@ -7267,7 +7270,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:201
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:207
 msgid "Shadows"
-msgstr ""
+msgstr "샤도우"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:202
 msgid "Enable rendering of shadows from dynamic lights (default: disabled)"
@@ -7561,7 +7564,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qh:7
 msgid "HUD"
-msgstr ""
+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."
@@ -7683,7 +7686,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
 msgid "Messages"
-msgstr ""
+msgstr "메시지"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
 msgid "Items"
@@ -7724,7 +7727,7 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:49
 #: qcsrc/menu/xonotic/serverlist.qc:767
 msgid "Players"
-msgstr ""
+msgstr "플레이어"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:51
 msgid "Force player models to mine"
@@ -8053,7 +8056,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qc:40
 msgid "Cancel"
-msgstr ""
+msgstr "취소"
 
 #: qcsrc/menu/xonotic/dialog_settings_input_userbind.qh:7
 msgid "User defined key bind"
@@ -8062,25 +8065,25 @@ msgstr ""
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:11
 #, c-format
 msgid "%d fps"
-msgstr ""
+msgstr "%d fps"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:12
 #, c-format
 msgid "%d KB/s"
-msgstr ""
+msgstr "%d KB/s"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:13
 #, c-format
 msgid "%d MB/s"
-msgstr ""
+msgstr "%d MB/s"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:27
 msgid "Network"
-msgstr ""
+msgstr "네트워크"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:29
 msgid "Client UDP port:"
-msgstr ""
+msgstr "클라이언트 UDP 포트:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:31
 msgid "Force client to use chosen port unless it is set to 0"
@@ -8096,7 +8099,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
 msgid "56k"
-msgstr ""
+msgstr "56k"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:38
 msgid "ISDN"
@@ -8128,7 +8131,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:52
 msgid "Downloads:"
-msgstr ""
+msgstr "다운로드:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:54
 msgid "Maximum number of concurrent HTTP/FTP downloads"
@@ -8164,7 +8167,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:85
 msgid "Framerate"
-msgstr ""
+msgstr "프레임레이트"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:87
 msgid "Maximum:"
@@ -8204,7 +8207,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
 msgid "Menu tooltips:"
-msgstr ""
+msgstr "메뉴 팁:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:137
 msgid ""
@@ -8295,7 +8298,7 @@ msgstr "텍스트 언어"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:69
 msgid "Set language"
-msgstr ""
+msgstr "확인"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:74
 msgid "Disable gore effects and harsh language"
@@ -8381,11 +8384,11 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:54
 msgid "16bit"
-msgstr ""
+msgstr "16빗"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:55
 msgid "32bit"
-msgstr ""
+msgstr "32빗"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:59
 msgid "Full screen"
@@ -8685,7 +8688,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/gametypelist.qc:86
 msgid "teamplay"
-msgstr ""
+msgstr "팀플레이"
 
 #: qcsrc/menu/xonotic/gametypelist.qc:88
 msgid "free for all"
@@ -8821,7 +8824,7 @@ msgstr "연결 종료하기"
 
 #: qcsrc/menu/xonotic/keybinder.qc:97
 msgid "quit"
-msgstr ""
+msgstr "종료"
 
 #: qcsrc/menu/xonotic/keybinder.qc:101
 msgid "auto-join team"
@@ -8833,7 +8836,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/keybinder.qc:106
 msgid "quick menu"
-msgstr ""
+msgstr "빠른메뉴"
 
 #: qcsrc/menu/xonotic/keybinder.qc:107
 msgid "sandbox menu"
@@ -8887,15 +8890,15 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:763
 msgid "Ping"
-msgstr ""
+msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:764
 msgid "Hostname"
-msgstr ""
+msgstr "호스트이름"
 
 #: qcsrc/menu/xonotic/serverlist.qc:765
 msgid "Map"
-msgstr ""
+msgstr ""
 
 #: qcsrc/menu/xonotic/serverlist.qc:766
 msgid "Type"
@@ -9054,51 +9057,51 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/statslist.qc:29
 msgid "January"
-msgstr ""
+msgstr "1월"
 
 #: qcsrc/menu/xonotic/statslist.qc:30
 msgid "February"
-msgstr ""
+msgstr "2월"
 
 #: qcsrc/menu/xonotic/statslist.qc:31
 msgid "March"
-msgstr ""
+msgstr "3월"
 
 #: qcsrc/menu/xonotic/statslist.qc:32
 msgid "April"
-msgstr ""
+msgstr "4월"
 
 #: qcsrc/menu/xonotic/statslist.qc:33
 msgid "May"
-msgstr ""
+msgstr "5월"
 
 #: qcsrc/menu/xonotic/statslist.qc:34
 msgid "June"
-msgstr ""
+msgstr "6월"
 
 #: qcsrc/menu/xonotic/statslist.qc:35
 msgid "July"
-msgstr ""
+msgstr "7월"
 
 #: qcsrc/menu/xonotic/statslist.qc:36
 msgid "August"
-msgstr ""
+msgstr "8월"
 
 #: qcsrc/menu/xonotic/statslist.qc:37
 msgid "September"
-msgstr ""
+msgstr "9월"
 
 #: qcsrc/menu/xonotic/statslist.qc:38
 msgid "October"
-msgstr ""
+msgstr "10월"
 
 #: qcsrc/menu/xonotic/statslist.qc:39
 msgid "November"
-msgstr ""
+msgstr "11월"
 
 #: qcsrc/menu/xonotic/statslist.qc:40
 msgid "December"
-msgstr ""
+msgstr "12월"
 
 #: qcsrc/menu/xonotic/statslist.qc:96
 msgid "Joined:"
@@ -9110,7 +9113,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/statslist.qc:110
 msgid "Time_Played:"
-msgstr ""
+msgstr "플레이_시간:"
 
 #: qcsrc/menu/xonotic/statslist.qc:117
 msgid "Favorite_Map:"
@@ -9184,3 +9187,6 @@ msgstr ""
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "제어반 활성화"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^채팅"
index 7f736e63a8a8989181926473b94c08faef1a1438..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-07-09 23:06+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."
@@ -231,7 +232,7 @@ msgstr "Pesya..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Keskows"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -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
@@ -2890,7 +2894,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9198,3 +9202,6 @@ msgstr ""
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr ""
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Keskows"
index 4ad2300d1d4d9813231d0e0619a9cd988788b8d7..c41b435f065019cd9d3ef3851199f819f8161012 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Macedonian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/mk/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
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 d7e0dc4136592a92f06e89ba1af23405e2a4f6ea..0bbf7b96001be8d5190afefcaf2008e20ddaf2ec 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Dutch (http://www.transifex.com/team-xonotic/xonotic/language/"
 "nl/)\n"
@@ -236,7 +236,7 @@ msgstr "Ga door..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2870,7 +2870,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9264,3 +9264,6 @@ msgstr "Team Kleur:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Activeer paneel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Chat"
index 674e494c9f5388bc0d265a7ee0ad7a7e48af1c41..e4e7fb0dd19ec9dceb422006627ded97fae33fa5 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Norwegian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/no/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index c18567a101a7cfe50e88e6564c265eb4a3bfe4ef..0b40453da5c9aa0dc5cfe785e3add14ea5e6ba47 100644 (file)
 # John Smith <myrangd@gmail.com>, 2016
 # Kriss Chr <kriss7475@gmail.com>, 2017
 # Piotr Kozica <koza91@gmail.com>, 2016
-# Robert Wolniak <robert.wolniak@gmail.com>, 2015
+# Rafał Szymański <okavasly@gmail.com>, 2017
+# 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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\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"
@@ -243,7 +244,7 @@ msgstr "Kontynuuj..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Czat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -365,19 +366,19 @@ msgstr "upuściłem flagę, ikona"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "QMCMD^upuść broń, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^upuszczono broń %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
-msgstr ""
+msgstr "QMCMD^upuść flagę/klucz, icon"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^upuszczono flagę/klucz %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:821
 msgid "QMCMD^Send private message to"
@@ -679,11 +680,11 @@ msgstr "samobójstwa"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:112
 msgid "SCO^takes"
-msgstr ""
+msgstr "SCO^przejęcia"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:113
 msgid "SCO^ticks"
-msgstr ""
+msgstr "SCO^ticks"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:295
 msgid ""
@@ -776,6 +777,8 @@ msgid ""
 "^3pickups^7                  How often a flag (CTF) or a key (KeyHunt) or a "
 "ball (Keepaway) was picked up\n"
 msgstr ""
+"^3pickups^7 Jak wiele razy flaga (CTF) lub klucz (KeyHunt) lub piłka "
+"(Keepaway) zostały podniesione\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:318
 msgid "^3captime^7                  Time of fastest cap (CTF)\n"
@@ -825,11 +828,11 @@ msgstr "^3laps^7 Ilość ukończonych okrążeń (wyścig/cts)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:329
 msgid "^3time^7                     Total time raced (race/cts)\n"
-msgstr ""
+msgstr "^3time^7 Całkowity czas wyścigów (race/cts)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:330
 msgid "^3fastest^7                  Time of fastest lap (race/cts)\n"
-msgstr ""
+msgstr "^3fastest^7 Czas najszybszego okrążenia (race/cts)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:331
 msgid "^3ticks^7                    Number of ticks (DOM)\n"
@@ -837,7 +840,7 @@ msgstr ""
 
 #: qcsrc/client/hud/panel/scoreboard.qc:332
 msgid "^3takes^7                    Number of domination points taken (DOM)\n"
-msgstr ""
+msgstr "^3takes^7 Liczba zdobytych punktów dominacji (DOM)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:333
 msgid "^3bckills^7                  Number of ball carrier kills\n"
@@ -1155,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"
@@ -1307,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"
@@ -1465,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
@@ -1472,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
@@ -2898,7 +2907,7 @@ msgstr "^BG%s%s^K1 zjadł rakietę ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9257,3 +9266,6 @@ msgstr "Kolor drużyny:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Włącz panel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Czat"
index 9997e727b386ba0095572ea19f1a9920418db659..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-07-09 23:06+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\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 chat."
+msgstr "^3Jogador^7: isto é a área doe conversação."
 
 #: qcsrc/client/hud/panel/engineinfo.qc:69
 #, c-format
@@ -54,17 +55,17 @@ msgstr "^1Assistindo: ^7%s"
 #: qcsrc/client/hud/panel/infomessages.qc:100
 #, c-format
 msgid "^1Press ^3%s^1 to spectate"
-msgstr "^1Pressione ^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
 msgid "primary fire"
-msgstr "fogo primário"
+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 "^1Pressione ^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,13 +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 ""
-"^1Pressione ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmera"
+"^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
@@ -100,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 "^1Pressione ^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
@@ -113,32 +114,32 @@ 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 "^1Pressione ^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
 msgid "jump"
-msgstr "pular"
+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 "%sPressione ^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
@@ -150,58 +151,57 @@ msgstr "pronto"
 #: qcsrc/client/hud/panel/infomessages.qc:162
 #, c-format
 msgid "%sPress ^3%s%s once you are ready"
-msgstr "%sPressione ^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 "^2Pressione ^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 " Pressione ^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 "^7Pressione ^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."
@@ -225,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
@@ -239,7 +239,7 @@ msgstr "Continuar..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Chat"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -259,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 "Chat da equipe"
+msgstr "Conversação da equipa"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:803
 msgid "QMCMD^quad soon"
@@ -272,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"
@@ -320,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)"
@@ -348,7 +348,7 @@ msgstr "Portador da bandeira aniquilado (l:%y^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:814
 msgid "QMCMD^killed flagcarrier, icon"
-msgstr ""
+msgstr "Portador da bandeira aniquilado, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:815
 #, c-format
@@ -361,11 +361,11 @@ msgstr "Bandeira largada, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^drop weapon, icon"
-msgstr ""
+msgstr "Largar arma, ícone"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:816
 msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "Arma largada %w^7 (l:%l^7)"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:817
 msgid "QMCMD^drop flag/key, icon"
@@ -387,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"
@@ -399,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"
@@ -420,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 chat"
+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"
@@ -437,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"
@@ -466,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 de chat"
+msgstr "Traduzir mensagens da conversação"
 
 #: qcsrc/client/hud/panel/quickmenu.qc:862
 #: qcsrc/client/hud/panel/quickmenu.qc:872
@@ -491,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
@@ -583,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"
@@ -685,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"
@@ -693,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"
@@ -706,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"
@@ -743,7 +744,7 @@ msgstr "^3suicídios^7 Número de suicídios\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:311
 msgid "^3frags^7                    kills - suicides\n"
-msgstr "^3frags^7 vítimas - suicídios\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"
@@ -759,23 +760,23 @@ 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 frags - mortes\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 (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"
@@ -788,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"
@@ -823,15 +824,15 @@ 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 (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 (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 (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"
@@ -863,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
@@ -877,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"
@@ -890,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
@@ -898,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
@@ -915,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:"
@@ -931,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"
@@ -940,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
@@ -955,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
@@ -1002,38 +1003,38 @@ 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 "^1Renascendo em ^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ê está morto, espere ^3%s^7 antes de renascer"
+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ê está morto, pressione ^2%s^7 para renascer"
+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
@@ -1057,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"
@@ -1111,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
@@ -1121,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"
@@ -1155,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"
@@ -1196,143 +1196,145 @@ 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"
-msgstr "Deathmatch"
+msgstr "Mata-mata"
 
 #: qcsrc/common/mapinfo.qh:99
 msgid "Score as many frags as you can"
-msgstr "Consiga o máximo de frags 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"
-msgstr "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"
+msgstr "Corra contra os outros jogadores até à linha de chegada"
 
 #: qcsrc/common/mapinfo.qh:160
 msgid "Race CTS"
-msgstr "Race CTS"
+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 frags 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 "Team Deathmatch"
+msgstr "Mata-mata por Equipa"
 
 #: qcsrc/common/mapinfo.qh:220
 msgid "Capture the Flag"
-msgstr "Capture the Flag"
+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
@@ -1362,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 ""
-"Pressione 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"
@@ -1401,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
@@ -1412,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
@@ -1458,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 ""
-"Pressione ^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"
@@ -1466,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
@@ -1478,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
@@ -1487,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
@@ -1517,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"
@@ -1539,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
@@ -1553,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
@@ -1566,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"
@@ -1601,7 +1602,7 @@ msgstr "Vingança"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:86
 msgid "Jump"
-msgstr "Pular"
+msgstr "Saltar"
 
 #: qcsrc/common/mutators/mutator/buffs/all.inc:95
 msgid "Invisible"
@@ -1617,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"
@@ -1629,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"
@@ -1637,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:"
@@ -1667,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"
@@ -1711,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"
@@ -1743,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
@@ -1770,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"
@@ -1802,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
@@ -1813,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"
@@ -1825,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
@@ -1838,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
@@ -1877,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:"
@@ -1886,8 +1887,8 @@ 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 chat de espectador não serão enviadas aos jogadores "
-"durante a partida"
+"^F4NOTA: ^BGas mensagens na conversação de espetador não serão enviadas aos "
+"jogadores durante a partida"
 
 #: qcsrc/common/notifications/all.inc:241
 #, c-format
@@ -1920,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"
@@ -1950,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
@@ -2000,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
@@ -2012,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
@@ -2061,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
@@ -2076,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
@@ -2086,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
@@ -2132,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
@@ -2168,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
@@ -2204,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
@@ -2214,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
@@ -2255,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
@@ -2265,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
@@ -2281,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
@@ -2302,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
@@ -2325,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
@@ -2341,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
@@ -2366,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
@@ -2391,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
@@ -2438,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
@@ -2448,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
@@ -2473,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
@@ -2538,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
@@ -2559,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
@@ -2627,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
@@ -2637,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
@@ -2659,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
@@ -2689,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
@@ -2703,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"
@@ -2726,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
@@ -2764,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
@@ -2780,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
@@ -2796,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
@@ -2811,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
@@ -2819,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
@@ -2833,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
@@ -2846,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
@@ -2868,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
@@ -2876,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
@@ -2885,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
@@ -2899,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
@@ -2924,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
@@ -2939,52 +2939,49 @@ 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
-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"
+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"
+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
@@ -2994,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
@@ -3040,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
@@ -3048,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
@@ -3071,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
@@ -3081,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
@@ -3106,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
@@ -3131,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
@@ -3156,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
@@ -3193,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
@@ -3228,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 ""
@@ -3248,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 ""
@@ -3262,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
@@ -3293,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 "^BGPressione ^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ê matou ^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 morto 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ê matou ^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 morto 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 "^BGPressione ^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
@@ -3487,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á renascendo 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 morto 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 morto 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 morto 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ê matou ^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 morto 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!"
@@ -3724,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ê nasceu congelado"
+msgstr "^K1A rodada já começou, surgiste congelado"
 
 #: qcsrc/common/notifications/all.inc:690
 #, c-format
@@ -3768,76 +3769,75 @@ 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 ""
 "^K1No spawnpoints available!\n"
 "Hope your team can fix it..."
 msgstr ""
-"^K1Não há pontos de nascimento disponíveis!\n"
-"Tomara que sua equipe conserte isso..."
+"^K1Não há pontos de surgimento disponíveis!\n"
+"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
@@ -3845,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
@@ -3880,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
@@ -3891,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 ""
@@ -3908,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!"
@@ -3919,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 "^BGPressione ^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 matando 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 ""
@@ -3956,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
@@ -3968,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
@@ -4038,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"
@@ -4046,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 "^BGPressione ^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 "^BGPressione ^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 "^BGPressione ^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 ""
+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
@@ -4135,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
@@ -4145,7 +4145,7 @@ msgstr " com %s"
 #: qcsrc/common/notifications/all.qh:444
 #, c-format
 msgid "%s^K1 made a TRIPLE FRAG! %s^BG"
-msgstr "%s^K1 fez um FRAG TRIPLO! %s^BG"
+msgstr "%s^K1 fez uma EXECUÇÃO TRIPLA! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:444
 #, c-format
@@ -4154,7 +4154,7 @@ msgstr "%s^K1 fez uma PONTUAÇÃO TRIPLA! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:444
 msgid "TRIPLE FRAG! "
-msgstr "FRAG TRIPLO! "
+msgstr "EXECUÇÃO TRIPLA! "
 
 #: qcsrc/common/notifications/all.qh:445
 #, c-format
@@ -4187,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
@@ -4215,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
@@ -4234,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
@@ -4257,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
@@ -4276,7 +4276,7 @@ msgstr "%d pontuações seguidas!"
 #: qcsrc/common/notifications/all.qh:501
 #, c-format
 msgid "%d frag spree! "
-msgstr "%d frags seguidos!"
+msgstr "%d execuções seguidas!"
 
 #: qcsrc/common/notifications/all.qh:514
 msgid "First blood! "
@@ -4297,7 +4297,7 @@ 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 frags seguidos! %s^BG"
+msgstr "%s^K1 tem %d execuções seguidas! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:560
 #, c-format
@@ -4317,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 frags"
+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 frags"
+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"
@@ -4352,7 +4352,7 @@ msgstr "Rosa"
 
 #: qcsrc/common/teams.qh:33
 msgid "Team"
-msgstr "Equipe"
+msgstr "Equipa"
 
 #: qcsrc/common/teams.qh:34
 msgid "Neutral"
@@ -4413,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"
@@ -4453,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"
@@ -4477,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"
@@ -4511,23 +4511,23 @@ msgstr "Walker"
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 #, c-format
 msgid "Press %s"
-msgstr "Pressione %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"
@@ -4551,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"
@@ -4579,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"
@@ -4587,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"
@@ -4611,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"
@@ -4619,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
@@ -4632,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
@@ -4848,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
@@ -4863,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"
@@ -4871,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"
@@ -4880,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
@@ -4902,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"
@@ -4926,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"
@@ -4934,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"
@@ -4946,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"
@@ -4970,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"
@@ -4990,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"
@@ -4998,7 +4998,7 @@ msgstr "Holandês"
 
 #: qcsrc/menu/xonotic/credits.qc:192
 msgid "English (Australia)"
-msgstr "Inglês (Australia)"
+msgstr "Inglês (Austrália)"
 
 #: qcsrc/menu/xonotic/credits.qc:197
 msgid "Finnish"
@@ -5022,7 +5022,7 @@ msgstr "Húngaro"
 
 #: qcsrc/menu/xonotic/credits.qc:231
 msgid "Irish"
-msgstr ""
+msgstr "Irlandês"
 
 #: qcsrc/menu/xonotic/credits.qc:234
 msgid "Italian"
@@ -5038,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"
@@ -5054,7 +5054,7 @@ msgstr "Russo"
 
 #: qcsrc/menu/xonotic/credits.qc:279
 msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Gaélico Escocês"
 
 #: qcsrc/menu/xonotic/credits.qc:282
 msgid "Serbian"
@@ -5074,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"
@@ -5098,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
@@ -5123,9 +5123,8 @@ msgid ""
 "player name to get started.  You can change these options later through the "
 "menu system."
 msgstr ""
-"Bem-vindo ao Xonotic! Por favor, 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
@@ -5135,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:"
@@ -5144,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
@@ -5153,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
@@ -5210,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:"
@@ -5218,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
@@ -5241,23 +5240,23 @@ msgstr "Painel Central"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:15
 msgid "Chat entries:"
-msgstr "Entradas do chat:"
+msgstr "Entradas da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
 msgid "Chat size:"
-msgstr "Tamanho do chat:"
+msgstr "Tamanho da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
 msgid "Chat lifetime:"
-msgstr "Tempo de vida do chat:"
+msgstr "Tempo de vida da conversação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
 msgid "Chat beep sound"
-msgstr "Som de aviso do chat"
+msgstr "Som de aviso da conversação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
 msgid "Chat Panel"
-msgstr "Painel do Chat"
+msgstr "Painel da Conversação"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
 msgid "Engine info:"
@@ -5273,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 estado"
+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 "Alinhar barra de estado:"
+msgstr "Alinhamento da barra de estado:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:27
 #: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:37
@@ -5303,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:"
@@ -5327,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"
@@ -5351,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"
@@ -5371,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"
@@ -5393,19 +5392,19 @@ 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 Race/CTS"
+msgstr "Painel ativado apenas em Corrida/CTS"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
 msgid "Status bar"
@@ -5467,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"
@@ -5487,16 +5486,16 @@ msgstr "Painel de Física"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qh:6
 msgid "Powerups Panel"
-msgstr "Painel de Poderes"
+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:"
@@ -5512,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 Race"
+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:"
@@ -5541,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"
@@ -5593,7 +5592,7 @@ msgstr "Pontuação:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:18
 msgid "Rankings:"
-msgstr "Tabela Classficativa:"
+msgstr "Classificações:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_score.qc:19
 msgid "Off"
@@ -5613,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:"
@@ -5673,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"
@@ -5697,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:"
@@ -5717,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
@@ -5742,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:"
@@ -5760,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
@@ -5784,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"
@@ -5804,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:"
@@ -5828,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:"
@@ -5837,7 +5836,7 @@ msgstr "Monstro:"
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:22
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:20
 msgid "Spawn"
-msgstr "Nascer"
+msgstr "Surgir"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:23
 #: qcsrc/menu/xonotic/serverlist.qc:268
@@ -5858,7 +5857,7 @@ msgstr "Vaguear"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:28
 msgid "Spawnpoint"
-msgstr "Ponto de nascimento"
+msgstr "Ponto de surgimento"
 
 #: qcsrc/menu/xonotic/dialog_monstertools.qc:29
 msgid "No moving"
@@ -5883,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"
@@ -5899,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
@@ -5927,13 +5926,13 @@ msgstr "Ilimitado"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:78
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:128
 msgid "Frag limit:"
-msgstr "Limite de frags:"
+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 frags necessária para acabar a partida"
+msgstr "A quantidade de execuções necessária para acabar a partida"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
 msgid "Capture limit:"
@@ -5969,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"
@@ -6008,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:"
@@ -6031,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"
@@ -6060,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"
@@ -6111,25 +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 pressione Ctrl+F para digitar uma palavra chave e buscar o "
-"mapa desejado. Você pode pressionar Ctrl+Delete para apagar e Enter para "
+"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"
@@ -6137,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"
@@ -6145,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:"
@@ -6182,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
@@ -6212,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
@@ -6251,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
@@ -6266,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"
@@ -6274,11 +6273,11 @@ msgstr "Exagero"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:99
 msgid "No powerups"
-msgstr "Sem poderes"
+msgstr "Sem potencializadores"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:101
 msgid "Powerups"
-msgstr "Poderes (powerups)"
+msgstr "Potencializadores"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:103
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:163
@@ -6295,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"
@@ -6304,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
@@ -6329,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 nascem 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 nascem 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)"
@@ -6364,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 nascerem 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"
@@ -6387,10 +6386,10 @@ 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 "
-"fogo secundário não causa nenhum dano, mas é útil para executar \"trickjumps"
-"\"."
+"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."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
 msgid ""
@@ -6398,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"
@@ -6408,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"
@@ -6424,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"
@@ -6432,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"
@@ -6443,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"
@@ -6460,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
@@ -6484,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)"
@@ -6492,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)"
@@ -6516,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)"
@@ -6553,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:"
@@ -6581,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"
@@ -6593,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"
@@ -6607,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
@@ -6621,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"
@@ -6653,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"
@@ -6677,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"
@@ -6685,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"
@@ -6730,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
@@ -6761,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 que deseja sair?"
+msgstr "Tens certeza de que queres sair?"
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:15
 msgid "Back to work..."
@@ -6773,7 +6773,7 @@ msgstr "De volta ao trabalho..."
 
 #: qcsrc/menu/xonotic/dialog_quit.qc:17
 msgid "I got some more fragging to do!"
-msgstr "Está na hora dos frags!"
+msgstr "Está na hora das execuções!"
 
 #: qcsrc/menu/xonotic/dialog_quit.qh:7
 msgid "Quit the game"
@@ -6805,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 *"
@@ -6813,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:"
@@ -6833,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:"
@@ -6861,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"
@@ -6881,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"
@@ -6925,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
@@ -6938,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:"
@@ -6986,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:"
@@ -7078,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 chat"
+msgstr "Som de mensagem da conversação"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:149
 msgid "Menu sounds"
@@ -7106,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"
@@ -7114,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:"
@@ -7122,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"
@@ -7138,7 +7138,7 @@ 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 matá-los"
+msgstr "Provocar inimigos automaticamente depois de executá-los"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:168
 msgid "Sometimes"
@@ -7286,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"
@@ -7325,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"
@@ -7350,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:"
@@ -7363,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)"
@@ -7387,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"
@@ -7400,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:"
@@ -7408,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:"
@@ -7416,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"
@@ -7428,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"
@@ -7455,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
@@ -7466,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"
@@ -7478,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"
@@ -7495,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"
@@ -7503,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"
@@ -7530,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 poderes (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"
@@ -7547,12 +7549,12 @@ msgstr "Partículas"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:240
 msgid "Spawnpoint effects"
-msgstr "Efeitos de ponto de nascimento"
+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 nascimento e sempre que um "
+"Efeitos de partículas em todos os pontos de surgimento e sempre que um "
 "jogador nascer"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:246
@@ -7565,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"
@@ -7585,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
@@ -7596,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 "Usa anéis para indicar estado 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"
@@ -7625,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"
@@ -7642,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"
@@ -7666,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 renascimento"
+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"
@@ -7699,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"
@@ -7727,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:"
@@ -7735,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:"
@@ -7756,52 +7758,53 @@ 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"
-msgstr "Informações de Frags"
+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:"
@@ -7809,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"
@@ -7830,11 +7833,13 @@ 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 frag à impressão central quando disponível"
+"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 frag nas mensagens de morte quando disponível"
+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"
@@ -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 The Flag"
+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 The Flag"
+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,19 +7861,19 @@ 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 chat"
+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 estados de jogadores no chat"
+msgstr "Mostrar estado dos jogadores na conversação"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
 msgid "Powerup notifications"
-msgstr "Notificações de poderes"
+msgstr "Notificações de potencializador"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:89
 msgid "Weapon centerprint notifications"
@@ -7884,7 +7889,7 @@ msgstr "Locutores"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:98
 msgid "Respawn countdown sounds"
-msgstr "Sons da contagem de renascimento"
+msgstr "Sons da contagem de ressurgimento"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:101
 msgid "Killstreak sounds"
@@ -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 renasce"
+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,66 +8196,66 @@ 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"
-msgstr " Pular continuamente ao segurar o botão de pular"
+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 pular:"
+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:"
@@ -8504,13 +8507,15 @@ 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 que deseja redefinir todas as configurações para o padrão?"
+msgstr ""
+"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"
@@ -8526,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 ""
@@ -8534,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"
@@ -8621,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"
@@ -8632,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)"
@@ -8654,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
@@ -8683,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"
@@ -8703,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"
@@ -8796,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:"
@@ -8820,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)"
@@ -8837,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 "???"
@@ -8890,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"
@@ -8899,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"
@@ -8927,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"
@@ -8953,23 +8959,23 @@ 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"
-msgstr "pular / nadar"
+msgstr "saltar / nadar"
 
 #: qcsrc/menu/xonotic/keybinder.qc:35
 msgid "crouch / sink"
@@ -9009,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"
@@ -9021,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"
@@ -9033,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"
@@ -9045,15 +9051,15 @@ msgstr "Comunicação"
 
 #: qcsrc/menu/xonotic/keybinder.qc:86
 msgid "public chat"
-msgstr "chat público"
+msgstr "Conversação pública"
 
 #: qcsrc/menu/xonotic/keybinder.qc:87 qcsrc/menu/xonotic/keybinder.qc:100
 msgid "team chat"
-msgstr "chat de equipe"
+msgstr "Conversação da equipa"
 
 #: qcsrc/menu/xonotic/keybinder.qc:88
 msgid "show chat history"
-msgstr "exibir histórico do chat"
+msgstr "mostrar histórico da conversação"
 
 #: qcsrc/menu/xonotic/keybinder.qc:89
 msgid "vote YES"
@@ -9069,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"
@@ -9081,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"
@@ -9101,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 pressione 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
@@ -9124,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>"
@@ -9137,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 ""
@@ -9184,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
@@ -9193,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"
@@ -9221,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"
@@ -9262,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"
@@ -9305,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"
@@ -9419,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
@@ -9434,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
@@ -9451,8 +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 "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 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 0086a180cfd0ab3f898eb45d7769b83974b4ded5..9e94da8c4785ef3451807546574e5e23861ca631 100644 (file)
@@ -14,7 +14,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Romanian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/ro/)\n"
@@ -238,7 +238,7 @@ msgstr "Continuă..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Conversație"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2936,8 +2936,8 @@ msgstr "^BG%s%s^K1 a mușcat din racheta%s%s lui ^BG%s^K1's"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 s-a apropiat prea mult de racheta%s%s lui ^BG%s^K1"
+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
@@ -9326,3 +9326,9 @@ msgstr "Culoare echipă:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Activare panou"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Conversație"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 s-a apropiat prea mult de racheta%s%s lui ^BG%s^K1"
index 44e7d4c48c771cddd01396cfa573ddd818c266f8..06e1922ae77fc612fb754d24eb30aba42d40dd4f 100644 (file)
@@ -6,7 +6,7 @@
 # adem4ik, 2014
 # Alex Talker <alextalker7@gmail.com>, 2014-2015
 # Andrei Stepanov, 2014
-# Andrei Stepanov, 2014-2017
+# Andrei Stepanov, 2014-2018
 # Andrey P <andrey.pyntikov@gmail.com>, 2016
 # Artem Vorotnikov <artem@vorotnikov.me>, 2015
 # Lord Canistra <lordcanistra@gmail.com>, 2011
@@ -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: 2017-07-09 23:06+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"
@@ -77,12 +77,12 @@ msgstr ""
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "next weapon"
-msgstr "следующее оружие"
+msgstr "след. оружие"
 
 #: qcsrc/client/hud/panel/infomessages.qc:102
 #: qcsrc/client/hud/panel/infomessages.qc:106
 msgid "previous weapon"
-msgstr "предыдущее оружие"
+msgstr "пред. оружие"
 
 #: qcsrc/client/hud/panel/infomessages.qc:106
 #, c-format
@@ -102,12 +102,12 @@ msgstr "бросить оружие"
 #: qcsrc/client/hud/panel/infomessages.qc:108
 #: qcsrc/menu/xonotic/keybinder.qc:41
 msgid "secondary fire"
-msgstr "дополниÑ\82елÑ\8cный огонь"
+msgstr "алÑ\8cÑ\82еÑ\80наÑ\82ивный огонь"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #, c-format
 msgid "^1Press ^3%s^1 for gamemode info"
-msgstr "^1Нажмите ^3%s^1 для показа информации о режиме игры"
+msgstr "^1Нажмите ^3%s^1 для показа сведений о режиме игры"
 
 #: qcsrc/client/hud/panel/infomessages.qc:111
 #: qcsrc/menu/xonotic/keybinder.qc:94
@@ -120,7 +120,7 @@ msgstr "^1Матч уже начался"
 
 #: qcsrc/client/hud/panel/infomessages.qc:126
 msgid "^1You have no more lives left"
-msgstr "^1У Ð\92ас закончились жизни"
+msgstr "^1У Ð²ас закончились жизни"
 
 #: qcsrc/client/hud/panel/infomessages.qc:128
 #: qcsrc/client/hud/panel/infomessages.qc:131
@@ -136,7 +136,7 @@ msgstr "прыжок"
 #: qcsrc/client/hud/panel/infomessages.qc:139
 #, c-format
 msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1Ð\9dаÑ\87ало игры через ^3%d^1 секунд"
+msgstr "^1СÑ\82аÑ\80Ñ\82 игры через ^3%d^1 секунд"
 
 #: qcsrc/client/hud/panel/infomessages.qc:145
 msgid "^2Currently in ^1warmup^2 stage!"
@@ -157,7 +157,7 @@ msgstr "готовность"
 #: qcsrc/client/hud/panel/infomessages.qc:162
 #, c-format
 msgid "%sPress ^3%s%s once you are ready"
-msgstr "%sÐ\9fо Ð³Ð¾Ñ\82овноÑ\81Ñ\82и Ð½Ð°Ð¶Ð¼Ð¸Ñ\82е ^3%s%s"
+msgstr "%sÐ\9dажмиÑ\82е ^3%s%s Ð¿Ð¾ Ð³Ð¾Ñ\82овноÑ\81Ñ\82и"
 
 #: qcsrc/client/hud/panel/infomessages.qc:167
 msgid "^2Waiting for others to ready up to end warmup..."
@@ -174,7 +174,7 @@ msgstr "^2Нажмите ^3%s^2 для завершения разминки"
 
 #: qcsrc/client/hud/panel/infomessages.qc:196
 msgid "Teamnumbers are unbalanced!"
-msgstr "Команды не равны!"
+msgstr "Команды не равны по составу!"
 
 #: qcsrc/client/hud/panel/infomessages.qc:199
 #, c-format
@@ -242,7 +242,7 @@ msgstr "Продолжить..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Чат"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -550,7 +550,7 @@ msgstr "SCO^время"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:80
 msgid "SCO^caps"
-msgstr "SCO^захваты"
+msgstr "SCO^захватов"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:81
 msgid "SCO^captime"
@@ -709,7 +709,7 @@ msgstr "^2scoreboard_columns_set ^7поле1 поле2 ...\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:300
 msgid "The following field names are recognized (case insensitive):\n"
-msgstr "Ð\91Ñ\8bли Ñ\80аÑ\81познанÑ\8b Ñ\81ледÑ\83Ñ\8eÑ\89ие Ð¸Ð¼ÐµÐ½Ð° Ð¿Ð¾Ð»ÐµÐ¹ (без Ñ\83Ñ\87ета регистра):\n"
+msgstr "РаÑ\81познанÑ\8b Ñ\81ледÑ\83Ñ\8eÑ\89ие Ð¸Ð¼ÐµÐ½Ð° Ð¿Ð¾Ð»ÐµÐ¹ (без Ñ\83Ñ\87Ñ\91та регистра):\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:301
 msgid "You can use a ^3|^7 to start the right-aligned fields.\n"
@@ -767,27 +767,29 @@ msgstr "^3сумма^7 фраги - смерти\n"
 msgid ""
 "^3caps^7                     How often a flag (CTF) or a key (KeyHunt) was "
 "captured\n"
-msgstr "^3caps^7 Как часто флаг (CTF) или ключ (KeyHunt) был захвачен\n"
+msgstr ""
+"^3caps^7 Как часто флаг (Захват флага) или ключ (Охота за ключами) был "
+"захвачен\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 ""
-"^3pickups^7 Как часто флаг (CTF) или ключ (KeyHunt) или мяч (Keepaway) были "
-"подобраны\n"
+"^3pickups^7 Как часто флаг (Захват флага) или ключ (Охота за ключами) или "
+"мÑ\8fÑ\87 (Ð\9fÑ\80Ñ\8fÑ\82ки) Ð±Ñ\8bли Ð¿Ð¾Ð´Ð¾Ð±Ñ\80анÑ\8b\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:318
 msgid "^3captime^7                  Time of fastest cap (CTF)\n"
-msgstr "^3captime^7 Ð\92Ñ\80емÑ\8f Ð½Ð°Ð¸Ð±Ñ\8bÑ\81Ñ\82Ñ\80ейÑ\88его Ð·Ð°Ñ\85ваÑ\82а(CTF)\n"
+msgstr "^3captime^7 Ð\92Ñ\80емÑ\8f Ð±Ñ\8bÑ\81Ñ\82Ñ\80ейÑ\88его Ð·Ð°Ñ\85ваÑ\82а (CTF)\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:319
 msgid "^3fckills^7                  Number of flag carrier kills\n"
-msgstr "^3фубийств^7 Число убийств флагоносцев\n"
+msgstr "^3фубийств^7 Число убитых флагоносцев\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:320
 msgid "^3returns^7                  Number of flag returns\n"
-msgstr "^3returns^7 Число возращённых флагов\n"
+msgstr "^3returns^7 Число возвращённых флагов\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:321
 msgid "^3drops^7                    Number of flag drops\n"
@@ -847,7 +849,7 @@ msgstr "^3нмубийств^7 Число убийств носителей мя
 msgid ""
 "^3bctime^7                   Total amount of time holding the ball in "
 "Keepaway\n"
-msgstr "^3bctime^7 Общее число продержанных мячей в режиме Keepaway\n"
+msgstr "^3bctime^7 Общее число продержанных мячей в режиме Прятки\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:335
 msgid "^3score^7                    Total score\n"
@@ -873,7 +875,7 @@ msgid ""
 "\n"
 msgstr ""
 "Специальные имена типов игры 'teams' и 'noteams' могут быть\n"
-"иÑ\81полÑ\8cзованÑ\8b Ð´Ð»Ñ\8f Ð²ÐºÐ»Ñ\8eÑ\87ениÑ\8f²Ñ\8bключения ВСЕХ командных/не\n"
+"иÑ\81полÑ\8cзованÑ\8b Ð´Ð»Ñ\8f Ð²ÐºÐ»Ñ\8eÑ\87ениÑ\8f¾Ñ\82ключения ВСЕХ командных/не\n"
 "командных игровых режимов.\n"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:346
@@ -911,7 +913,7 @@ msgstr "Н/Д"
 #: qcsrc/client/hud/panel/scoreboard.qc:1156
 #, c-format
 msgid "Accuracy stats (average %d%%)"
-msgstr "СÑ\82аÑ\82иÑ\81Ñ\82ика Ñ\82оÑ\87ноÑ\81Ñ\82и (средняя %d%%)"
+msgstr "ТоÑ\87ноÑ\81Ñ\82Ñ\8c Ð¿Ð¾Ð¿Ð°Ð´Ð°Ð½Ð¸Ð¹ (средняя %d%%)"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1295
 msgid "Map stats:"
@@ -931,7 +933,7 @@ msgstr "Рейтинг времени захвата"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1354
 msgid "Rankings"
-msgstr "Ранг"
+msgstr "РейÑ\82инг"
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1519
 #: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:43
@@ -998,7 +1000,7 @@ msgstr " по достижению лидерства в ^3%s %s^7"
 #: qcsrc/client/hud/panel/scoreboard.qc:1688
 #, c-format
 msgid "^1Respawning in ^3%s^1..."
-msgstr "^1Возрождение после ^3%s^1..."
+msgstr "^1Возрождение через ^3%s^1..."
 
 #: qcsrc/client/hud/panel/scoreboard.qc:1698
 #, c-format
@@ -1020,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?"
@@ -1076,7 +1078,7 @@ msgstr "км/ч"
 
 #: qcsrc/client/main.qc:1020
 msgid " mph"
-msgstr "милÑ\8f/ч"
+msgstr "милÑ\8c/ч"
 
 #: qcsrc/client/main.qc:1022
 msgid " knots"
@@ -1122,7 +1124,7 @@ msgstr ""
 
 #: qcsrc/client/mapvoting.qc:507
 msgid "^1Error:^7 Couldn't find pak index.\n"
-msgstr "^1Error:^7 Невозможно найти индекс пака.\n"
+msgstr "^1Error:^7 Не удалось найти индекс пака.\n"
 
 #: qcsrc/client/mapvoting.qc:516
 msgid "Requesting preview...\n"
@@ -1162,7 +1164,7 @@ msgstr "Большая броня"
 
 #: qcsrc/common/items/item/armor.qh:147
 msgid "Mega armor"
-msgstr "Мега броня"
+msgstr "Мега-броня"
 
 #: qcsrc/common/items/item/health.qh:111
 msgid "Big health"
@@ -1178,7 +1180,7 @@ msgstr "Реактивный ранец"
 
 #: qcsrc/common/items/item/jetpack.qh:82
 msgid "Fuel regen"
-msgstr "ЭнеÑ\80гиÑ\8f Ñ\80егенеÑ\80аÑ\86ии"
+msgstr "РегенеÑ\80аÑ\82оÑ\80 Ñ\82оплива"
 
 #: qcsrc/common/items/item/powerup.qh:44
 msgid "Strength"
@@ -1242,8 +1244,8 @@ msgid ""
 "Find and bring the enemy flag to your base to capture it, defend your base "
 "from the other team"
 msgstr ""
-"Найдите и принесите флаг противника на свою базу для захвата, защищайте вашу "
-"базÑ\83 Ð¾Ñ\82 ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ\8b Ð¿Ñ\80оÑ\82ивника"
+"Найдите и принесите флаг противника на свою базу, защищайте свой флаг от "
+"команды противника"
 
 #: qcsrc/common/mapinfo.qh:249
 msgid "Clan Arena"
@@ -1305,8 +1307,8 @@ msgid ""
 "Kill enemies to freeze them, stand next to frozen teammates to revive them; "
 "freeze all enemies to win"
 msgstr ""
-"Поражайте врагов, чтобы заморозить их всех и выиграть раунд, и "
-"Ñ\80азмоÑ\80аживайÑ\82е Ñ\81оÑ\8eзников, Ñ\81Ñ\82оÑ\8f Ñ\80Ñ\8fдом Ñ\81 Ð½Ð¸Ð¼Ð¸"
+"Поражайте врагов, чтобы заморозить их всех и выиграть раунд. Размораживайте "
+"союзников, стоя рядом с ними"
 
 #: qcsrc/common/mapinfo.qh:446
 msgid "Hold the ball to get points for kills"
@@ -1364,11 +1366,11 @@ msgstr "Повезёт в следующий раз!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1172
 msgid "Tubular! Press \"Next Level\" to continue!"
-msgstr "ТÑ\83бÑ\83лаÑ\80! Ð\9dажмиÑ\82е \"СледÑ\83Ñ\8eÑ\89ий Ñ\83Ñ\80овнь\" для продолжения!"
+msgstr "Ð\9fÑ\80евоÑ\81Ñ\85одно! Ð\9dажмиÑ\82е \"СледÑ\83Ñ\8eÑ\89ий Ñ\83Ñ\80овень\" для продолжения!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1174
 msgid "Wicked! Press \"Next Level\" to continue!"
-msgstr "Ð\93Ñ\80еÑ\88ник! Ð\9dажмиÑ\82е \"СледÑ\83Ñ\8eÑ\89ий Ñ\83Ñ\80овнь\" для продолжения!"
+msgstr "Ð\9eзоÑ\80ник! Ð\9dажмиÑ\82е \"СледÑ\83Ñ\8eÑ\89ий Ñ\83Ñ\80овень\" для продолжения!"
 
 #: qcsrc/common/minigames/minigame/bd.qc:1177
 msgid "Press the space bar to change your currently selected tile"
@@ -1487,7 +1489,7 @@ msgstr "Выберите в меню \"^1Следующий матч^7\" для
 #: 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 "Дождитесь пока соперник подтвердит старт переигровки"
 
 #: qcsrc/common/minigames/minigame/pp.qc:582
 #: qcsrc/common/minigames/minigame/ttt.qc:665
@@ -1621,7 +1623,7 @@ msgstr "Бонус"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:8
 msgid "Damage text"
-msgstr "ТекÑ\81Ñ\82 урона"
+msgstr "ЦиÑ\84Ñ\80Ñ\8b урона"
 
 #: qcsrc/common/mutators/mutator/damagetext/ui_damagetext.qc:18
 msgid "Draw damage numbers"
@@ -1629,11 +1631,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:"
@@ -1699,7 +1701,7 @@ msgstr "Граната"
 
 #: qcsrc/common/mutators/mutator/overkill/hmg.qh:17
 msgid "Heavy Machine Gun"
-msgstr "ТÑ\8fжÑ\91лÑ\8bй Ð¿улемёт"
+msgstr "ТÑ\8fжÑ\91лÑ\8bй Ð\9fулемёт"
 
 #: qcsrc/common/mutators/mutator/overkill/rpc.qh:17
 msgid "Rocket Propelled Chainsaw"
@@ -1736,13 +1738,13 @@ msgstr "Контрольная точка"
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:13
 #: qcsrc/common/mutators/mutator/waypoints/waypointsprites.qc:252
 msgid "Finish"
-msgstr "Ð\9aонеÑ\86"
+msgstr "ФиниÑ\88"
 
 #: 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 "Ð\9dаÑ\87ало"
+msgstr "СÑ\82аÑ\80Ñ\82"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:17
 msgid "Defend"
@@ -1758,11 +1760,11 @@ msgstr "Нажать"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:21
 msgid "Flag carrier"
-msgstr "Ð\97наменосец"
+msgstr "Флагоносец"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:22
 msgid "Enemy carrier"
-msgstr "Вражеский знаменосец"
+msgstr "Вражеский флагоносец"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:23
 msgid "Dropped flag"
@@ -1790,7 +1792,7 @@ msgstr "Розовая база"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:29
 msgid "Return flag here"
-msgstr "Ð\92еÑ\80нÑ\83Ñ\82Ñ\8c Ñ\84лаг Ð·Ð´ÐµÑ\81Ñ\8c"
+msgstr "Ð\92еÑ\80нÑ\83Ñ\82Ñ\8c Ñ\84лаг Ð¾Ñ\82Ñ\81Ñ\8eда"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:31
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:32
@@ -1817,7 +1819,7 @@ msgstr "Носитель ключа"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:39
 msgid "Run here"
-msgstr "Беги сюда"
+msgstr "Бегите сюда"
 
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:45
 #: qcsrc/common/mutators/mutator/waypoints/all.inc:48
@@ -1873,7 +1875,7 @@ msgstr "^1Уведомления от сервера:"
 
 #: qcsrc/common/notifications/all.inc:239
 msgid "^F4NOTE: ^BGSpectator chat is not sent to players during the match"
-msgstr "^F4Ð\9fРÐ\98Ð\9cÐ\95ЧÐ\90Ð\9dÐ\98Ð\95: ^BGЧаÑ\82 Ð·Ñ\80иÑ\82елей Ð½Ðµ Ð²Ð¸Ð´ÐµÐ½ Ð´Ð»Ñ\8f Ð¸Ð³Ñ\80оков во время матча"
+msgstr "^F4Ð\9fРÐ\98Ð\9cÐ\95ЧÐ\90Ð\9dÐ\98Ð\95: ^BGÐ\98гÑ\80оки Ð½Ðµ Ð²Ð¸Ð´Ñ\8fÑ\82 Ñ\87аÑ\82 Ð·Ñ\80иÑ\82елей во время матча"
 
 #: qcsrc/common/notifications/all.inc:241
 #, c-format
@@ -1910,23 +1912,23 @@ 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ен на базу владельцем"
+msgstr "^BG ^TC^TT^BG Ð¤Ð»Ð°Ð³ Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91н на базу владельцем"
 
 #: qcsrc/common/notifications/all.inc:247
 msgid "^BGThe flag was returned by its owner"
-msgstr "^BGФлаг Ð±Ñ\8bл Ð²Ð¾Ð·Ð²Ñ\80аÑ\89ен на базу владельцем"
+msgstr "^BGФлаг Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91н на базу владельцем"
 
 #: qcsrc/common/notifications/all.inc:248
 msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
-msgstr "^BG ^TC^TT^BG Флаг был уничтожен и возвращен на базу"
+msgstr "^BG ^TC^TT^BG Флаг был уничтожен и возвращён на базу"
 
 #: qcsrc/common/notifications/all.inc:249
 msgid "^BGThe flag was destroyed and returned to base"
-msgstr "^BGФлаг был уничтожен и возвращен на базу"
+msgstr "^BGФлаг был уничтожен и возвращён на базу"
 
 #: qcsrc/common/notifications/all.inc:250
 msgid "^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"
-msgstr "^BG ^TC^TT^BG Ð¤Ð»Ð°Ð³ Ð±Ñ\8bл Ð±Ñ\80оÑ\88ен Ð² Ð±Ð°Ð·Ðµ Ð¸ Ð²Ð¾Ð·Ð²Ñ\80аÑ\89ен Ð½Ð° Ð½ÐµÐµ"
+msgstr "^BG ^TC^TT^BG Ð¤Ð»Ð°Ð³ Ð±Ñ\8bл Ð±Ñ\80оÑ\88ен Ð½Ð° Ð±Ð°Ð·Ðµ Ð¸ Ð²Ð¾Ð·Ð²Ñ\80аÑ\89Ñ\91н"
 
 #: qcsrc/common/notifications/all.inc:251
 msgid "^BGThe flag was dropped in the base and returned itself"
@@ -2007,11 +2009,11 @@ msgstr "^BGУ вас нет топлива для ^F1Реактивного ра
 msgid "^F2You lack a UID, superspec options will not be saved/restored"
 msgstr ""
 "^F2У вас нет UID, настройки суперспектатора не будут сохранены или "
-"востановлены"
+"воÑ\81Ñ\81Ñ\82ановленÑ\8b"
 
 #: qcsrc/common/notifications/all.inc:271
 msgid "^F1Round already started, you will join the game in the next round"
-msgstr "^F1РаÑ\83нд Ñ\83же Ð½Ð°Ñ\87алÑ\81Ñ\8f, Ð²Ñ\8b Ð½Ð°Ñ\87нÑ\91Ñ\82е Ð¸Ð³Ñ\80Ñ\83 Ñ\81о Ñ\81ледÑ\83Ñ\8eÑ\89его Ñ\80аÑ\83ндда"
+msgstr "^F1Раунд уже начался, вы начнёте игру со следующего раунда"
 
 #: qcsrc/common/notifications/all.inc:272
 msgid "^F2You will spectate in the next round"
@@ -2020,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
@@ -2045,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л Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ Ð¿Ð¾Ð´Ð¾Ð¶Ð¶ÐµÐ½ ^BG%s^K1^K1%s%s"
+msgstr "^BG%s%s^K1 Ð½ÐµÐ¼Ð½Ð¾Ð³Ð¾ Ð¿Ð¾Ð´Ð¿Ð°Ð»Ñ\91н Ð¸Ð· ^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
@@ -2070,22 +2072,22 @@ msgstr "^BG%s%s^K1 был взорван ^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 слишком близко подошел к взрыву напалма%s%s"
+msgstr "^BG%s%s^K1 слишком близко подошёл к взрыву напалма%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 был сожжён заживо Гранатой Напалма ^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
@@ -2095,12 +2097,12 @@ 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
 msgid "^BG%s%s^K1 was slimed by ^BG%s^K1%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:288
 #, c-format
@@ -2116,7 +2118,7 @@ msgstr ""
 #: 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 Ð±Ñ\8bл Ñ\83биÑ\82 ^BG%s^K1%s%s Ð² Ð¿Ñ\80оÑ\86еÑ\81Ñ\81е Ñ\82елепоÑ\80Ñ\82аÑ\86ии"
+msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ñ\82елеÑ\84Ñ\80агнÑ\83Ñ\82 ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:290
 #, c-format
@@ -2129,15 +2131,13 @@ msgstr ""
 msgid ""
 "^BG%s%s^K1 got caught in the blast when ^BG%s^K1's Bumblebee exploded%s%s"
 msgstr ""
-"^BG%s%s^K1 зацепило взрывной волной от подорвавшегося с Bumblebee ^BG%s^K1%s"
-"%s"
+"^BG%s%s^K1 зацепило взрывной волной от подорвавшегося со Шмеля ^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 долюбовался огоньками из пушки Bumblebee, управляемого ^BG%s^K1%s"
-"%s"
+"^BG%s%s^K1 засмотрелся на огоньки из пушки Шмеля, управляемого ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:293
 #, c-format
@@ -2147,7 +2147,7 @@ msgstr "^BG%s%s^K1 был раздавлен ^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 был завален кассетными бомбами с Raptor'а ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 был завален кассетными бомбами с Ящера ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:295
 #, c-format
@@ -2158,47 +2158,46 @@ msgstr "^BG%s%s^K1 не смог устоять перед пурпурными
 #, 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 зацепило взрывной волной от взорвавшегося на Raptor'e ^BG%s^K1%s%s"
+"^BG%s%s^K1 зацепило взрывной волной от взорвавшегося на Ящере ^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 зацепило взрывной волной от взорвавшегося на Spiderbot'e ^BG"
-"%s^K1%s%s"
+"^BG%s%s^K1 зацепило взрывной волной от взорвавшегося на Пауке-боте ^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 Ð±Ñ\8bл Ð¸Ð·Ð¼ÐµÐ»Ñ\8cÑ\87Ñ\91н Spiderbot'ом, управляемым ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð¸Ð·Ð¼ÐµÐ»Ñ\8cÑ\87Ñ\91н Ð\9fÑ\83ком-боÑ\82ом, управляемым ^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 был разорван на куски Spiderbot'ом, управляемым ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван на куски Пауком-ботом, управляемым ^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 зацепило взрывной волной от взорвавшегося на Racer'e ^BG%s^K1%s%s"
+"^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 "^BG%s%s^K1 пригвоздило Racer'ом, управляемым ^BG%s^K1%s%s"
+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 "^BG%s%s^K1 не смог скрыться от Racer'а, управляемого ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 не смог скрыться от Гонщика, управляемого ^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 Ð±Ñ\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,32 +2267,32 @@ 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
 msgid "^BG%s^K1's innards became outwards by a Shambler%s%s"
-msgstr "^BG%s^K1's Ð±Ñ\8bл Ð²Ñ\8bвеÑ\80нÑ\83Ñ\82 Ð½Ð°Ð¸Ð·Ð½Ð°Ð½ÐºÑ\83 Ð¨Ð°Ð¼Ð±Ð»ÐµÑ\80ом%s%s"
+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н Ð¾Ð³Ð½Ðµным шаром Виверна%s%s"
+msgstr "^BG%s^K1 Ð¿Ð¾Ñ\80ажÑ\91н Ð¾Ð³Ð½ÐµÐ½ным шаром Виверна%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
@@ -2355,7 +2354,7 @@ msgstr "^BG%s^K1 сгинул%s%s"
 #: qcsrc/common/notifications/all.inc:330
 #, c-format
 msgid "^BG%s^K1 became a shooting star%s%s"
-msgstr "^BG%s^K1 стал падующей звездой%s%s"
+msgstr "^BG%s^K1 стал падающей звездой%s%s"
 
 #: qcsrc/common/notifications/all.inc:331
 #, c-format
@@ -2390,17 +2389,17 @@ 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
 msgid "^BG%s^K1 got caught up in the FLAC turret fire%s%s"
-msgstr "^BG%s^K1 Ð¿Ð¾Ð¿Ð°Ð» Ð¿Ð¾Ð´ Ð¾Ð³Ð¾Ð½Ñ\8c Ð·ÐµÐ½Ð¸Ñ\82ки FLAC%s%s"
+msgstr "^BG%s^K1 Ð¿Ð¾Ð¿Ð°Ð» Ð¿Ð¾Ð´ Ð¾Ð³Ð¾Ð½Ñ\8c Ð\97ениÑ\82ной Ð\9fÑ\83Ñ\88ки %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
@@ -2410,17 +2409,17 @@ msgstr "^BG%s^K1 не смог спрятаться от турели 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 Ð±Ñ\8bл Ð¸Ð·Ñ\80еÑ\88еÑ\87Ñ\91н Ð\9fÑ\83лемÑ\91Ñ\82ной Ð±Ð°Ñ\88ней%s%s"
+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,62 +2429,62 @@ 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
 msgid "^BG%s^K1 got served a lead enrichment by a Walker turret%s%s"
-msgstr "^BG%s^K1 Ð±Ñ\8bл Ð¾Ð±Ð¾Ð³Ð°Ñ\89Ñ\91н Ñ\81винÑ\86ом Ð¸Ð· Ñ\82Ñ\83Ñ\80ели Walker'a%s%s"
+msgstr "^BG%s^K1 Ð¾Ð±Ð¾Ð³Ð°Ñ\89Ñ\91н Ñ\81винÑ\86ом Ð¸Ð· Ñ\82Ñ\83Ñ\80ели Ð¥Ð¾Ð´Ñ\83нa%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 Ð±Ñ\8bл Ð¿Ñ\80онзÑ\91н Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e Walker'а%s%s"
+msgstr "^BG%s^K1 Ð¿Ñ\80онзÑ\91н Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e Ð¥Ð¾Ð´Ñ\83на%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 был разорван в клочья турелью Walker'а%s%s"
+msgstr "^BG%s^K1 разорван в клочья турелью Ходуна%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 зацепило взрывной волной от Bumblebee%s%s"
+msgstr "^BG%s^K1 зацепило взрывной волной от Шмеля %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 был раздавлен весом тяжёлой машины%s%s"
+msgstr "^BG%s^K1 раздавлен весом тяжёлой машины%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 был накрыт кассетными бомбами с Raptor'а%s%s"
+msgstr "^BG%s^K1 был накрыт кассетными бомбами с Ящера%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 задело взрывной волной от Raptor'a%s%s"
+msgstr "^BG%s^K1 задело взрывной волной от Ящера %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 задело взрывной волной от Spiderbot'а%s%s"
+msgstr "^BG%s^K1 задело взрывной волной от Паука-бота%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 был разорван на кусочки ракетой Spiderbot'а%s%s"
+msgstr "^BG%s^K1 разорван на кусочки ракетой Паука-бота%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 задело взрывной волной от Racer'а%s%s"
+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 "^BG%s^K1 не смог укрыться от ракеты Racer'а%s%s"
+msgstr "^BG%s^K1 не смог укрыться от ракеты Гонщика%s%s"
 
 #: qcsrc/common/notifications/all.inc:359
 #, 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
@@ -2530,7 +2529,7 @@ 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 "^TC^TT^BG команда выиграла этот раунд"
+msgstr "^BGКоманда ^TC^TT^BG выиграла этот раунд"
 
 #: qcsrc/common/notifications/all.inc:371
 #: qcsrc/common/notifications/all.inc:685
@@ -2551,7 +2550,7 @@ msgstr "^BGРаунд окончен, победитель не выявлен"
 #: qcsrc/common/notifications/all.inc:375
 #, c-format
 msgid "^BGGodmode saved you %s units of damage, cheater!"
-msgstr "^BGРежим Бога спас тебя от %s единиц урона, читер!"
+msgstr "^BGРежим Бога спас вас от %s единиц урона, читер!"
 
 #: qcsrc/common/notifications/all.inc:377
 #, c-format
@@ -2567,13 +2566,13 @@ msgstr "^BG%s^BG потерял усилитель %s^BG!"
 #: qcsrc/common/notifications/all.inc:692
 #, c-format
 msgid "^BGYou dropped the %s^BG buff!"
-msgstr "^BGÐ\92Ñ\8b Ñ\83Ñ\80онили усилитель %s^BG!"
+msgstr "^BGÐ\92Ñ\8b Ñ\81бÑ\80оÑ\81или усилитель %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:380
 #: qcsrc/common/notifications/all.inc:693
 #, c-format
 msgid "^BGYou got the %s^BG buff!"
-msgstr "^BGÐ\92Ñ\8b Ð·Ð°Ð±Ñ\80али усилитель %s^BG!"
+msgstr "^BGÐ\92Ñ\8b Ð¿Ð¾Ð´Ð½Ñ\8fли усилитель %s^BG!"
 
 #: qcsrc/common/notifications/all.inc:382
 #: qcsrc/common/notifications/all.inc:696
@@ -2585,7 +2584,7 @@ msgstr "^BGУ вас отсутствует ^F1%s"
 #: qcsrc/common/notifications/all.inc:697
 #, c-format
 msgid "^BGYou dropped the ^F1%s^BG%s"
-msgstr "^BGВы выбросили ^F1%s^BG%s"
+msgstr "^BGВы сбросили ^F1%s^BG%s"
 
 #: qcsrc/common/notifications/all.inc:384
 #: qcsrc/common/notifications/all.inc:698
@@ -2624,7 +2623,7 @@ msgstr "^BG%s^F3 подключился"
 #: qcsrc/common/notifications/all.inc:391
 #, c-format
 msgid "^BG%s^F3 connected and joined the ^TC^TT team"
-msgstr "^BG%s^F3 подключен и присоединен к ^TC^TT коменде"
+msgstr "^BG%s^F3 подключён и присоединён к ^TC^TT команде"
 
 #: qcsrc/common/notifications/all.inc:392
 #, c-format
@@ -2640,7 +2639,7 @@ msgstr "^BG%s^F3 сейчас играет в команде ^TC^TT"
 #: qcsrc/common/notifications/all.inc:706
 #, c-format
 msgid "^BG%s^BG has dropped the ball!"
-msgstr "^BG%s^BG Ð\9fоÑ\82еÑ\80Ñ\8fл мяч!"
+msgstr "^BG%s^BG Ð²Ñ\8bбÑ\80оÑ\81ил мяч!"
 
 #: qcsrc/common/notifications/all.inc:396
 #: qcsrc/common/notifications/all.inc:707
@@ -2656,7 +2655,7 @@ msgstr "^BG%s^BG захватил ключ ^TC^TT команды"
 #: qcsrc/common/notifications/all.inc:399
 #, c-format
 msgid "^BG%s^BG dropped the ^TC^TT Key"
-msgstr "^BG%s^BG выбросил ^TC^TT Ключ"
+msgstr "^BG%s^BG уронил ^TC^TT Ключ"
 
 #: qcsrc/common/notifications/all.inc:400
 #, 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!"
@@ -2749,13 +2748,13 @@ msgid ""
 "^F2You were kicked from the server because you are a spectator and "
 "spectators aren't allowed at the moment."
 msgstr ""
-"^F2ТÑ\8b Ð±Ñ\8bл Ð²Ñ\8bкинÑ\83Ñ\82 Ñ\81 Ñ\81еÑ\80веÑ\80а, Ð¿Ð¾Ñ\82омÑ\83 Ñ\87Ñ\82о Ñ\82Ñ\8b Ð·Ñ\80иÑ\82елÑ\8c, Ð° Ð·Ñ\80иÑ\82ели Ð½Ðµ Ð´Ð¾Ð¿Ñ\83Ñ\81каÑ\8eÑ\82Ñ\81Ñ\8f "
-"на данный момент."
+"^F2Ð\92Ñ\8b Ð²Ñ\8bкинÑ\83Ñ\82Ñ\8b Ñ\81 Ñ\81еÑ\80веÑ\80а, Ð¿Ð¾Ñ\82омÑ\83 Ñ\87Ñ\82о Ð²Ñ\8b Ð±Ñ\8bли Ð·Ñ\80иÑ\82елем, Ð° Ð·Ñ\80иÑ\82ели Ð½Ðµ "
+"допÑ\83Ñ\81каÑ\8eÑ\82Ñ\81Ñ\8f Ð½Ð° Ð´Ð°Ð½Ð½Ñ\8bй Ð¼Ð¾Ð¼ÐµÐ½Ñ\82."
 
 #: qcsrc/common/notifications/all.inc:425
 #, c-format
 msgid "^BG%s^F3 is now spectating"
-msgstr "^BG%s^F3 Ñ\82епеÑ\80Ñ\8c Ð½Ð°Ð±Ð»Ñ\8eдатель"
+msgstr "^BG%s^F3 Ñ\82епеÑ\80Ñ\8c Ð·Ñ\80итель"
 
 #: qcsrc/common/notifications/all.inc:427
 #, c-format
@@ -2819,7 +2818,7 @@ msgstr "^F4Вас пригласил ^BG%s^F4 к себе на игру в ^F2%s
 
 #: qcsrc/common/notifications/all.inc:439
 msgid "^TC^TT ^BGteam scores!"
-msgstr "^TC^TT ^BG команда увеличивает счет!"
+msgstr "^BGКоманда ^TC^TT^BG увеличивает счёт!"
 
 #: qcsrc/common/notifications/all.inc:441
 #, c-format
@@ -2828,7 +2827,7 @@ msgid ""
 "kicked, because spectating isn't allowed at this time!"
 msgstr ""
 "^F2Вы должны присоединиться к игре в течение %s, в противном случае вы "
-"бÑ\83деÑ\82е Ð¾Ñ\82Ñ\81оединенÑ\8b Ð¾Ñ\82 Ñ\81еÑ\80веÑ\80а, Ñ\82ак ÐºÐ°Ðº Ð±Ñ\8bÑ\82Ñ\8c Ð½Ð°Ð±Ð»Ñ\8eдателем временно запрещено!"
+"бÑ\83деÑ\82е Ð¾Ñ\82Ñ\81оединенÑ\8b Ð¾Ñ\82 Ñ\81еÑ\80веÑ\80а, Ñ\82ак ÐºÐ°Ðº Ð±Ñ\8bÑ\82Ñ\8c Ð·Ñ\80ителем временно запрещено!"
 
 #: qcsrc/common/notifications/all.inc:443
 #, c-format
@@ -2894,12 +2893,12 @@ 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
 msgid "^BG%s%s^K1 was shot to death by ^BG%s^K1's Blaster%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð·Ð°Ñ\81Ñ\82Ñ\80елен Ð¸Ð· Ð\91лаÑ\81Ñ\82еÑ\80а ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 застрелен из Бластера ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:459
 #, c-format
@@ -2909,12 +2908,12 @@ msgstr "^BG%s^K1 отправил себя в ад из своего же Бла
 #: 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 испытал на себе силу Crylink'а ^BG%s^K1%s%s"
+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 "^BG%s^K1 испытал на себе силу собственного Crylink'а%s%s"
+msgstr "^BG%s^K1 испытал на себе силу собственного Крайлинка%s%s"
 
 #: qcsrc/common/notifications/all.inc:462
 #, c-format
@@ -2923,8 +2922,8 @@ msgstr "^BG%s%s^K1 скушал ракету ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-msgstr "^BG%s%s^K1 оказался слишком близко к ракете ^BG%s^K1%s%s"
+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
@@ -2934,22 +2933,22 @@ 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 был разорван зарядом Electro от ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван зарядом Электро ^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 почуял запах озона от Electro комбо ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 почуял запах озона от комбо Электро ^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 подошел слишком близко сфере Электро ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 подошёл слишком близко сфере Электро ^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 Ð´Ð¾Ð¸Ð³Ñ\80алÑ\81Ñ\8f Ñ\81 Ð­Ð»ÐµÐºÑ\82Ñ\80иÑ\87еÑ\81кими Ð·Ð°Ñ\80Ñ\8fдами%s%s"
+msgstr "^BG%s^K1 Ð´Ð¾Ð¸Ð³Ñ\80алÑ\81Ñ\8f Ñ\81 Ð·Ð°Ñ\80Ñ\8fдами Ð­Ð»ÐµÐºÑ\82Ñ\80о %s%s"
 
 #: qcsrc/common/notifications/all.inc:469
 #, 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,42 +2973,42 @@ 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
 msgid "^BG%s%s^K1 was pummeled by a burst of ^BG%s^K1's Hagar rockets%s%s"
-msgstr "^BG%s%s^K1 был утрамбован очередью из Hagar'а от ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 утрамбован очередью из Хагара от ^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 Ð±Ñ\8bл Ð¾Ð±Ñ\81Ñ\82Ñ\80елÑ\8fн Ð¸Ð· Hagar'а Ñ\81о Ñ\81Ñ\82оÑ\80онÑ\8b ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð¾Ð±Ñ\81Ñ\82Ñ\80елÑ\8fн Ð¸Ð· Ð¥Ð°Ð³Ð°Ñ\80а ^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 доигрался с ракетками из Hagar'а%s%s"
+msgstr "^BG%s^K1 доигрался с ракетками из Хагара%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 был порезан HLAC'ом ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 был порезан из ТЛО ^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 не соблюдал технику безопасности при обращении с HLAC%s%s"
+msgstr "^BG%s^K1 не соблюдал технику безопасности при обращении с ТЛО %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 Ð±Ñ\8bл Ð·Ð°Ñ\81Ñ\82Ñ\80елен Ð¸Ð· Ð¢Ñ\8fжÑ\91лого Ð¿улемёта ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð·Ð°Ñ\81Ñ\82Ñ\80елен Ð¸Ð· Ð¢Ñ\8fжÑ\91лого Ð\9fулемёта ^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 был разорван на куски из Тяжёлого пулемёта ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван на куски из Тяжёлого Пулемёта ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:481
 #, c-format
@@ -3031,12 +3030,12 @@ msgstr "^BGУ %s^K1 завяли уши от игры на @!#%%й Бутылк
 #: 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 был расстрелян из Пулемёта ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 расстрелян из Пулемёта ^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 Ð±Ñ\8bл Ð¸Ð·Ñ\80еÑ\88еÑ\87ен Пулемётом ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð¸Ð·Ñ\80еÑ\88еÑ\87Ñ\91н Пулемётом ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:486
 #: qcsrc/common/notifications/all.inc:790
@@ -3058,48 +3057,49 @@ msgstr "^BG%s^K1 забыл о своей мине%s%s"
 #, c-format
 msgid "^BG%s%s^K1 got too close to ^BG%s^K1's Mortar grenade%s%s"
 msgstr ""
-"^BG%s%s^K1 оказался в зоне поражения гранаты, выпущенной из Mortar'a ^BG"
+"^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 "^BG%s%s^K1 отведал гранаты из Mortar'a ^BG%s^K1%s%s"
+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 "^BG%s^K1 не уследил за гранатой, выпущенной из своего Mortar'a%s%s"
+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 "^BG%s^K1 взорвал сам себя с помощью Mortar'a%s%s"
+msgstr "^BG%s^K1 взорвал сам себя с помощью Мортиры %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 был расстрелян из Rifle ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 расстрелян из Винтовки ^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 погиб после знакомства с пулей из Rifle ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 погиб после знакомства с пулей из Винтовки ^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 не смог избежать знакомства с пулей из Rifle ^BG%s^K1%s%s"
+msgstr ""
+"^BG%s%s^K1 не смог избежать знакомства с пулей из Винтовки ^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 не смог спрятаться от Rifle ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 не смог спрятаться от Винтовки ^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 был распилен пополам Реактивной Бензопилой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 распилен пополам Реактивной Бензопилой ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:498
 #, c-format
@@ -3109,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
@@ -3126,8 +3126,7 @@ 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 ""
-"^BG%s%s^K1 был захвачен системой самонаведения Самонаводчика ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 был захвачен системой Самонаводчика ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:503
 #, c-format
@@ -3137,22 +3136,22 @@ msgstr "^BG%s^K1 доигрался с ракетками из Самонаво
 #: 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 Ð±Ñ\8bл Ñ\80аÑ\81Ñ\82Ñ\80елÑ\8fн из Шоковой Волны ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð·Ð°Ñ\81Ñ\82Ñ\80елен из Шоковой Волны ^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 Ð±Ñ\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
 msgid "^BG%s%s^K1 was gunned down by ^BG%s^K1's Shotgun%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¿Ñ\80иÑ\81Ñ\82Ñ\80елен Ð¸Ð· Shotgun'a ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 Ð¿Ñ\80иÑ\81Ñ\82Ñ\80елен Ð¸Ð· Ð\94Ñ\80обовика ^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 отшлёпал ^BG%s^K1 своим большим Shotgun'ом%s%s"
+msgstr "^BG%s%s^K1 отшлёпал ^BG%s^K1 своим большим Дробовиком%s%s"
 
 #: qcsrc/common/notifications/all.inc:508
 #, c-format
@@ -3172,12 +3171,12 @@ 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
 msgid "^BG%s%s^K1 has been vaporized by ^BG%s^K1's Vortex%s%s"
-msgstr "^BG%s%s^K1 Ð±Ñ\8bл Ð¸Ñ\81паÑ\80Ñ\91н Ñ\81 Ð¿Ð¾Ð¼Ð¾Ñ\89Ñ\8cÑ\8e Ð\92иÑ\85Ñ\80Ñ\8f ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 испарён с помощью Вихря ^BG%s^K1%s%s"
 
 #: qcsrc/common/notifications/all.inc:537
 msgid "^F4You are now alone!"
@@ -3206,7 +3205,7 @@ msgstr "^F4Игра начнётся через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:545
 msgid "^F4Round starts in ^COUNT"
-msgstr "^F4Раунд начнется через ^COUNT"
+msgstr "^F4Раунд начнётся через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:546
 msgid "^F4Round cannot start"
@@ -3295,11 +3294,11 @@ msgstr "^BGВы передали флаг %s"
 
 #: qcsrc/common/notifications/all.inc:569
 msgid "^BGYou got the ^TC^TT^BG flag!"
-msgstr "^BGÐ\92Ñ\8b Ð·Ð°Ð±Ñ\80али ^TC^TT^BG флаг!"
+msgstr "^BGÐ\92Ñ\8b Ð¿Ð¾Ð´Ð½Ñ\8fли ^TC^TT^BG флаг!"
 
 #: qcsrc/common/notifications/all.inc:570
 msgid "^BGYou got the flag!"
-msgstr "^BGÐ\92Ñ\8b Ð·Ð°Ð±Ñ\80али флаг!"
+msgstr "^BGÐ\92Ñ\8b Ð¿Ð¾Ð´Ð½Ñ\8fли флаг!"
 
 #: qcsrc/common/notifications/all.inc:571
 #, c-format
@@ -3314,56 +3313,52 @@ msgstr "^BGВы подобрали %sвражеский^BG флаг, верни
 #: qcsrc/common/notifications/all.inc:573
 #, c-format
 msgid "^BGThe %senemy^BG got your flag! Retrieve it!"
-msgstr "^BG%sпротивник^BG забрал ваш флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник^BG забрал ваш флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:574
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"
-msgstr "^BG%sпротивник (^BG%s%s)^BG забрал ваш флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник (^BG%s%s)^BG забрал ваш флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:575
 #, c-format
 msgid "^BGThe %senemy^BG got the flag! Retrieve it!"
-msgstr "^BG%sпротивник^BG забрал флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник^BG забрал флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:576
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"
-msgstr "^BG%sпротивник (^BG%s%s)^BG забрал флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник (^BG%s%s)^BG забрал флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:577
 #, c-format
 msgid "^BGThe %senemy^BG got their flag! Retrieve it!"
-msgstr "^BG%sпротивник^BG забрал свой флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник^BG забрал свой флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:578
 #, c-format
 msgid "^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"
-msgstr "^BG%sпротивник (^BG%s%s)^BG забрал свой флаг! Верните его!"
+msgstr "^BG%sÐ\9fротивник (^BG%s%s)^BG забрал свой флаг! Верните его!"
 
 #: qcsrc/common/notifications/all.inc:579
 #, c-format
 msgid "^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"
-msgstr ""
-"^BGВаш %sтоварищ по команде^BG заполучил ^TC^TT^BG флаг! Защищайте его!"
+msgstr "^BGВаш %sсоюзник^BG заполучил ^TC^TT^BG флаг! Защищайте его!"
 
 #: 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 ""
-"^BGВаш %sтоварищ по команде (^BG%s%s)^BG заполучил ^TC^TT^BG флаг! Защищайте "
-"его!"
+msgstr "^BGВаш %sсоюзник (^BG%s%s)^BG заполучил ^TC^TT^BG флаг! Защищайте его!"
 
 #: qcsrc/common/notifications/all.inc:581
 #, c-format
 msgid "^BGYour %steam mate^BG got the flag! Protect them!"
-msgstr "^BGÐ\92аÑ\88 %sÑ\82оваÑ\80иÑ\89 Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ^BG заполучил флаг! Защищайте его!"
+msgstr "^BGÐ\92аÑ\88 %sÑ\81оÑ\8eзник^BG заполучил флаг! Защищайте его!"
 
 #: qcsrc/common/notifications/all.inc:582
 #, c-format
 msgid "^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"
-msgstr ""
-"^BGВаш %sтоварищ по команде (^BG%s%s)^BG заполучил флаг! Защищайте его!"
+msgstr "^BGВаш %sсоюзник (^BG%s%s)^BG заполучил флаг! Защищайте его!"
 
 #: qcsrc/common/notifications/all.inc:583
 msgid "^BGEnemies can now see you on radar!"
@@ -3385,7 +3380,7 @@ msgstr ""
 #: qcsrc/common/notifications/all.inc:590
 #, c-format
 msgid "^K3%sYou fragged ^BG%s"
-msgstr "^K3%sÐ\92Ñ\8b Ñ\83били ^BG%s"
+msgstr "^K3%sÐ\92Ñ\8b Ñ\84Ñ\80агнÑ\83ли ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:591
 #: qcsrc/common/notifications/all.inc:600
@@ -3397,7 +3392,7 @@ msgstr "^K3%sВы отыграли очко у ^BG%s"
 #: qcsrc/common/notifications/all.inc:592
 #, c-format
 msgid "^K1%sYou were fragged by ^BG%s"
-msgstr "^K1%sÐ\92аÑ\81 Ñ\83бил ^BG%s"
+msgstr "^K1%sÐ\92аÑ\81 Ñ\84Ñ\80агнÑ\83л ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:593
 #: qcsrc/common/notifications/all.inc:602
@@ -3429,7 +3424,7 @@ msgstr "^K1%sВы были заморожены игроком ^BG%s"
 #: qcsrc/common/notifications/all.inc:617
 #, c-format
 msgid "^K1%sYou typefragged ^BG%s"
-msgstr "^K1%sÐ\92Ñ\8b Ñ\83били ^BG%s, пока он писал"
+msgstr "^K1%sÐ\92Ñ\8b Ñ\84Ñ\80агнÑ\83ли ^BG%s, пока он писал"
 
 #: qcsrc/common/notifications/all.inc:618
 #, c-format
@@ -3439,12 +3434,12 @@ msgstr "^K1%sВы отыграли очко у ^BG%s^K1 пока они писа
 #: qcsrc/common/notifications/all.inc:619
 #, c-format
 msgid "^K1%sYou were typefragged by ^BG%s"
-msgstr "^K1%sÐ\9fока Ð²Ñ\8b Ð¿Ð¸Ñ\81али, Ð²Ð°Ñ\81 Ñ\83бил ^BG%s"
+msgstr "^K1%sÐ\9fока Ð²Ñ\8b Ð¿Ð¸Ñ\81али, Ð²Ð°Ñ\81 Ñ\84Ñ\80агнÑ\83л ^BG%s"
 
 #: qcsrc/common/notifications/all.inc:620
 #, c-format
 msgid "^K1%sYou were scored against by ^BG%s^K1 while typing"
-msgstr "^K1%sВас фрагнул игрок ^BG%s^K1 пока вы печатали"
+msgstr "^K1%sВас фрагнул игрок ^BG%s^K1, пока вы писали"
 
 #: qcsrc/common/notifications/all.inc:626
 #, c-format
@@ -3466,11 +3461,11 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:630
 msgid "^K1Don't go against your team mates!"
-msgstr "^K1Ð\9dе Ñ\83бивайÑ\82е Ñ\82оваÑ\80иÑ\89ей Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ!"
+msgstr "^K1Ð\9dе Ñ\83бивайÑ\82е Ñ\81оÑ\8eзников!"
 
 #: qcsrc/common/notifications/all.inc:630
 msgid "^K1Don't shoot your team mates!"
-msgstr "^K1Ð\9dе Ñ\81Ñ\82Ñ\80елÑ\8fйÑ\82е Ð² Ñ\81воиÑ\85 Ñ\82оваÑ\80иÑ\89ей Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ!"
+msgstr "^K1Ð\9dе Ñ\81Ñ\82Ñ\80елÑ\8fйÑ\82е Ð² Ñ\81воиÑ\85 Ñ\81оÑ\8eзников!"
 
 #: qcsrc/common/notifications/all.inc:631
 msgid "^K1Die camper!"
@@ -3539,7 +3534,7 @@ msgstr "^K1Нахождение рядом со взрывом напалма о
 
 #: qcsrc/common/notifications/all.inc:642
 msgid "^K1You felt a little chilly!"
-msgstr "^K1Ð\92Ñ\8b Ð¿Ð¾Ñ\87Ñ\83вÑ\81Ñ\82вовали Ð¿Ñ\80оÑ\85ладеÑ\86!"
+msgstr "^K1Ð\92Ñ\8b Ð¿Ð¾Ñ\87Ñ\83вÑ\81Ñ\82вовали Ð¾Ð·Ð½Ð¾Ð±!"
 
 #: qcsrc/common/notifications/all.inc:642
 msgid "^K1You got a little bit too cold!"
@@ -3559,7 +3554,7 @@ msgstr "^K1Вы погибли от отсутствия патронов..."
 
 #: qcsrc/common/notifications/all.inc:645
 msgid "^K1You grew too old without taking your medicine"
-msgstr "^K1Вы прожили слишком долго, для человека не принимающего лекарств"
+msgstr "^K1Вы прожили слишком долго для человека не принимающего лекарств"
 
 #: qcsrc/common/notifications/all.inc:645
 msgid "^K1You need to preserve your health"
@@ -3600,7 +3595,7 @@ msgstr "^K1Ваша встреча с турелью закончилась пл
 
 #: qcsrc/common/notifications/all.inc:652
 msgid "^K1You were fragged by a turret!"
-msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\83биты турелью!"
+msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\84Ñ\80агнÑ\83ты турелью!"
 
 #: qcsrc/common/notifications/all.inc:653
 msgid "^K1You had an unfortunate run in with an eWheel turret!"
@@ -3608,19 +3603,19 @@ msgstr "^K1Ваша встреча с турелью еМобиля законч
 
 #: qcsrc/common/notifications/all.inc:653
 msgid "^K1You were fragged by an eWheel turret!"
-msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\83биты турелью еМобиля!"
+msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\84Ñ\80агнÑ\83ты турелью еМобиля!"
 
 #: qcsrc/common/notifications/all.inc:654
 msgid "^K1You had an unfortunate run in with a Walker turret!"
-msgstr "^K1Ваша встреча с турелью Walker закончилась плачевно!"
+msgstr "^K1Ваша встреча с турелью Ходуна закончилась плачевно!"
 
 #: qcsrc/common/notifications/all.inc:654
 msgid "^K1You were fragged by a Walker turret!"
-msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\83биÑ\82Ñ\8b Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e Walker!"
+msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\84Ñ\80агнÑ\83Ñ\82Ñ\8b Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e Ð¥Ð¾Ð´Ñ\83на!"
 
 #: qcsrc/common/notifications/all.inc:655
 msgid "^K1You got caught in the blast of a Bumblebee explosion!"
-msgstr "^K1Ð\92аÑ\81 Ð·Ð°Ð´ÐµÐ»Ð¾ Ð²Ð·Ñ\80Ñ\8bвной Ð²Ð¾Ð»Ð½Ð¾Ð¹ Ð¾Ñ\82 Bumblebee!"
+msgstr "^K1Ð\92аÑ\81 Ð·Ð°Ð´ÐµÐ»Ð¾ Ð²Ð·Ñ\80Ñ\8bвной Ð²Ð¾Ð»Ð½Ð¾Ð¹ Ð¨Ð¼ÐµÐ»Ñ\8f!"
 
 #: qcsrc/common/notifications/all.inc:656
 msgid "^K1You were crushed by a vehicle!"
@@ -3628,27 +3623,27 @@ msgstr "^K1Вы были раздавлены весом тяжёлой маши
 
 #: qcsrc/common/notifications/all.inc:657
 msgid "^K1You were caught in a Raptor cluster bomb!"
-msgstr "^K1Вас накрыло кассетными бомбами с Raptor'а!"
+msgstr "^K1Вас накрыло кассетными бомбами с Ящера!"
 
 #: qcsrc/common/notifications/all.inc:658
 msgid "^K1You got caught in the blast of a Raptor explosion!"
-msgstr "^K1Вас задело взрывной волной от Raptor'a!"
+msgstr "^K1Вас задело взрывной волной от Ящера!"
 
 #: qcsrc/common/notifications/all.inc:659
 msgid "^K1You got caught in the blast of a Spiderbot explosion!"
-msgstr "^K1Вас задело взрывной волной от Spiderbot'a!"
+msgstr "^K1Вас задело взрывной волной от Паука-ботa!"
 
 #: qcsrc/common/notifications/all.inc:660
 msgid "^K1You were blasted to bits by a Spiderbot rocket!"
-msgstr "^K1Ракета Spiderbot'а порвала Вас в клочья!"
+msgstr "^K1Ракета Паука-бота порвала вас в клочья!"
 
 #: qcsrc/common/notifications/all.inc:661
 msgid "^K1You got caught in the blast of a Racer explosion!"
-msgstr "^K1Вас задело взрывной волной от Racer'а!"
+msgstr "^K1Вас задело взрывной волной от Гонщика!"
 
 #: qcsrc/common/notifications/all.inc:662
 msgid "^K1You couldn't find shelter from a Racer rocket!"
-msgstr "^K1Вы не смогли укрыться от ракеты Racer'а!"
+msgstr "^K1Вы не смогли укрыться от ракеты Гонщика!"
 
 #: qcsrc/common/notifications/all.inc:663
 msgid "^K1Watch your step!"
@@ -3657,22 +3652,22 @@ msgstr "^K1Смотри под ноги!"
 #: qcsrc/common/notifications/all.inc:665
 #, c-format
 msgid "^K1Moron! You fragged ^BG%s^K1, a team mate!"
-msgstr "^K1Ð\94ебил! Ð¢Ñ\8b Ñ\83бил ^BG%s^K1, Ñ\81воего Ñ\82оваÑ\80иÑ\89а Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ!"
+msgstr "^K1Ð\9dегодÑ\8fй! Ð\92Ñ\8b Ñ\84Ñ\80агнÑ\83ли ^BG%s^K1, Ñ\81воего Ñ\81оÑ\8eзника!"
 
 #: qcsrc/common/notifications/all.inc:665
 #, c-format
 msgid "^K1Moron! You went against ^BG%s^K1, a team mate!"
-msgstr "^K1Ð\94ебил! Ð¢Ñ\8b Ð½Ð°Ð¿Ð°Ð» Ð½Ð° ^BG%s^K1, Ñ\81воего Ñ\82оваÑ\80иÑ\89а Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ!"
+msgstr "^K1Ð\9dегодÑ\8fй! Ð\92Ñ\8b Ð½Ð°Ð¿Ð°Ð»Ð¸ Ð½Ð° ^BG%s^K1, Ñ\81воего Ñ\81оÑ\8eзника!"
 
 #: qcsrc/common/notifications/all.inc:666
 #, c-format
 msgid "^K1You were fragged by ^BG%s^K1, a team mate"
-msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\83биÑ\82Ñ\8b ^BG%s^K1, Ð²Ð°Ñ\88им Ñ\82оваÑ\80иÑ\89ем Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ"
+msgstr "^K1Ð\92Ñ\8b Ð±Ñ\8bли Ñ\84Ñ\80агнÑ\83Ñ\82Ñ\8b ^BG%s^K1, Ð²Ð°Ñ\88им Ñ\81оÑ\8eзником"
 
 #: qcsrc/common/notifications/all.inc:666
 #, c-format
 msgid "^K1You were scored against by ^BG%s^K1, a team mate"
-msgstr "^K1Ð\92Ñ\8b Ð¿Ñ\80оигÑ\80али Ð¾Ñ\87ко ^BG%s^K1, Ñ\81воемÑ\83 Ñ\82оваÑ\80иÑ\89Ñ\83 Ð¿Ð¾ ÐºÐ¾Ð¼Ð°Ð½Ð´Ðµ"
+msgstr "^K1Ð\92Ñ\8b Ð¿Ñ\80оигÑ\80али Ð¾Ñ\87ко ^BG%s^K1, Ñ\81воемÑ\83 Ñ\81оÑ\8eзникÑ\83"
 
 #: qcsrc/common/notifications/all.inc:668
 msgid ""
@@ -3680,7 +3675,7 @@ msgid ""
 "^BGDisconnecting in ^COUNT..."
 msgstr ""
 "^K1Хватит бездельничать!\n"
-"^BGРаÑ\81Ñ\81оединение через ^COUNT..."
+"^BGÐ\9eÑ\82клÑ\8eÑ\87ение через ^COUNT..."
 
 #: qcsrc/common/notifications/all.inc:670
 #, c-format
@@ -3742,7 +3737,7 @@ msgstr "^K1A %s прибыл!"
 
 #: qcsrc/common/notifications/all.inc:694
 msgid "^BGYou got the ^F1Fuel regenerator"
-msgstr "^BGУ Ð²Ð°Ñ\81 ÐµÑ\81Ñ\82Ñ\8c ^F1Ð\92оÑ\81Ñ\81Ñ\82ановиÑ\82елÑ\8c топлива"
+msgstr "^BGУ Ð²Ð°Ñ\81 ÐµÑ\81Ñ\82Ñ\8c ^F1РегенеÑ\80аÑ\82оÑ\80 топлива"
 
 #: qcsrc/common/notifications/all.inc:695
 msgid "^BGYou got the ^F1Jet pack"
@@ -3785,7 +3780,7 @@ msgid ""
 "^BGAll keys are in ^TC^TT team^BG's hands!\n"
 "Interfere ^F4NOW^BG!"
 msgstr ""
-"^BG^TC^TT команда^BG собрала все ключи!\n"
+"^BGКоманда ^TC^TT^BG собрала все ключи!\n"
 "Помешайте им встретиться. ^F4БЫСТРО^BG!"
 
 #: qcsrc/common/notifications/all.inc:713
@@ -3828,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!"
@@ -3836,7 +3831,7 @@ msgstr "^F4^COUNT^BG осталось на поиск патронов!"
 
 #: qcsrc/common/notifications/all.inc:725
 msgid "^BGGet some ammo or you'll be dead in ^F4^COUNT^BG!"
-msgstr "^BGНайдите патронов, иначе вы умрёте через ^F4^COUNT^BG!"
+msgstr "^BGНайдите патроны, иначе вы погибните через ^F4^COUNT^BG!"
 
 #: qcsrc/common/notifications/all.inc:725
 msgid "^BGGet some ammo! ^F4^COUNT^BG left!"
@@ -3869,7 +3864,7 @@ msgstr "^BGВы захватили контрольную точку %s^BG"
 #: qcsrc/common/notifications/all.inc:734
 #, c-format
 msgid "^TC^TT^BG team captured %s^BG control point"
-msgstr "Команда ^TC^TT^BG захватила контрольную точку %s^BG"
+msgstr "^BGКоманда ^TC^TT^BG захватила контрольную точку %s^BG"
 
 #: qcsrc/common/notifications/all.inc:735
 msgid "^BGThis control point currently cannot be captured"
@@ -3974,7 +3969,7 @@ msgstr "^F2Действие Щита закончилось"
 
 #: qcsrc/common/notifications/all.inc:756
 msgid "^F2You are on speed"
-msgstr "^F2Ваша скорость передвижения повышена"
+msgstr "^F2Вы двигаетесь быстрее"
 
 #: qcsrc/common/notifications/all.inc:757
 msgid "^F2Speed has worn off"
@@ -4002,7 +3997,7 @@ msgstr "^BGЗадача выполнена!"
 
 #: qcsrc/common/notifications/all.inc:767
 msgid "^BGThere are more to go..."
-msgstr "^BGВпереди еще много чего..."
+msgstr "^BGВпереди ещё много чего..."
 
 #: qcsrc/common/notifications/all.inc:768
 #, c-format
@@ -4031,7 +4026,7 @@ msgstr "^K1Смена команды через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:776
 msgid "^K1Spectating in ^COUNT"
-msgstr "^K1Ð\92Ñ\8b Ñ\81Ñ\82анеÑ\82е Ð½Ð°Ð±Ð»Ñ\8eдателем через ^COUNT"
+msgstr "^K1Ð\92Ñ\8b Ñ\81Ñ\82анеÑ\82е Ð·Ñ\80ителем через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:777
 msgid "^K1Suicide in ^COUNT"
@@ -4043,11 +4038,11 @@ msgstr "^F4Тайм-аут начнётся через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:780
 msgid "^F4Timeout ends in ^COUNT"
-msgstr "^F4Тайм-аут законится через ^COUNT"
+msgstr "^F4Тайм-аут закончится через ^COUNT"
 
 #: qcsrc/common/notifications/all.inc:782
 msgid "^K1Cannot join given minigame session!"
-msgstr "^K1Невозможно присоединиться к данной сессии миниигры!"
+msgstr "^K1Невозможно присоединиться к данной сессии мини-игры!"
 
 #: qcsrc/common/notifications/all.inc:784
 #, c-format
@@ -4057,7 +4052,7 @@ msgstr "^BGНажмите ^F2%s^BG, чтобы войти или выйти из
 #: qcsrc/common/notifications/all.inc:785
 #, c-format
 msgid "^BGPress ^F2%s^BG to enter the vehicle gunner"
-msgstr "^BGНажмите ^F2%s^BG, чтобы стать пулемётчиком траспорта"
+msgstr "^BGНажмите ^F2%s^BG, чтобы стать пулемётчиком транспорта"
 
 #: qcsrc/common/notifications/all.inc:786
 #, c-format
@@ -4154,7 +4149,7 @@ msgstr "%s^K1 начал РЕЗНЮ! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:446
 msgid "MASSACRE! "
-msgstr "РЕЗНЯ!"
+msgstr "РЕЗНЯ! "
 
 #: qcsrc/common/notifications/all.qh:447
 #, c-format
@@ -4173,7 +4168,7 @@ msgstr "БЕСПРЕДЕЛ! "
 #: qcsrc/common/notifications/all.qh:448
 #, c-format
 msgid "%s^K1 is a BERSERKER! %s^BG"
-msgstr "%s^K1 БЕРСЕРКЕР! %s^BG"
+msgstr "%s^K1 БЕРСЕРК! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:448
 #, c-format
@@ -4182,7 +4177,7 @@ msgstr "%s^K1 набрал ДВАДЦАТЬ ОЧКОВ ПОДРЯД! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:448
 msgid "BERSERKER! "
-msgstr "БЕРСЕРКЕР! "
+msgstr "БЕРСЕРК! "
 
 #: qcsrc/common/notifications/all.qh:449
 #, c-format
@@ -4196,7 +4191,7 @@ msgstr "%s^K1 набрал ДВАДЦАТЬ ПЯТЬ ОЧКОВ ПОДРЯД! %s
 
 #: qcsrc/common/notifications/all.qh:449
 msgid "CARNAGE! "
-msgstr "БОЙНЯ!"
+msgstr "БОЙНЯ! "
 
 #: qcsrc/common/notifications/all.qh:450
 #, c-format
@@ -4210,7 +4205,7 @@ msgstr "%s^K1 предрекает АРМАГЕДДОН! %s^BG"
 
 #: qcsrc/common/notifications/all.qh:450
 msgid "ARMAGEDDON! "
-msgstr "АРМАГЕДДОН!"
+msgstr "АРМАГЕДДОН! "
 
 #: qcsrc/common/notifications/all.qh:457
 #, c-format
@@ -4299,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
@@ -4380,7 +4375,7 @@ msgstr "GENERATOR^Розовый"
 
 #: qcsrc/common/turrets/all.qh:51
 msgid "Turrets dump command only works with sv_cmd.\n"
-msgstr "Команда выгрузки туреток работает только с sv_cmd.\n"
+msgstr "Команда выгрузки турелей работает только с sv_cmd.\n"
 
 #: qcsrc/common/turrets/cl_turrets.qc:129
 #, c-format
@@ -4401,7 +4396,7 @@ msgstr "еМобиль"
 
 #: qcsrc/common/turrets/turret/flac.qh:13
 msgid "FLAC Cannon"
-msgstr "Ð\97ениÑ\82наÑ\8f Ð¿ушка"
+msgstr "Ð\97ениÑ\82наÑ\8f Ð\9fушка"
 
 #: qcsrc/common/turrets/turret/flac_weapon.qh:7
 msgid "FLAC"
@@ -4474,11 +4469,11 @@ msgstr "Катушка Теслы"
 
 #: qcsrc/common/turrets/turret/walker.qh:15
 msgid "Walker Turret"
-msgstr "ХодÑ\8fÑ\87аÑ\8f Ñ\82Ñ\83Ñ\80елÑ\8c"
+msgstr "ТÑ\83Ñ\80елÑ\8c Ð¥Ð¾Ð´Ñ\83на"
 
 #: qcsrc/common/turrets/turret/walker_weapon.qh:7
 msgid "Walker"
-msgstr "Ходунки"
+msgstr "Ходун"
 
 #: qcsrc/common/vehicles/cl_vehicles.qc:192
 #, c-format
@@ -4523,7 +4518,7 @@ msgstr "Вспышка Ящера"
 
 #: qcsrc/common/vehicles/vehicle/spiderbot.qh:19
 msgid "Spiderbot"
-msgstr "Паук-робот"
+msgstr "Паук-бот"
 
 #: qcsrc/common/weapons/all.qh:78
 msgid "Weapons dump command only works with sv_cmd.\n"
@@ -4910,7 +4905,7 @@ msgstr "Код игры"
 
 #: qcsrc/menu/xonotic/credits.qc:116
 msgid "Marketing / PR"
-msgstr "Маркетинг / Cвязи с общественностью"
+msgstr "Маркетинг / Связи с общественностью"
 
 #: qcsrc/menu/xonotic/credits.qc:122
 msgid "Legal"
@@ -5131,7 +5126,7 @@ msgstr "Добро пожаловать"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:16
 msgid "Ammunition display:"
-msgstr "Ð\9fоказ патронов:"
+msgstr "Ð\9eÑ\82обÑ\80ажение патронов:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:19
 msgid "Show only current ammo type"
@@ -5140,17 +5135,17 @@ msgstr "Показывать только текущий вид патронов
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:22
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:44
 msgid "Noncurrent alpha:"
-msgstr "Ð\94Ñ\80Ñ\83гаÑ\8f Ð¿Ñ\80озÑ\80аноÑ\87ть:"
+msgstr "Ð\9dеакÑ\82ивнаÑ\8f Ð¿Ñ\80озÑ\80аÑ\87ноÑ\81ть:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:26
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:48
 msgid "Noncurrent scale:"
-msgstr "Ð\94Ñ\80Ñ\83гой размер:"
+msgstr "Ð\9dеакÑ\82ивнÑ\8bй размер:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:30
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:24
 msgid "Align icon:"
-msgstr "Ð\92Ñ\8bÑ\80овнÑ\8fÑ\82Ñ\8c Ð·Ð½Ð°Ñ\87ок:"
+msgstr "Ð\92Ñ\8bÑ\80овнÑ\8fÑ\82Ñ\8c Ð·Ð½Ð°Ñ\87ки:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_ammo.qc:31
 #: qcsrc/menu/xonotic/dialog_hudpanel_centerprint.qc:30
@@ -5297,7 +5292,7 @@ msgstr "Панель информационных сообщений"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:16
 msgid "PNL^Disabled"
-msgstr "PNL^Ð\92Ñ\8bключена"
+msgstr "PNL^Ð\9eÑ\82ключена"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:17
 msgid "PNL^Enabled spectating"
@@ -5429,7 +5424,7 @@ msgstr "км/ч"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:54
 msgid "mph"
-msgstr "милÑ\8f/ч"
+msgstr "милÑ\8c/ч"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:55
 msgid "knots"
@@ -5449,7 +5444,7 @@ msgstr "Ускорение:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:67
 msgid "Include vertical acceleration"
-msgstr "С вертикальним ускорением"
+msgstr "С вертикальным ускорением"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_physics.qh:6
 msgid "Physics Panel"
@@ -5539,19 +5534,19 @@ msgstr "Режим увел.:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:46
 msgid "Zoomed in"
-msgstr "Приближён"
+msgstr "Приближен"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:47
 msgid "Zoomed out"
-msgstr "Не приближён"
+msgstr "Не приближен"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:48
 msgid "Always zoomed"
-msgstr "Всегда приближён"
+msgstr "Всегда приближен"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:49
 msgid "Never zoomed"
-msgstr "Никогда не приближён"
+msgstr "Никогда не приближен"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_radar.qh:6
 msgid "Radar Panel"
@@ -5643,7 +5638,7 @@ msgstr "Иконки оружия:"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:41
 msgid "Show only owned weapons"
-msgstr "Показывать только свое оружие"
+msgstr "Показывать только своё оружие"
 
 #: qcsrc/menu/xonotic/dialog_hudpanel_weapons.qc:52
 msgid "Show weapon ID as:"
@@ -5708,7 +5703,7 @@ msgstr "Обновить"
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:33
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:30
 msgid "Set skin"
-msgstr "Ð\92Ñ\8bбÑ\80ать тему"
+msgstr "Ð\9fÑ\80именить тему"
 
 #: qcsrc/menu/xonotic/dialog_hudsetup_exit.qc:37
 msgid "Save current skin"
@@ -5901,7 +5896,7 @@ msgstr "Предел фрагов:"
 #: 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 "Количество фрагов, необходимых для завершения состязания"
+msgstr "Количество фрагов, необходимых для завершения матча"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
 msgid "Capture limit:"
@@ -5909,7 +5904,7 @@ msgstr "Предел захватов:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:67
 msgid "The amount of captures needed before the match will end"
-msgstr "Количество захватов, необходимых для завершения состязания"
+msgstr "Количество захватов, необходимых для завершения матча"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:68
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:69
@@ -5925,7 +5920,7 @@ msgstr "Предел очков:"
 #: 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 "Количество очков, необходимых для завершения состязания"
+msgstr "Количество очков, необходимых для завершения матча"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:70
 msgid "Lives:"
@@ -5941,7 +5936,7 @@ msgstr "Цели:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:72
 msgid "The amount of goals needed before the match will end"
-msgstr "Количество голов, необходимых для завершения состязания"
+msgstr "Количество голов, необходимых для завершения матча"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:97
 msgid "Gametype"
@@ -5953,8 +5948,7 @@ msgstr "Предел времени:"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:104
 msgid "Timelimit in minutes that when hit, will end the match"
-msgstr ""
-"Ограничение времени в минутах, состязание закончится при его достижении"
+msgstr "Ограничение времени в минутах, после которого закончится матч"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:105
 #, c-format
@@ -6079,8 +6073,8 @@ msgid ""
 "Click here or Ctrl-F to provide a keyword to narrow down the map list. Ctrl-"
 "Delete to clear; Enter when done."
 msgstr ""
-"Нажмите здесь или Ctrl-F, чтобы задать ключевое слово для сужения списка "
-"карт. Ctrl-Delete, чтобы очистить; Enter, когда закончите."
+"Нажмите здесь или Ctrl+F, чтобы задать ключевое слово для сужения списка "
+"карт. Ctrl+Delete, чтобы очистить; Enter, когда закончите."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:207
 msgid "Add shown"
@@ -6137,7 +6131,7 @@ msgstr "Закрыть"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qc:96
 msgid "MAP^Play"
-msgstr "Играть"
+msgstr "MAP^Играть"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mapinfo.qh:7
 msgid "Map Information"
@@ -6164,12 +6158,12 @@ msgstr "Уклонение"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:63
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:267
 msgid "InstaGib"
-msgstr "Ð\98нÑ\81Ñ\82аÐ\93иб"
+msgstr "Ð\98нÑ\81Ñ\82агиб"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:65
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:216
 msgid "New Toys"
-msgstr "Ð\9dовÑ\8bе Ð\98грушки"
+msgstr "Ð\9dовÑ\8bе Ð¸грушки"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:67
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:272
@@ -6179,12 +6173,12 @@ msgstr "НИКС"
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:69
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:220
 msgid "Rocket Flying"
-msgstr "РакеÑ\82нÑ\8bй Ð\9fолÑ\91Ñ\82"
+msgstr "Ð\9fолÑ\91Ñ\82 Ð½Ð° Ñ\80акеÑ\82е"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:71
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:212
 msgid "Invincible Projectiles"
-msgstr "Неразрушимые Снаряды"
+msgstr "Неразрушимые снаряды"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:75
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:282
@@ -6309,7 +6303,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
 msgid "Weapons stay after they are picked up"
-msgstr "Ð\92Ñ\81Ñ\91 Ñ\81обÑ\80анное Ð¾Ñ\80Ñ\83жие Ð¾Ñ\81Ñ\82аÑ\91Ñ\82Ñ\81Ñ\8f Ð¿Ð¾Ñ\81ле Ð²Ð¾Ð·Ñ\80ождений"
+msgstr "Ð\9fÑ\83Ñ\88ки Ð¾Ñ\81Ñ\82аÑ\8eÑ\82Ñ\81Ñ\8f Ð¿Ð¾Ñ\81ле Ð¿Ð¾Ð´Ð±Ð¾Ñ\80а"
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
 msgid "Regular (no arena)"
@@ -6350,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оÑ\81Ñ\82епенного "
-"огня не наносит урона, но он хорош для прыжка."
+"Ñ\81екÑ\83нд, Ñ\87Ñ\82обÑ\8b Ð½Ð°Ð¹Ñ\82и ÐµÑ\89Ñ\91, Ð¸Ð½Ð°Ñ\87е Ð¾Ð½ Ð²Ñ\81Ñ\82Ñ\80еÑ\82иÑ\82 Ñ\81меÑ\80Ñ\82Ñ\8c. Ð ÐµÐ¶Ð¸Ð¼ Ð°Ð»Ñ\8cÑ\82еÑ\80наÑ\82ивного "
+"огня не наносит урона, но он хорош для трюков."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
 msgid ""
@@ -6359,9 +6353,9 @@ msgid ""
 "weapon. After some time, a countdown will start, after which everyone will "
 "switch to another weapon."
 msgstr ""
-"Xonotic без предметов — вместо подбора предметов, каждый играет с тем же "
-"оружием. Через некоторое время начнётся обратный отчёт, после чего "
-"переключится на другое оружие."
+"Xonotic без предметов — вместо подбора предметов, каждый играет одним и тем "
+"же Ð¾Ñ\80Ñ\83жием. Ð§ÐµÑ\80ез Ð½ÐµÐºÐ¾Ñ\82оÑ\80ое Ð²Ñ\80емÑ\8f Ð½Ð°Ñ\87нÑ\91Ñ\82Ñ\81Ñ\8f Ð¾Ð±Ñ\80аÑ\82нÑ\8bй Ð¾Ñ\82Ñ\87Ñ\91Ñ\82, Ð¿Ð¾Ñ\81ле Ñ\87его "
+"произойдёт переключение на другое оружие."
 
 #: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:277
 msgid "with blaster"
@@ -6403,7 +6397,8 @@ msgstr "Пауза"
 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"
@@ -6802,11 +6797,11 @@ msgstr "Установить прочность:"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:63
 msgid "Non-solid"
-msgstr "Не твердый"
+msgstr "Не твёрдый"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:64
 msgid "Solid"
-msgstr "Твердый"
+msgstr "Твёрдый"
 
 #: qcsrc/menu/xonotic/dialog_sandboxtools.qc:65
 msgid "Set physics:"
@@ -7027,7 +7022,7 @@ msgstr "7.1"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:134
 msgid "Swap stereo output channels"
-msgstr "Поменять местами стерео каналы"
+msgstr "Поменять местами каналы стерео"
 
 #: qcsrc/menu/xonotic/dialog_settings_audio.qc:135
 msgid "Swap left/right channels"
@@ -7149,7 +7144,7 @@ msgstr "Максимальная"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:65
 msgid "Geometry detail:"
-msgstr "Детали геометрии:"
+msgstr "Детализация геометрии:"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:67
 msgid "Change the smoothness of the curves on the map (default: normal)"
@@ -7250,8 +7245,8 @@ msgid ""
 "Disable textures completely for very slow hardware. This gives a huge "
 "performance boost, but looks very ugly. (default: disabled)"
 msgstr ""
-"Ð\92Ñ\8bклÑ\8eÑ\87иÑ\82Ñ\8c Ñ\82екÑ\81Ñ\82Ñ\83Ñ\80Ñ\8b Ð¿Ð¾Ð»Ð½Ð¾Ñ\81Ñ\82Ñ\8cÑ\8e для очень слабых компьютеров. Это даст лучшую "
-"пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c, Ð½Ð¾ Ð±Ñ\83деÑ\82 Ð²Ñ\8bглÑ\8fдеÑ\82Ñ\8c Ð¿Ð»Ð¾Ñ\85о (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Ð\9fолноÑ\81Ñ\82Ñ\8cÑ\8e Ð¾Ñ\82клÑ\8eÑ\87иÑ\82Ñ\8c Ñ\82екÑ\81Ñ\82Ñ\83Ñ\80Ñ\8b для очень слабых компьютеров. Это даст лучшую "
+"пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c, Ð½Ð¾ Ð±Ñ\83деÑ\82 Ð²Ñ\8bглÑ\8fдеÑ\82Ñ\8c Ð½Ðµ ÐºÑ\80аÑ\81иво (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:135
 msgid "Use lightmaps"
@@ -7294,7 +7289,7 @@ msgid ""
 "\"pop out\" of the flat 2D surface (default: disabled)"
 msgstr ""
 "Эффект рельефного текстурирования, который сделает 2D-текстуры трёхмерными "
-"(по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"(по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:148
 msgid "Relief mapping"
@@ -7306,7 +7301,7 @@ msgid ""
 "(default: disabled)"
 msgstr ""
 "Более высокое качество рельефного текстурирования, которое также снизит "
-"пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"пÑ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:152
 msgid "Reflections:"
@@ -7318,7 +7313,7 @@ msgid ""
 "with reflecting surfaces (default: disabled)"
 msgstr ""
 "Качество отражения и преломления, снижающее производительность на картах с "
-"зеÑ\80калÑ\8cнÑ\8bми Ð¿Ð¾Ð²ÐµÑ\80Ñ\85ноÑ\81Ñ\82Ñ\8fми (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"зеÑ\80калÑ\8cнÑ\8bми Ð¿Ð¾Ð²ÐµÑ\80Ñ\85ноÑ\81Ñ\82Ñ\8fми (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:156
 msgid "Resolution of reflections/refractions (default: good)"
@@ -7400,7 +7395,7 @@ msgid ""
 "of real dynamic lights (default: disabled)"
 msgstr ""
 "Включить быстрое, но некрасивое динамическое освещение отрисовкой ярких "
-"коÑ\80он Ð²Ð¼ÐµÑ\81Ñ\82о Ñ\80еалÑ\8cного Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ\87еÑ\81кого Ð¾Ñ\81веÑ\89ениÑ\8f (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"коÑ\80он Ð²Ð¼ÐµÑ\81Ñ\82о Ñ\80еалÑ\8cного Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ\87еÑ\81кого Ð¾Ñ\81веÑ\89ениÑ\8f (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:198
 msgid "Realtime dynamic lighting"
@@ -7422,7 +7417,7 @@ msgstr "Тени"
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:202
 msgid "Enable rendering of shadows from dynamic lights (default: disabled)"
 msgstr ""
-"Ð\92клÑ\8eÑ\87иÑ\82Ñ\8c Ð¾Ñ\82Ñ\80иÑ\81овкÑ\83 Ñ\82еней Ð¾Ñ\82 Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ\87еÑ\81кого Ð¾Ñ\81веÑ\89ениÑ\8f (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Ð\92клÑ\8eÑ\87иÑ\82Ñ\8c Ð¾Ñ\82Ñ\80иÑ\81овкÑ\83 Ñ\82еней Ð¾Ñ\82 Ð´Ð¸Ð½Ð°Ð¼Ð¸Ñ\87еÑ\81кого Ð¾Ñ\81веÑ\89ениÑ\8f (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:205
 msgid "Realtime world lighting"
@@ -7435,13 +7430,13 @@ msgid ""
 msgstr ""
 "Включить отрисовку полного освещения реального времени на картах, "
 "поддерживающих это. Примечание: это скажется на производительности (по "
-"Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:208
 msgid ""
 "Enable rendering of shadows from realtime world lights (default: disabled)"
 msgstr ""
-"Ð\92клÑ\8eÑ\87иÑ\82Ñ\8c Ð¾Ñ\82Ñ\80иÑ\81овкÑ\83 Ñ\82еней Ð¾Ñ\82 Ð¾Ñ\81веÑ\89ениÑ\8f Ñ\80еалÑ\8cного Ð²Ñ\80емени (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Ð\92клÑ\8eÑ\87иÑ\82Ñ\8c Ð¾Ñ\82Ñ\80иÑ\81овкÑ\83 Ñ\82еней Ð¾Ñ\82 Ð¾Ñ\81веÑ\89ениÑ\8f Ñ\80еалÑ\8cного Ð²Ñ\80емени (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:212
 msgid "Use normal maps"
@@ -7474,7 +7469,7 @@ msgid ""
 msgstr ""
 "Включить эффект свечения, который увеличивает яркость пикселей, "
 "соседствующих с очень яркими. Очень снижает производительность (по "
-"Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:226
 msgid "Extra postprocessing effects"
@@ -7486,7 +7481,7 @@ msgid ""
 "using a powerup (default: disabled)"
 msgstr ""
 "Включить специальные эффекты пост-обработки, когда получен урон, под водой "
-"или Ð²ÐºÐ»Ñ\8eÑ\87ен Ñ\81веÑ\82 (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"или Ð¸Ñ\81полÑ\8cзÑ\83еÑ\82Ñ\81Ñ\8f Ñ\83Ñ\81илиÑ\82елÑ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_effects.qc:232
 msgid "Motion blur strength - 0.4 recommended"
@@ -7598,7 +7593,7 @@ 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"
@@ -7761,7 +7756,7 @@ msgstr "Серии убийств в информационных сообщен
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:46
 msgid "SPREES^Disabled"
-msgstr "SPREES^Ð\92Ñ\8bключены"
+msgstr "SPREES^Ð\9eÑ\82ключены"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:47
 msgid "Target"
@@ -7785,7 +7780,7 @@ msgstr "Добавлять расширенную информацию о фра
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:62
 msgid "Add frag location to death messages when available"
-msgstr "Ð\94обавлÑ\8fÑ\82Ñ\8c Ñ\81ведениÑ\8f Ð¾ Ð¼ÐµÑ\81Ñ\82е Ñ\84Ñ\80ага Ð² Ñ\81ообÑ\89ениÑ\8f Ð¾ Ñ\81меÑ\80Ñ\82и ÐºÐ¾Ð³Ð´Ð° возможно"
+msgstr "УказÑ\8bваÑ\82Ñ\8c Ð¼ÐµÑ\81Ñ\82о Ñ\84Ñ\80ага Ð² Ñ\81ообÑ\89ениÑ\8f Ð¾ Ñ\81меÑ\80Ñ\82и, ÐµÑ\81ли возможно"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:65
 msgid "Gamemode Settings"
@@ -7855,7 +7850,7 @@ msgstr "Предметы"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:32
 msgid "Use simple 2D images instead of item models"
-msgstr "Показывать 2D изображения вместо моделей предметов"
+msgstr "Показывать иконки вместо моделей предметов"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:34
 msgid "Unavailable alpha:"
@@ -7875,7 +7870,7 @@ msgstr "Тёмный"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:41
 msgid "GHOITEMS^Tinted"
-msgstr "Окрашеные"
+msgstr "Окрашенные"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:42
 msgid "GHOITEMS^Normal"
@@ -7892,15 +7887,15 @@ msgstr "Игроки"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:51
 msgid "Force player models to mine"
-msgstr "Применить мою модель к другим игрокам"
+msgstr "Применять мою модель к игрокам"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:53
 msgid "Force player colors to mine"
-msgstr "Применить мои цвета к другим игрокам"
+msgstr "Применять мои цвета к игрокам"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:56
 msgid "In non teamplay modes only"
-msgstr "ТолÑ\8cко Ð² некомандных режимах"
+msgstr "Ð\92 некомандных режимах"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_model.qc:60
 msgid "Body fading:"
@@ -7952,7 +7947,7 @@ msgstr "Плавное приседание"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:42
 msgid "View waving while idle"
-msgstr "РаÑ\81каÑ\87ивание ÐºÐ°Ð¼ÐµÑ\80Ñ\8b Ð¿Ñ\80и Ð±ÐµÐ·Ð´ÐµÐ¹Ñ\81Ñ\82вовии"
+msgstr "Раскачивание камеры при бездействии"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:46
 msgid "View bobbing while walking around"
@@ -8029,15 +8024,15 @@ msgstr "Кратность"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:113
 msgid "Display reticle 2D overlay while zooming"
-msgstr "Показывать 2D эффект увеличительного прицела"
+msgstr "Показывать 2D-эффект увеличительного прицела"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:116
 msgid "Release zoom when you die or respawn"
-msgstr "Ð\92Ñ\8bключать увеличитель при смерти или возрождении"
+msgstr "Ð\9eÑ\82ключать увеличитель при смерти или возрождении"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qc:120
 msgid "Release zoom when you switch weapons"
-msgstr "Ð\92Ñ\8bключать увеличитель при смене оружия"
+msgstr "Ð\9eÑ\82ключать увеличитель при смене оружия"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_view.qh:7
 #: qcsrc/menu/xonotic/keybinder.qc:76
@@ -8058,7 +8053,7 @@ msgstr "Вниз"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:50
 msgid "Use priority list for weapon cycling"
-msgstr "Использовать приоритеты для прокрутки оружия"
+msgstr "Использовать приоритеты для переключения оружия"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:51
 msgid ""
@@ -8067,7 +8062,7 @@ msgstr "Использовать список выше при езде с ору
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:53
 msgid "Cycle through only usable weapon selections"
-msgstr "ЦиклиÑ\80овать только готовые к использованию оружия"
+msgstr "Ð\9fеÑ\80еклÑ\8eÑ\87ать только готовые к использованию оружия"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:57
 msgid "Auto switch weapons on pickup"
@@ -8082,7 +8077,7 @@ msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:61
 msgid "Release attack buttons when you switch weapons"
-msgstr "Ð\92Ñ\8bключать кнопку атаки при смене оружия"
+msgstr "Ð\9eÑ\82ключать кнопку атаки при смене оружия"
 
 #: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:64
 msgid "Draw 1st person weapon model"
@@ -8176,7 +8171,7 @@ msgstr "Отключить системное ускорение мыши"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:79
 msgid "Make use of DGA mouse input"
-msgstr "Использовать DGA ввод для мыши"
+msgstr "Использовать ввод с мыши через DGA"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:93
 msgid "Pressing \"enter console\" key also closes it"
@@ -8188,7 +8183,7 @@ msgstr "Использовать клавишу для открытия конс
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:96
 msgid "Automatically repeat jumping if holding jump"
-msgstr "Повторять прыжок автоматически при удержании"
+msgstr "Повторять прыжок автоматически при удержании нажатия"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:99
 msgid "Jetpack on jump:"
@@ -8196,7 +8191,7 @@ msgstr "Реактивный ранец при прыжке:"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:101
 msgid "JPJUMP^Disabled"
-msgstr "JPJUMP^Ð\92Ñ\8bключены"
+msgstr "JPJUMP^Ð\9eÑ\82ключены"
 
 #: qcsrc/menu/xonotic/dialog_settings_input.qc:102
 msgid "Air only"
@@ -8231,7 +8226,7 @@ msgstr "Определённая пользователем привязка к
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:11
 #, c-format
 msgid "%d fps"
-msgstr "%d фпс"
+msgstr "%d fps"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:12
 #, c-format
@@ -8253,7 +8248,7 @@ msgstr "Порт UDP клиента:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:31
 msgid "Force client to use chosen port unless it is set to 0"
-msgstr "Ð\9fÑ\80инÑ\83диÑ\82елÑ\8cное Ð¸Ñ\81полÑ\8cзованние ÐºÐ»Ð¸ÐµÐ½Ñ\82ом Ð²Ñ\8bбÑ\80анного Ð¿Ð¾Ñ\80Ñ\82а, Ð¸Ð½Ð°Ñ\87е 0"
+msgstr "Принудительное использование клиентом выбранного порта, иначе 0"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:34
 msgid "Bandwidth:"
@@ -8329,7 +8324,7 @@ msgstr "Компенсация ошибки движения"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:82
 msgid "Use encryption (AES) when available"
-msgstr "Использовать шифрование (AES) если возможно"
+msgstr "Использовать шифрование (AES), если возможно"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:85
 msgid "Framerate"
@@ -8365,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:"
@@ -8401,7 +8396,7 @@ msgstr "Показывать текущие дату и время"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:144
 msgid "Show current date and time of day, useful on screenshots"
-msgstr "Ð\9fоказÑ\8bваÑ\82Ñ\8c Ñ\82екÑ\83Ñ\89ие Ð´Ð°Ñ\82Ñ\83 Ð¸ Ð²Ñ\80емÑ\8f, Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ Ð´Ð»Ñ\8f Ñ\81нимков Ñ\8dкÑ\80ана"
+msgstr "Ð\9fоказÑ\8bваÑ\82Ñ\8c Ñ\82екÑ\83Ñ\89ие Ð´Ð°Ñ\82Ñ\83 Ð¸ Ð²Ñ\80емÑ\8f, Ð¿Ð¾Ð»ÐµÐ·Ð½Ð¾ Ð´Ð»Ñ\8f Ñ\81кÑ\80инÑ\88оÑ\82ов"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc.qc:147
 msgid "Enable developer mode"
@@ -8423,7 +8418,7 @@ msgstr "Полный сброс"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:31
 msgid "Cvar filter:"
-msgstr "Фильтр cvar:"
+msgstr "Фильтр переменных:"
 
 #: qcsrc/menu/xonotic/dialog_settings_misc_cvars.qc:38
 msgid "Modified cvars only"
@@ -8467,7 +8462,7 @@ msgstr "Язык текста"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:69
 msgid "Set language"
-msgstr "Ð\92Ñ\8bбÑ\80ать язык"
+msgstr "Ð\9fÑ\80именить язык"
 
 #: qcsrc/menu/xonotic/dialog_settings_user.qc:74
 msgid "Disable gore effects and harsh language"
@@ -8478,12 +8473,11 @@ 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 "Ð\9fока Ð²Ñ\8b Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87енÑ\8b, Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ Ñ\8fзÑ\8bка Ð¿Ñ\80имениÑ\82Ñ\81Ñ\8f только для меню,"
+msgstr "Ð\9fока Ð²Ñ\8b Ð¿Ð¾Ð´ÐºÐ»Ñ\8eÑ\87енÑ\8b, Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ðµ Ñ\8fзÑ\8bка Ð²Ñ\81Ñ\82Ñ\83пиÑ\82 Ð² Ñ\81илÑ\83 только для меню,"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:12
 msgid "full language changes will take effect starting from the next game"
@@ -8491,7 +8485,7 @@ msgstr "полное применение языка вступит в силу
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:16
 msgid "Disconnect now"
-msgstr "СейÑ\87аÑ\81 Ð¾Ñ\82клÑ\8eÑ\87ен"
+msgstr "Ð\9eÑ\82Ñ\81оединиÑ\82Ñ\8cÑ\81Ñ\8f Ñ\81ейÑ\87аÑ\81"
 
 #: qcsrc/menu/xonotic/dialog_settings_user_languagewarning.qc:17
 msgid "Switch language"
@@ -8551,7 +8545,7 @@ msgstr "Глубина цвета:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:53
 msgid "How many bits per pixel (BPP) to render at, 32 is recommended"
-msgstr "Сколько бит на точку использовать для вывода, советуется 32"
+msgstr "Сколько бит на пиксель использовать для вывода, рекомендуется 32"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:54
 msgid "16bit"
@@ -8574,9 +8568,9 @@ 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"
@@ -8584,7 +8578,7 @@ msgstr "Перевернуть изображение по горизонтал
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:68
 msgid "Poor man's left handed mode (default: off)"
-msgstr "Режим Ð»ÐµÐ²Ð¾Ñ\80Ñ\83кого Ð±ÐµÐ´Ð½Ñ\8fги (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл)"
+msgstr "Режим Ð»ÐµÐ²Ð¾Ñ\80Ñ\83кого Ð±ÐµÐ´Ð½Ñ\8fги (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:71
 msgid "Anisotropy:"
@@ -8626,7 +8620,7 @@ msgid ""
 "might decrease performance by quite a lot (default: disabled)"
 msgstr ""
 "Включить сглаживание, которое сглаживает края 3D-геометрии. Примечание: это "
-"можеÑ\82 Ñ\81илÑ\8cно Ñ\81низиÑ\82Ñ\8c Ð¿Ñ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"можеÑ\82 Ñ\81илÑ\8cно Ñ\81низиÑ\82Ñ\8c Ð¿Ñ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:85
 msgid "AA^Disabled"
@@ -8638,7 +8632,7 @@ msgstr "Высококачественный буфер кадров"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:97
 msgid "Depth first:"
-msgstr "СпеÑ\80ва глубина:"
+msgstr "СнаÑ\87ала глубина:"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:99
 msgid ""
@@ -8646,7 +8640,7 @@ msgid ""
 "normal rendering starts (default: disabled)"
 msgstr ""
 "Устранить перерасход отрисовкой только глубокой версии сцен до нормального "
-"наÑ\87ала Ð¾Ñ\82Ñ\80иÑ\81овки (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"наÑ\87ала Ð¾Ñ\82Ñ\80иÑ\81овки (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:100
 msgid "DF^Disabled"
@@ -8662,7 +8656,7 @@ msgstr "Всё"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:105
 msgid "Vertex Buffer Objects (VBOs)"
-msgstr "Использовать Vertex Buffer Objects (VBO)"
+msgstr "Использовать вершинные буферы (VBO)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:108
 msgid "VBO^Off"
@@ -8670,7 +8664,7 @@ msgstr "Отключено"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:109
 msgid "Vertices, some Tris (compatible)"
-msgstr "Вершины и отдельные треугольники (безопасно)"
+msgstr "Вершины, отдельные треугольники (безопасно)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:110
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:114
@@ -8768,9 +8762,9 @@ 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 ""
-"Заставляет процессор ждать пока видеокарта закончит отрисовку каждого кадра, "
-"может помочь в случае задержек и лагов на некоторых компьютерах (по "
-"Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Заставляет процессор ждать, пока видеокарта закончит отрисовку каждого "
+"кадÑ\80а, Ð¼Ð¾Ð¶ÐµÑ\82 Ð¿Ð¾Ð¼Ð¾Ñ\87Ñ\8c Ð² Ñ\81лÑ\83Ñ\87ае Ð·Ð°Ð´ÐµÑ\80жек Ð¸ Ð»Ð°Ð³Ð¾Ð² Ð½Ð° Ð½ÐµÐºÐ¾Ñ\82оÑ\80Ñ\8bÑ\85 ÐºÐ¾Ð¼Ð¿Ñ\8cÑ\8eÑ\82еÑ\80аÑ\85 (по "
+"Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:158
 msgid "Use OpenGL 2.0 shaders (GLSL)"
@@ -8785,8 +8779,8 @@ msgid ""
 "Enable use of GLSL to apply gamma correction, note that it might decrease "
 "performance by a lot (default: disabled)"
 msgstr ""
-"Активировать GLSL, чтобы применить гамма-коррекцию. Примечание: это сильно "
-"Ñ\81низиÑ\82 Ð¿Ñ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð²Ñ\8bкл.)"
+"Активировать GLSL, чтобы применять гамма-коррекцию. Примечание: это сильно "
+"Ñ\81низиÑ\82 Ð¿Ñ\80оизводиÑ\82елÑ\8cноÑ\81Ñ\82Ñ\8c (по Ñ\83молÑ\87аниÑ\8e: Ð¾Ñ\82кл.)"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:168
 msgid "Psycho coloring (easter egg)"
@@ -8810,7 +8804,7 @@ msgstr "Уровень сложности:"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer.qc:131
 msgid "CSKL^Easy"
-msgstr "Легкий"
+msgstr "Лёгкий"
 
 #: qcsrc/menu/xonotic/dialog_singleplayer.qc:132
 msgid "CSKL^Medium"
@@ -8838,11 +8832,11 @@ 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)"
-msgstr "Ð\90вÑ\82овÑ\8bбоÑ\80 ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ\8b (Ñ\81овеÑ\82уется)"
+msgstr "Ð\90вÑ\82овÑ\8bбоÑ\80 ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ\8b (Ñ\80екомендуется)"
 
 #: qcsrc/menu/xonotic/dialog_teamselect.qc:37
 msgid "red"
@@ -8962,7 +8956,7 @@ msgstr "показать очки"
 
 #: qcsrc/menu/xonotic/keybinder.qc:80
 msgid "screen shot"
-msgstr "Ñ\81нимок Ñ\8dкÑ\80ана"
+msgstr "Ñ\81кÑ\80инÑ\88оÑ\82"
 
 #: qcsrc/menu/xonotic/keybinder.qc:81
 msgid "maximize radar"
@@ -8970,7 +8964,7 @@ msgstr "увеличить радар"
 
 #: qcsrc/menu/xonotic/keybinder.qc:82
 msgid "3rd person view"
-msgstr "Ð\92ид от 3-го лица"
+msgstr "вид от 3-го лица"
 
 #: qcsrc/menu/xonotic/keybinder.qc:83
 msgid "enter spectator mode"
@@ -9018,7 +9012,7 @@ msgstr "выйти"
 
 #: qcsrc/menu/xonotic/keybinder.qc:101
 msgid "auto-join team"
-msgstr "авто-выбор команды"
+msgstr "автовыбор команды"
 
 #: qcsrc/menu/xonotic/keybinder.qc:103
 msgid "drop key / drop flag"
@@ -9048,7 +9042,7 @@ msgstr "Не нажимайте эту кнопку снова!"
 msgid ""
 "Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"
 msgstr ""
-"Что? Не могу зайти (m = NULL). Перефильтрую, чтобы такого больше не "
+"Что? Не могу зайти (m = NULL). Перефильтровка, чтобы такого больше не "
 "случалось.\n"
 
 #: qcsrc/menu/xonotic/maplist.qc:299
@@ -9061,8 +9055,8 @@ msgid ""
 "Huh? Can't play this (invalid game type). Refiltering so this won't happen "
 "again.\n"
 msgstr ""
-"Что? Не могу зайти (неверный тип игры). Перефильтрую, чтобы такого больше не "
-"случалось.\n"
+"Что? Не могу зайти (неверный тип игры). Перефильтровка, чтобы такого больше "
+"не случалось.\n"
 
 #: qcsrc/menu/xonotic/playerlist.qc:100 qcsrc/menu/xonotic/playerlist.qc:110
 msgid "spectator"
@@ -9320,7 +9314,7 @@ msgstr "Любимая_карта:"
 #: qcsrc/menu/xonotic/statslist.qc:201 qcsrc/menu/xonotic/statslist.qc:245
 #, c-format
 msgid "%s_Matches:"
-msgstr "%s_матчей:"
+msgstr "Матчи_%s:"
 
 #: qcsrc/menu/xonotic/statslist.qc:208
 #, c-format
@@ -9345,7 +9339,7 @@ msgstr "%s_любимая_карта:"
 #: qcsrc/menu/xonotic/statslist.qc:246
 #, c-format
 msgid "%d (unranked)"
-msgstr "%d (неÑ\80ейÑ\82инговÑ\8bе)"
+msgstr "%d (без Ñ\80ейÑ\82инга)"
 
 #: qcsrc/menu/xonotic/util.qc:417
 #, c-format
@@ -9389,3 +9383,9 @@ msgstr "Цвет команды:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Включить панель"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Чат"
+
+#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+#~ msgstr "^BG%s%s^K1 оказался слишком близко к ракете ^BG%s^K1%s%s"
index 8fb025ec12555faca203f269b3185c42cc3f15a6..b0f2b4f61aae2b322025d0339b88d522b97feefe 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Albanian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/sq/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index 38a5a241f1e896773b6b82947ae7f8df65902693..b9ec73a79cec6e175fc74ad5491abc660d11a09c 100644 (file)
@@ -13,7 +13,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 23:01+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Serbian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/sr/)\n"
@@ -235,7 +235,7 @@ msgstr "Настави..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "Ћаскање"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2868,7 +2868,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9262,3 +9262,6 @@ msgstr "Боја екипе:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "Омогући плочу"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Ћаскање"
index 814381f6cf323e7c4a25d1d01364227bef8182ad..0934f9fbc60015047c9780bbbaf2f91b354690f2 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Swedish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/sv/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index ba9d6e2d22fa08e68b990b7101269718b3920e21..a62ab5191216fd99cae34d5e077044e536d42787 100644 (file)
@@ -8,7 +8,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Turkish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/tr/)\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index b9dc5a5a7c6af5163ab527deb5715da5b2977005..f164a92f212400290df133137b41875ca61b47c6 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-19 19:55+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Ukrainian (http://www.transifex.com/team-xonotic/xonotic/"
 "language/uk/)\n"
@@ -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
@@ -2874,7 +2876,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index c402ca735a92ad4c5a7b95a504af6b5d1d0467f6..5653a3e4ce517610f6c45f19111b881825f65aee 100644 (file)
@@ -8,10 +8,10 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-07-05 15:06+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Uzbek (Latin) (http://www.transifex.com/team-xonotic/xonotic/"
-"language/uz@Latn/)\n"
+"language/uz%40Latn/)\n"
 "Language: uz@Latn\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -2845,7 +2845,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
index f0bc7b65df27ea098d95df457233f1697b3a51a2..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-07-09 23:06+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"
@@ -234,7 +236,7 @@ msgstr "继续..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "对话"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -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
@@ -2850,7 +2856,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -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"
@@ -4950,7 +4956,7 @@ msgstr "好的"
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:7
 msgid "Credits"
-msgstr "制作人员"
+msgstr ""
 
 #: qcsrc/menu/xonotic/dialog_credits.qh:8
 msgid "The Xonotic credits"
@@ -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:"
@@ -9160,3 +9171,6 @@ msgstr "队伍颜色:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "启用面板"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^对话"
index 42e1801c52bb7593d0af017116a5456906b99813..fca87630b0c661ed9483fd65e99a40ba8160cf7b 100644 (file)
@@ -12,7 +12,7 @@ msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-07-09 23:06+0000\n"
+"PO-Revision-Date: 2017-09-20 00:00+0000\n"
 "Last-Translator: divVerent <divVerent@xonotic.org>\n"
 "Language-Team: Chinese (Taiwan) (http://www.transifex.com/team-xonotic/"
 "xonotic/language/zh_TW/)\n"
@@ -233,7 +233,7 @@ msgstr "繼續..."
 #: qcsrc/client/hud/panel/quickmenu.qc:794
 #: qcsrc/client/hud/panel/quickmenu.qc:798
 msgid "Chat"
-msgstr "對話"
+msgstr ""
 
 #: qcsrc/client/hud/panel/quickmenu.qc:795
 msgid "QMCMD^:-) / nice one"
@@ -2857,7 +2857,7 @@ msgstr ""
 
 #: qcsrc/common/notifications/all.inc:463
 #, c-format
-msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
+msgid "^BG%s%s^K1 got too close to ^BG%s^K1's rocket%s%s"
 msgstr ""
 
 #: qcsrc/common/notifications/all.inc:464
@@ -9169,3 +9169,6 @@ msgstr "團隊顏色:"
 #: qcsrc/menu/xonotic/util.qh:44
 msgid "Enable panel"
 msgstr "開啟板面"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^對話"
index fb341c5b8537f37c492a2de2c7148ebd39b9b579..8e7bc9b4f74f414ac766859647221abbdf4ddd5b 100644 (file)
@@ -45,6 +45,9 @@ seta crosshair_color_special_rainbow_brightness 20 "color brightness of the rand
 // per-weapon crosshairs
 seta crosshair_per_weapon 1    "when 1, each gun will display a different crosshair"
 
+// side-scrolling crosshair
+seta crosshair_2d 54 "selects crosshair to use in side-scrolling mode (\"\" uses regular crosshair and 0 is none)"
+
 
 // =========================
 //  Crosshair ring settings
index 86b48082742510298643d3039145c27b34156815..931434697a8604ed527c55a25cb22e2e1f9958fd 100644 (file)
@@ -1 +1 @@
-exec defaultXonotic.cfg
+exec xonotic-common.cfg
diff --git a/defaultClient.cfg b/defaultClient.cfg
deleted file mode 100644 (file)
index e4904ff..0000000
+++ /dev/null
@@ -1,846 +0,0 @@
-// this resets most client cvars and aliases to their defaults
-// if you want to reset your client to defaults, it's probably a better idea to delete (parts of) config.cfg and restart
-
-
-// changes a cvar and reports it to the server (for the menu to notify the
-// server about changes)
-alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
-
-seta cl_firststart "" "how many times the client has been run"
-seta cl_startcount 0 "how many times the client has been run"
-
-// other aliases
-alias +hook +button6
-alias -hook -button6
-alias +jetpack +button10
-alias -jetpack -button10
-alias +dodge +button11
-alias -dodge -button11
-alias use "impulse 21"
-
-// for backwards compatibility
-// TODO Remove after 0.8 release!
-cl_particles_forcetraileffects 1
-
-alias dropweapon "impulse 17"
-alias +show_info +button7
-alias -show_info -button7
-
-// merge lightmaps up to 2048x2048 textures
-mod_q3bsp_lightmapmergepower 4
-
-// player defaults
-_cl_color "112.211" // same effect as 112, but menuqc can detect this as the default and not intentionally set
-_cl_name ""
-seta _cl_gender 0 "storage cvar for current player gender (0 = undisclosed, 1 = male, 2 = female)"
-_cl_playerskin 0
-
-seta cl_reticle 1 "enable zoom reticles"
-seta cl_reticle_stretch 0 "stretch reticles so they fit the screen (breaks image proportions)"
-seta cl_reticle_normal 1 "draw an aiming reticle when zooming with the zoom button"
-seta cl_reticle_normal_alpha 1 "alpha of the normal reticle"
-seta cl_reticle_weapon 1 "draw custom aiming reticle when zooming with certain weapons"
-seta cl_reticle_weapon_alpha 1 "alpha of the custom reticle"
-
-fov 100
-seta cl_velocityzoom_enabled 0 "velocity based zooming of fov"
-seta cl_velocityzoom_factor 0 "factor of fov zooming (negative values zoom out)"
-seta cl_velocityzoom_type 3 "how to factor in speed, 1 = all velocity in all directions, 2 = velocity only in forward direction (can be negative), 3 = velocity only in forward direction (limited to forward only)"
-seta cl_velocityzoom_speed 1000 "target speed for fov factoring"
-seta cl_velocityzoom_time 0.2  "time value for averaging speed values"
-seta cl_spawnzoom 1 "zoom effect immediately when a player spawns"
-seta cl_spawnzoom_speed 1 "speed at which zooming occurs while spawning"
-seta cl_spawnzoom_factor 2 "factor of zoom while spawning"
-seta cl_zoomfactor 5   "how much +zoom will zoom (1-30)"
-seta cl_zoomspeed 8    "how fast it will zoom (0.5-16), negative values mean instant zoom"
-seta cl_zoomsensitivity 0      "how zoom changes sensitivity (0 = weakest, 1 = strongest)"
-
-seta cl_unpress_zoom_on_spawn 1 "automatically unpress zoom when you spawn"
-seta cl_unpress_zoom_on_death 1 "automatically unpress zoom when you die (and don't allow zoom again while dead)"
-seta cl_unpress_zoom_on_weapon_switch 1 "automatically unpress zoom when you switch a weapon"
-seta cl_unpress_attack_on_weapon_switch 0 "automatically unpress fire and fire1 attack buttons when you switch a weapon"
-
-seta cl_spawn_event_particles 1 "pointparticles effect whenever a player spawns"
-seta cl_spawn_event_sound 1 "sound effect whenever a player spawns"
-//seta cl_spawn_point_model 0 "place a model at all spawn points" // still needs a model
-seta cl_spawn_point_particles 1 "pointparticles effect at all spawn points" // managed by effects-.cfg files
-seta cl_spawn_point_dist_min 1200
-seta cl_spawn_point_dist_max 1600
-
-freelook 1
-sensitivity 6
-v_gamma 1
-viewsize 100
-bgmvolume 1
-volume 0.5
-// fullscreen 1024x768x32bit
-vid_bitsperpixel 32
-vid_fullscreen 1
-vid_width 1024
-vid_height 768
-vid_pixelheight 1
-vid_resizable 0 // cannot be turned on before it is sure it cannot cause a r_restart
-vid_desktopfullscreen 1
-prvm_language en
-set _menu_prvm_language ""
-set _menu_vid_width "$vid_width"
-set _menu_vid_height "$vid_height"
-set _menu_vid_pixelheight "$vid_pixelheight"
-set _menu_vid_desktopfullscreen "$vid_desktopfullscreen"
-seta menu_vid_scale 0
-seta menu_vid_allowdualscreenresolution 0
-// 2D resolution 800x600
-vid_conwidth 800
-vid_conheight 600
-// menu_conwidth, menu_conheight are set inside quake.rc
-v_deathtilt 0 // needed for spectators (who are dead to avoid prediction)
-
-// create a temporary empty alias for menu_sync so that execution of effects-normal.cfg, hud_luma.cfg
-// and sRGB-{disable,enable}.cfg on game start doesn't show an error message in the console
-alias menu_sync "" // will be re-aliased later
-
-// we want to use sRGB for our maps!
-exec sRGB-disable.cfg
-vid_sRGB_fallback 2
-r_hdr_glowintensity 1
-// #define Image_LinearFloatFromsRGBFloat(c) (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f))
-set rpn_sRGB_to_linear "dup 0.055 add 1.055 div 2.4 pow exch 12.92 div dup 0.0031308 gt when"
-// #define Image_sRGBFloatFromLinearFloat(c) (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f)
-set rpn_linear_to_sRGB "dup 1.0 2.4 div pow 1.055 mul 0.055 sub exch 12.92 mul dup 0.04045 ge when"
-
-// -nosRGB to -sRGB sky shader conversion:
-//
-// q3map_sunExt 1 0.6875 0.375 340 25 47 0 16
-//                                    ^^ elevation
-//                             ^^^ sunlight
-// q3map_skylight 110 3
-//                ^^^ skylight
-//
-// With that, do (the last parameter is the ratio of skylight you assume hits
-// the surfaces, about 0.25 for inner surfaces near sky, about 1.00 on
-// terrain):
-// ]skybox_nosRGB_to_sRGB 340 47 110 0.25
-// rpn: still on stack: new_sunlight:
-// rpn: still on stack: 380.464142
-// rpn: still on stack: new_skylight:
-// rpn: still on stack: 9.32523632
-//
-// The equivalent -sRGB shader then will have:
-//
-// q3map_sunExt 1 0.6875 0.375 380.464142 25 47 0 16
-// q3map_skylight 9.32523632 3
-alias skybox_nosRGB_to_sRGB "rpn $3 402.123 $4 div div $rpn_sRGB_to_linear 402.123 $4 div mul /new_skylight: $3 402.123 $4 div div $1 256 div $2 0.017453 mul sin mul add $rpn_sRGB_to_linear $3 402.123 $4 div div $rpn_sRGB_to_linear sub 256 mul $2 0.017453 mul sin div /new_sunlight:"
-
-set cl_orthoview 0 "enable top-down view of the map- meant to be used for radar map images (note: orthoview sets cvars temporarily, requires restart to return them to normal)"
-set cl_orthoview_nofog 1 "disable fog while in orthoview-- note, should not be enabled on ALL maps, i.e. oilrig works fine with this disabled"
-
-// these settings determine how much the view is affected by movement/damage
-cl_smoothviewheight 0.05 // time of the averaging to the viewheight value so that it creates a smooth transition for crouching and such. 0 for instant transition
-cl_deathfade 0 // fade screen to dark red when dead, value represents how fast the fade is (higher is faster)
-cl_bobcycle 0.5 // how long the cycle of up/down view movement takes (only works if cl_bob is not 0), default is 0.6
-cl_bob 0 // how much view moves up/down when moving (does not move if cl_bobcycle is 0, but still enables cl_bobmodel), default is 0.02
-cl_bob2cycle 1 // how long the cycle of left/right view movement takes (only works if cl_bob2 is not 0), default is 0.6
-cl_bob2 0 // how much view moves left/right when moving (does not move if cl_bob2cycle is 0), default is 0.01
-cl_bobfall 0.05 "how much the view swings down when falling (influenced by the speed you hit the ground with)"
-cl_bobfallcycle 3 "speed of the bobfall swing"
-cl_bobfallspeed 200 "necessary amount of speed for bob-falling to occur"
-cl_bobmodel 1 // whether to have gun model move around on screen when moving (only works if cl_bob is not 0), default is 1
-cl_bobmodel_side 0.2 // amount the gun sways to the sides
-cl_bobmodel_speed 10 // rate at which the gun sways
-cl_bobmodel_up 0.1 // amount the gun sways up and down
-
-cl_followmodel 1 // enables weapon pushing / pulling effect when walking
-seta cl_followmodel_speed 0.3 "gun following speed"
-seta cl_followmodel_limit 135 "gun following limit"
-seta cl_followmodel_velocity_absolute 0 "make the effect ignore velocity direction changes (side effect: it causes a glitch when teleporting / passing through a warpzone)"
-seta cl_followmodel_velocity_lowpass 0.05 "gun following velocity lowpass averaging time"
-seta cl_followmodel_highpass 0.05 "gun following highpass averaging time"
-seta cl_followmodel_lowpass 0.03 "gun following lowpass averaging time"
-
-cl_leanmodel 1 // enables weapon leaning effect when looking around
-seta cl_leanmodel_speed 0.3 "gun leaning speed"
-seta cl_leanmodel_limit 30 "gun leaning limit"
-seta cl_leanmodel_highpass1 0.2 "gun leaning pre-highpass averaging time"
-seta cl_leanmodel_highpass 0.2 "gun leaning highpass averaging time"
-seta cl_leanmodel_lowpass 0.05 "gun leaning lowpass averaging time"
-
-cl_rollangle 0 // amount of view tilt when strafing, default is 2.0
-v_kicktime 0 // how long damage kicks of the view last, default is 0 seconds
-gl_polyblend 0 // whether to use screen tints, this has now been replaced by a better system in CSQC
-r_motionblur 0 // motion blur value, default is 0
-r_damageblur 0 // motion blur when damaged, default is 0 (removed in Xonotic)
-
-r_bloom_blur 4
-r_bloom_brighten 2
-r_bloom_colorexponent 1
-r_bloom_colorscale 1
-r_bloom_colorsubtract 0.125
-r_bloom_resolution 320
-r_bloom_scenebrightness 0.85
-
-seta vid_x11_display ""        "xonotic-linux-*.sh will use this to start xonotic on an other/new X display"
-// This can have three possible settings:
-//     ""              run as usual
-//     ":n"            use DISPLAY=:n, create it if needed
-//     ":n/layout"     use DISPLAY=:n, create it if needed with ServerLayout layout
-
-cl_autodemo_nameformat demos/%Y-%m-%d_%H-%M
-
-// taunts and voices
-seta cl_autotaunt 0 "automatically taunt enemies when fragging them"
-seta cl_voice_directional 1    "0 = all voices are non-directional, 1 = all voices are directional, 2 = only taunts are directional"
-seta cl_voice_directional_taunt_attenuation 0.5 "this defines the distance from which taunts can be heard"
-
-seta cl_hitsound 1 "play a hit notifier sound when you have hit an enemy, 1: same pitch 2: increase pitch with more damage 3: decrease pitch with more damage"
-set cl_hitsound_antispam_time 0.05 "don't play the hitsound more often than this"
-seta cl_hitsound_min_pitch 0.75 "minimum pitch of hit sound"
-seta cl_hitsound_max_pitch 1.5 "maximum pitch of hit sound"
-seta cl_hitsound_nom_damage 25 "damage amount at which hitsound bases pitch off"
-
-seta cl_eventchase_death 1 "camera goes into 3rd person mode when the player is dead; set to 2 to active the effect only when the corpse doesn't move anymore"
-seta cl_eventchase_frozen 0 "camera goes into 3rd person mode when the player is frozen"
-seta cl_eventchase_nexball 1 "camera goes into 3rd person mode when in nexball game-mode"
-seta cl_eventchase_distance 140 "final camera distance"
-seta cl_eventchase_generator_distance 400 "final camera distance while viewing generator explosion"
-seta cl_eventchase_speed 1.3 "how fast the camera slides back, 0 is instant"
-seta cl_eventchase_maxs "12 12 8" "max size of eventchase camera bbox"
-seta cl_eventchase_mins "-12 -12 -8" "min size of eventchase camera bbox"
-seta cl_eventchase_viewoffset "0 0 20" "viewoffset of eventchase camera"
-seta cl_eventchase_generator_viewoffset "0 0 80" "viewoffset of eventchase camera while viewing generator explosion"
-seta cl_eventchase_vehicle 1 "camera goes into 3rd person mode when inside a vehicle"
-seta cl_eventchase_vehicle_viewoffset "0 0 80"
-seta cl_eventchase_vehicle_distance 250
-
-set _vehicles_shownchasemessage 0
-
-seta cl_particles_oldvortexbeam 0 "Uses the old v2.3 Vortex beam instead of the new beam, only works if server allows it (g_allow_oldvortexbeam 1)"
-
-seta cl_damageeffect 1 "enable weapon damage effects: 1 enables the feature on skeletal models, 2 on any model"
-seta cl_damageeffect_ticrate 0.1 "particle spawn rate"
-seta cl_damageeffect_bones 5 "how many damages to allow on a rigged mesh at once (non-skeletal objects are limited to one)"
-seta cl_damageeffect_distribute 1 "divide particle intensity if multiple damages are present"
-seta cl_damageeffect_lifetime 0.1 "how much a damage effect lasts, based on damage amount"
-seta cl_damageeffect_lifetime_min 3 "minimum lifetime a damage effect may have"
-seta cl_damageeffect_lifetime_max 6 "maximum lifetime a damage effect may have"
-
-set cl_deathglow 0.8 "number of seconds during which dead bodies glow out"
-
-cl_movement 1
-cl_movement_track_canjump 0
-cl_stairsmoothspeed 200
-
-alias g_waypointeditor_spawn "impulse 103"
-alias g_waypointeditor_remove "impulse 104"
-alias g_waypointeditor_relinkall "impulse 105"
-alias g_waypointeditor_saveall "impulse 106"
-alias g_waypointeditor_unreachable "impulse 107"
-
-seta menu_sandbox_spawn_model ""
-seta menu_sandbox_attach_bone ""
-seta menu_sandbox_edit_skin 0
-seta menu_sandbox_edit_alpha 1
-seta menu_sandbox_edit_color_main "1 1 1"
-seta menu_sandbox_edit_color_glow "1 1 1"
-seta menu_sandbox_edit_frame 0
-seta menu_sandbox_edit_scale 1
-seta menu_sandbox_edit_solidity 1
-seta menu_sandbox_edit_physics 1
-seta menu_sandbox_edit_force 1
-seta menu_sandbox_edit_material ""
-
-seta menu_monsters_edit_spawn ""
-seta menu_monsters_edit_skin 0
-seta menu_monsters_edit_movetarget 1
-
-// effects
-r_glsl_vertextextureblend_usebothalphas 1 // allows to abuse texture blending as detail texture
-mod_q3shader_force_terrain_alphaflag 1 // supposedly now required for r_glsl_vertextextureblend_usebothalphas to work
-r_glsl_postprocess 0 // but note, hud_postprocessing enables this
-r_picmipsprites 0 // Xonotic uses sprites that should never be picmipped (team mate, typing, waypoints)
-r_picmipworld 1
-gl_picmip_world 0
-gl_picmip_sprites 0
-gl_picmip_other 1 // so, picmip -1 is best possible quality
-r_mipsprites 1
-r_mipskins 1
-gl_max_lightmapsize 4096
-r_shadow_realtime_world_lightmaps 1
-r_shadow_realtime_world_importlightentitiesfrommap 0 // Whether build process uses keepLights is nontransparent and may change, so better make keepLights not matter.
-cl_decals_fadetime 5
-cl_decals_time 1
-seta cl_gunalign 3 "Gun alignment; 1 = center, 3 = right, 4 = left; requires reconnect"
-seta cl_nogibs 0 "reduce number of violence effects, or remove them totally"
-seta cl_particlegibs 0 "simpler gibs"
-seta cl_gibs_damageforcescale 3.5 "force to push around gibs"
-seta cl_gibs_lifetime 2.5 "average lifetime of gibs"
-seta cl_gibs_velocity_scale 1 "gib throw velocity force scale"
-seta cl_gibs_velocity_random 1 "gib throw velocity randomness scale"
-seta cl_gibs_velocity_up 1 "extra z velocity for gibs"
-seta cl_gibs_ticrate 0.1 "ticrate for gibs"
-seta cl_gibs_sloppy 1 "sloppy gibs, may temporarily penetrate walls"
-seta cl_gibs_avelocity_scale 1 "how much angular velocity to use on gibs"
-seta cl_casings 1 "enable or disable bullet casings"
-seta cl_casings_shell_time 30 "shell casing lifetime"
-seta cl_casings_bronze_time 10 "bullet casings lifetime"
-seta cl_casings_ticrate 0.1 "ticrate for casings"
-seta cl_casings_sloppy 1 "sloppy casings, may temporarily penetrate walls"
-seta cl_projectiles_sloppy 1 "sloppy projectiles, may temporarily penetrate walls"
-cl_stainmaps 0
-cl_particles_smoke 1
-vid_gl20 1
-r_glsl_deluxemapping 1
-r_glsl_offsetmapping 0
-r_glsl_offsetmapping_lod 1
-r_glsl_offsetmapping_reliefmapping 0
-r_glsl_offsetmapping_scale 0.02
-
-scr_conalpha 1
-scr_conbrightness 0.2
-scr_screenshot_jpeg 1
-scr_screenshot_jpeg_quality 0.9
-
-cl_sound_wizardhit ""
-cl_sound_hknighthit ""
-cl_sound_tink1 weapons/tink1.wav
-cl_sound_ric1 weapons/ric1.wav
-cl_sound_ric2 weapons/ric2.wav
-cl_sound_ric3 weapons/ric3.wav
-cl_sound_r_exp3 ""
-
-seta cl_announcer default "name of the announcer you wish to use from data/sound/announcer"
-seta cl_announcer_antispam 2 "number of seconds before an announcement of the same sound can be played again"
-seta cl_announcer_maptime 3 "play announcer sound telling you the remaining maptime - 0: do not play at all, 1: play at one minute, 2: play at five minutes, 3: play both"
-
-// aliases:
-alias +fire +attack
-alias -fire -attack
-alias +fire2 +button3
-alias -fire2 -button3
-alias +attack2 +button3 // old alias from Nexuiz
-alias -attack2 -button3 // old alias name from Nexuiz
-alias +crouch +button5
-alias -crouch -button5
-alias weapnext "_weapnext_${cl_weaponpriority_useforcycling}"
-alias _weapnext_0 "impulse 18"
-alias _weapnext_1 "impulse 15"
-alias _weapnext_2 "impulse 10"
-alias weaplast "impulse 11"
-alias weapprev "_weapprev_${cl_weaponpriority_useforcycling}"
-alias _weapprev_0 "impulse 19"
-alias _weapprev_1 "impulse 16"
-alias _weapprev_2 "impulse 12"
-alias weapbest "impulse 13"
-
-// experimental zoom toggle (can be in wrong state at start of a game, though)
-set _togglezoom +
-alias +zoom "set _togglezoom -; +button4"
-alias -zoom "set _togglezoom +; -button4"
-alias togglezoom "${_togglezoom}zoom"
-
-alias reload "impulse 20"
-
-// weapons
-alias weapon_group_1 "impulse 1"
-alias weapon_group_2 "impulse 2"
-alias weapon_group_3 "impulse 3"
-alias weapon_group_4 "impulse 4"
-alias weapon_group_5 "impulse 5"
-alias weapon_group_6 "impulse 6"
-alias weapon_group_7 "impulse 7"
-alias weapon_group_8 "impulse 8"
-alias weapon_group_9 "impulse 9"
-alias weapon_group_0 "impulse 14" // cycles the superweapons
-// TODO: remove after 0.8.2. Default impulse commands for 0.8.1 servers
-exec weapons.cfg
-
-cl_curl_enabled 1
-cl_curl_maxdownloads 3
-cl_curl_maxspeed 0
-cl_curl_useragent 1
-cl_curl_useragent_append "$g_xonoticversion"
-
-seta g_waypointsprite_alpha 1 "This allows the client to control transparency of the waypoint"
-seta g_waypointsprite_crosshairfadealpha 0.25 "alpha multiplier near crosshair"
-seta g_waypointsprite_crosshairfadescale 1 "scale multiplier near the crosshair"
-seta g_waypointsprite_crosshairfadedistance 150 "distance in virtual pixels from crosshair where to start fading"
-seta g_waypointsprite_distancefadealpha 1 "alpha multiplier near distance"
-seta g_waypointsprite_distancefadescale 0.7 "scale multiplier near the distance"
-seta g_waypointsprite_distancefadedistancemultiplier 0.5 "distance in map sizes from distance where to stop fading"
-set g_waypointsprite_distancealphaexponent 2
-seta g_waypointsprite_edgefadealpha 0.5 "alpha multiplier near the edge"
-seta g_waypointsprite_edgefadedistance 50 "distance in virtual pixels from edge where to start fading"
-seta g_waypointsprite_edgefadescale 1 "scale multiplier near the edge"
-seta g_waypointsprite_edgeoffset_bottom 0 "offset of how close the waypoint can be to the bottom edge of the screen"
-seta g_waypointsprite_edgeoffset_left 0 "offset of how close the waypoint can be to the left edge of the screen"
-seta g_waypointsprite_edgeoffset_right 0 "offset of how close the waypoint can be to the right edge of the screen"
-seta g_waypointsprite_edgeoffset_top 0 "offset of how close the waypoint can be to the top edge of the screen"
-seta g_waypointsprite_fontsize 12
-seta g_waypointsprite_itemstime 2 "show waypoints to indicate that some important items (mega health, large armor) are about to respawn: 1 when spectating, 2 even playing in warmup stage"
-set g_waypointsprite_minscale 0.5
-set g_waypointsprite_minalpha 0.4
-set g_waypointsprite_normdistance 512
-seta g_waypointsprite_scale 1
-set g_waypointsprite_spam 0 "Debugging feature. Set to 10 and load courtfun in race mode to test."
-set g_waypointsprite_timealphaexponent 1
-seta g_waypointsprite_turrets 1 "disable turret waypoints"
-seta g_waypointsprite_turrets_maxdist 5000 "max distance for turret waypoints"
-seta g_waypointsprite_uppercase 1
-
-alias "g_waypointsprite_personal"      "impulse 30"
-alias "g_waypointsprite_personal_p"    "impulse 31"
-alias "g_waypointsprite_personal_d"    "impulse 32"
-alias "g_waypointsprite_team_helpme"   "impulse 33"
-alias "g_waypointsprite_team_here"     "impulse 34"
-alias "g_waypointsprite_team_here_p"   "impulse 35"
-alias "g_waypointsprite_team_here_d"   "impulse 36"
-alias "g_waypointsprite_team_danger"   "impulse 37"
-alias "g_waypointsprite_team_danger_p" "impulse 38"
-alias "g_waypointsprite_team_danger_d" "impulse 39"
-alias "g_waypointsprite_clear_personal"        "impulse 47"
-alias "g_waypointsprite_clear" "impulse 48"
-alias "g_waypointsprite_toggle"        "toggle cl_hidewaypoints"
-
-seta cl_hidewaypoints 0 "disable static waypoints, only show team waypoints"
-
-seta cl_damagetext "1" "Draw damage dealt where you hit the enemy"
-seta cl_damagetext_format "-{total}" "How to format the damage text. {health}, {armor}, {total}, {potential}: full damage not capped to target's health, {potential_health}: health damage not capped to target's health"
-seta cl_damagetext_format_verbose 0 "{health} shows {potential_health} too when they differ; {total} shows {potential} too when they differ"
-seta cl_damagetext_format_hide_redundant 0 "hide {armor} if 0; hide {potential} and {potential_health} when same as actual"
-seta cl_damagetext_color "1 1 0" "Damage text color"
-seta cl_damagetext_color_per_weapon "0" "Damage text uses weapon color"
-seta cl_damagetext_size_min 10 "Damage text font size for small damage"
-seta cl_damagetext_size_min_damage 25 "How much damage is considered small"
-seta cl_damagetext_size_max 16 "Damage text font size for large damage"
-seta cl_damagetext_size_max_damage 140 "How much damage is considered large"
-seta cl_damagetext_alpha_start "1" "Damage text initial alpha"
-seta cl_damagetext_alpha_lifetime "3" "Damage text lifetime in seconds"
-seta cl_damagetext_velocity "0 0 20" "Damage text move direction"
-seta cl_damagetext_offset "0 -40 0" "Damage text offset"
-seta cl_damagetext_accumulate_range "30" "Damage text spawned within this range is accumulated"
-seta cl_damagetext_accumulate_alpha_rel "0.65" "Only update existing damage text when it's above this much percentage (0 to 1) of the starting alpha"
-seta cl_damagetext_friendlyfire "1" "Show damage text for friendlyfire too"
-seta cl_damagetext_friendlyfire_color "1 0 0" "Damage text color for friendlyfire"
-
-seta cl_damagetext_2d_pos "0.47 0.53 0" "2D damage text initial position (X and Y between 0 and 1)"
-seta cl_damagetext_2d_alpha_start 1 "2D damage text initial alpha"
-seta cl_damagetext_2d_alpha_lifetime 1.3 "2D damage text lifetime (alpha fading) in seconds"
-seta cl_damagetext_2d_size_lifetime 3 "2D damage text lifetime (size shrinking) in seconds"
-seta cl_damagetext_2d_velocity "-25 0 0" "2D damage text move direction (screen coordinates)"
-seta cl_damagetext_2d_overlap_offset "0 -15 0" "Offset 2D damage text by this much to prevent overlapping (screen coordinates)"
-seta cl_damagetext_2d_close_range 125 "Always use 2D damagetext for hits closer that this"
-seta cl_damagetext_2d_out_of_view 1 "Always use 2D damagetext for hits that occured off-screen"
-
-seta cl_vehicles_alarm 1 "Play an alarm sound when the vehicle you are driving is heavily damaged"
-seta cl_vehicles_hud_tactical 1
-seta cl_vehicles_hudscale 0.5
-seta cl_vehicles_notify_time 15
-seta cl_vehicles_crosshair_size 0.5
-seta cl_vehicles_crosshair_colorize 1
-
-r_labelsprites_scale 0.40625 // labels sprites get displayed at 0.5x from 640x480 to 1280x1024, and at 1x from 1600x1200 onwards
-
-exec binds-xonotic.cfg
-
-seta menu_skin "luma"
-set menu_slowmo 1
-seta menu_sounds 0 "enables menu sound effects. 1 enables click sounds, 2 also enables hover sounds"
-seta menu_tooltips 1 "menu tooltips: 0 disabled, 1 enabled, 2 also shows cvar or console command (when available) changed or executed by the item"
-set menu_picmip_bypass 0 "bypass texture quality enforcement based on system resources, not recommended and may cause crashes!"
-set menu_showboxes 0 "show item bounding boxes (debug)"
-set menu_cvarlist_onlymodified 0 "show only modified cvars in the cvar list"
-set menu_force_on_disconnection 1 "force to show the menu this number of seconds after you get disconnected (0 to disable)"
-
-r_textbrightness 0.2
-r_textcontrast 0.8
-r_textshadow 0
-r_font_postprocess_blur 1
-r_font_postprocess_outline 1
-
-// good settings for these fonts
-con_chat 5
-con_chatpos -9
-con_chatsize 10
-con_chatwidth 0.6
-con_notify 0
-con_notifysize 10
-con_notifyalign 0
-con_textsize 10
-
-seta sbar_info_pos 0 "Y-axis distance from lower right corner for engine info prints"
-
-// scoreboard
-seta scoreboard_columns default
-
-// keep old scoreboard cvars for compatibility's sake
-// they've been replaced by hud_panel_scoreboard_* cvars
-// TODO remove them after a future release (0.8.2+)
-seta scoreboard_border_thickness 1 "scoreboard border thickness"
-seta scoreboard_accuracy_border_thickness 1 "accuracy stats border thickness"
-seta scoreboard_accuracy_doublerows 0 "use two rows instead of one"
-seta scoreboard_accuracy_nocolors 0 "don't use colors displaying accuracy stats"
-seta scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars"
-seta scoreboard_color_bg_r 0.125 "red color component of the scoreboard background"
-seta scoreboard_color_bg_g 0.55 "green color component of the scoreboard background"
-seta scoreboard_color_bg_b 0.875 "blue color component of the scoreboard background"
-seta scoreboard_color_bg_team 0.6 "team color multiplier of the scoreboard background"
-seta scoreboard_alpha_bg 0.7 "scoreboard background alpha"
-seta scoreboard_alpha_fg 1 "scoreboard foreground alpha"
-seta scoreboard_alpha_name 0.9 "alpha of player text in scoreboard list other than self"
-seta scoreboard_alpha_name_self 1 "alpha of player text in scoreboard list of self"
-seta scoreboard_fadeinspeed 10 "speed at which scoreboard fades in, higher is faster (0 = instant)"
-seta scoreboard_fadeoutspeed 5 "speed at which scoreboard fades out, higher is faster (0 = instant)"
-seta scoreboard_highlight 1 "enable highlighting for rows and columns in the scoreboard"
-seta scoreboard_highlight_alpha 0.08 "highlight alpha value (depends on hud_scoreboard_highlight 1)"
-seta scoreboard_highlight_alpha_self 0.3 "self highlight alpha value"
-seta scoreboard_offset_left 0.15 "how far (by percent) the scoreboard is offset from the left screen edge"
-seta scoreboard_offset_right 0.15 "how far (by percent) the scoreboard is offset from the right screen edge"
-seta scoreboard_offset_vertical 0.05 "how far (by percent) the scoreboard is offset from the top and bottom of the screen"
-seta scoreboard_bg_scale 0.25 "scale for the tiled scoreboard background"
-seta scoreboard_respawntime_decimals 1 "decimal places to show for the respawntime countdown display on the scoreboard"
-seta scoreboard_dynamichud 0 "apply the dynamic hud effects to the scoreboard"
-
-seta accuracy_color_levels "0 20 100" "accuracy values at which a specified color (accuracy_color<X>) will be used. If your accuracy is between 2 of these values then a mix of the Xth and X+1th colors will be used. You can specify up to 10 values, in increasing order"
-seta accuracy_color0 "1 0 0"
-seta accuracy_color1 "1 1 0"
-seta accuracy_color2 "0 1 0"
-
-// for menu server list (eventually make them have engine support?)
-seta menu_slist_showfull 1 "show servers even if they are full and have no slots to join"
-seta menu_slist_showempty 1 "show servers even if they are no empty and have no opponents to play against"
-seta menu_slist_modfilter "" // set to either: !modname or modname. modname of = means "same as we are running now".
-
-// other serverlist cvars
-seta menu_slist_categories 1
-seta menu_slist_categories_onlyifmultiple 1
-seta menu_slist_purethreshold 0
-seta menu_slist_modimpurity 0
-seta menu_slist_recommendations 3
-seta menu_slist_recommendations_maxping 150
-seta menu_slist_recommendations_minfreeslots 1
-seta menu_slist_recommendations_minhumans 0
-seta menu_slist_recommendations_purethreshold -1
-
-// serverlist category override cvars
-seta menu_slist_categories_CAT_FAVORITED_override ""
-seta menu_slist_categories_CAT_RECOMMENDED_override ""
-seta menu_slist_categories_CAT_NORMAL_override ""
-seta menu_slist_categories_CAT_SERVERS_override "CAT_NORMAL"
-seta menu_slist_categories_CAT_XPM_override ""
-seta menu_slist_categories_CAT_MODIFIED_override ""
-seta menu_slist_categories_CAT_OVERKILL_override ""
-seta menu_slist_categories_CAT_INSTAGIB_override ""
-seta menu_slist_categories_CAT_DEFRAG_override ""
-
-seta menu_weaponarena ""
-
-seta menu_maxplayers 16 "maxplayers value when the menu starts a game"
-
-// useful keybind to maximize the chat area temporarily
-// HUD code takes care of many of these now...
-//set _backup_con_chatvars_set 0
-//alias _restore_con_chatvars_0 ""
-//alias _restore_con_chatvars_1 "set _backup_con_chatvars_set 0; con_chatpos $_backup_con_chatpos; con_chat $_backup_con_chat; con_notify $_backup_con_notify; con_chattime $_backup_con_chattime; cl_deathscoreboard $_backup_cl_deathscoreboard; scr_centertime $_backup_scr_centertime;r_track_sprites $_backup_r_track_sprites"
-//alias _restore_con_chatvars "_restore_con_chatvars_$_backup_con_chatvars_set"
-//alias _backup_con_chatvars_0 "set _backup_con_chatvars_set 1; set _backup_con_chatpos $con_chatpos; set _backup_con_chat $con_chat; set _backup_con_notify $con_notify; set _backup_con_chattime $con_chattime; set _backup_cl_deathscoreboard $cl_deathscoreboard; set _backup_scr_centertime $scr_centertime;set _backup_r_track_sprites $r_track_sprites"
-//alias _backup_con_chatvars_1 ""
-//alias _backup_con_chatvars "_backup_con_chatvars_$_backup_con_chatvars_set"
-//alias +con_chat_maximize "_backup_con_chatvars; con_chatpos -9; con_chat 100; con_notify 0; con_chattime 3600; cl_deathscoreboard 0; scr_centertime 0; r_track_sprites 0"
-//alias -con_chat_maximize "_restore_con_chatvars"
-
-set _con_chat_maximized 0
-set _backup_con_chatvars_set 0
-alias _restore_con_chatvars_0 ""
-alias _restore_con_chatvars_1 "set _backup_con_chatvars_set 0; con_notify $_backup_con_notify; con_chattime $_backup_con_chattime; cl_deathscoreboard $_backup_cl_deathscoreboard; scr_centertime $_backup_scr_centertime;r_track_sprites $_backup_r_track_sprites"
-alias _restore_con_chatvars "_restore_con_chatvars_$_backup_con_chatvars_set"
-alias _backup_con_chatvars_0 "set _backup_con_chatvars_set 1; set _backup_con_notify $con_notify; set _backup_con_chattime $con_chattime; set _backup_cl_deathscoreboard $cl_deathscoreboard; set _backup_scr_centertime $scr_centertime;set _backup_r_track_sprites $r_track_sprites"
-alias _backup_con_chatvars_1 ""
-alias _backup_con_chatvars "_backup_con_chatvars_$_backup_con_chatvars_set"
-alias +con_chat_maximize "_con_chat_maximized 1; _backup_con_chatvars; con_notify 0; con_chattime 3600; cl_deathscoreboard 0; scr_centertime 0; r_track_sprites 0"
-alias -con_chat_maximize "_con_chat_maximized 0; _restore_con_chatvars"
-
-// tab completion
-set con_completion_playdemo    *.dem
-set con_completion_timedemo    *.dem
-set con_completion_ply         *.dem
-set con_completion_tdem                *.dem
-set con_completion_exec                *.cfg
-set con_completion_chmap       map
-set con_completion_devmap      map
-set con_completion_gotomap     map
-set con_completion_vmap                map
-set con_completion_vnextmap    map
-set con_completion_vdomap      map
-set con_completion_playermodel "models/player/*.iqm"
-
-// helper
-// these non-saved engine cvars shall be saved
-alias makesaved "seta $1 \"${$1 ?}\""
-makesaved cl_maxfps_alwayssleep
-makesaved cl_port
-makesaved gl_finish
-makesaved net_slist_queriespersecond
-makesaved r_ambient
-makesaved r_drawviewmodel
-makesaved r_showsurfaces
-makesaved r_subdivisions_tolerance
-makesaved skill
-makesaved vid_gl13
-makesaved vid_gl20
-makesaved v_idlescale
-makesaved v_kicktime
-makesaved music_playlist_list0
-makesaved music_playlist_random0
-
-cl_netfps 60 // should match or be a multiple of sys_ticrate
-
-seta gl_texturecompression 0
-gl_texturecompression_color 1
-gl_texturecompression_gloss 1
-gl_texturecompression_glow 1
-gl_texturecompression_lightcubemaps 1
-gl_texturecompression_q3bsplightmaps 0
-gl_texturecompression_sky 1
-
-cl_maxfps 200
-
-seta menu_mouse_absolute 1 "use the OS mouse pointer motion for menu"
-seta menu_mouse_speed 1 "speed multiplier for the mouse in the menu (does not affect in-game aiming)"
-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_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_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"
-seta cl_weaponpriority8 ""                                                              "use weapon_priority_8_prev for prev gun from this list, weapon_priority_8_best for best gun, weapon_priority_8_next for next gun"
-seta cl_weaponpriority9 ""                                                              "use weapon_priority_9_prev for prev gun from this list, weapon_priority_9_best for best gun, weapon_priority_9_next for next gun"
-seta cl_weaponimpulsemode 0 "0: only cycle between currently usable weapons in weapon priority order; 1: cycle between all possible weapons on a key in weapon priority order"
-
-alias _gl_flashblend_update_00 "gl_flashblend 1"
-alias _gl_flashblend_update_10 "gl_flashblend 0"
-alias _gl_flashblend_update_01 "gl_flashblend 0"
-alias _gl_flashblend_update_11 "gl_flashblend 0"
-alias gl_flashblend_update "_gl_flashblend_update_$r_shadow_realtime_dlight$r_showsurfaces"
-
-set cl_handicap 1      "multiplies damage received and divides damage dealt NOTE: reconnect or use 'sendcvar cl_handicap' to update the choice."
-
-seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice."
-
-seta cl_autoscreenshot 1 "Take a screenshot upon the end of a match... 0 = Disable completely, 1 = Allow sv_autoscreenshot to take a screenshot when requested, 2 = Always take an autoscreenshot anyway."
-
-seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disable, 1 = Stop when touching ground, 2 = Enable"
-
-seta cl_race_cptimes_showself 1 "Always show your own times as well as the current best on checkpoints in Race/CTS"
-seta cl_race_cptimes_onlyself 0 "Only show your own times on checkpoints in Race/CTS"
-
-set cl_stripcolorcodes 0       "experimental feature (notes: strips ALL color codes from messages!)"
-
-// Demo camera
-set camera_enable              0       "Enables the camera for demo playback"
-set camera_free                0       "Free camera instead of chasing the player"
-set camera_reset               0       "Resets the camera position and switch to chase mode"
-set camera_speed_roll          0.9     "Camera rotation speed"
-set camera_speed_chase                 4       "Camera movement speed on the x/y/z axis while chasing the player"
-set camera_speed_free          8       "Camera movement speed on the x/y/z axis in free mode"
-set camera_speed_attenuation   10      "Camera movements attenuation factor. Bigger is smoother. Applies to mouse movements"
-set camera_mouse_threshold     0.5     "Use to ignore small mouse movements. This allows for smoother camera control"
-set camera_chase_smoothly      0       "Attenuate player movements (only in chase mode)"
-set camera_look_player         0       "Always look to the player. Mouse input is ignored in this mode"
-set camera_look_attenuation    8       "Attenuation of \"looking\" movements, only if camera_look_player is set. Bigger is smoother"
-set camera_forward_follows     1       "0: Move the camera forwards without changing altitude. 1: Move towards what you are looking"
-
-// "Gentle mode": show no blood
-seta cl_gentle 0               "client side gentle mode, master switch for removing both gibs and messages"
-seta cl_gentle_gibs 0          "client side gentle mode (only replaces gibs); when set to 1, white smoke replaces gibs, when set to 2, colorful clouds replace gibs"
-seta cl_gentle_messages 0      "client side gentle mode (only replaces frag messages/centerprints)"
-seta cl_gentle_damage 0        "client side gentle mode (only replaces damage flash); when set to 1, a white flash replaces the blood image, when set to 2, a randomly colored flash is used instead"
-
-set cl_jetpack_attenuation 2 "jetpack sound attenuation"
-
-set cl_warpzone_usetrace 1 "do not touch"
-
-set cl_effects_lightningarc_simple 0
-set cl_effects_lightningarc_segmentlength 64
-set cl_effects_lightningarc_drift_start 0.45
-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
-set cl_loddistance2 3072
-seta cl_playerdetailreduction 4        "the higher, the less detailed player models are displayed (LOD)"
-seta cl_modeldetailreduction 1 "the higher, the less detailed certain map models are displayed (LOD)"
-
-seta cl_casings_maxcount 100 "maximum amount of shell casings (must be at least 1)"
-seta cl_gibs_maxcount 100 "maximum amount of gibs (must be at least 1)"
-
-//cl_gunalign calculator
-seta menu_cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
-alias _gunalign_01 "cl_gunalign 1"
-alias _gunalign_02 "cl_gunalign 2"
-alias _gunalign_03 "cl_gunalign 3"
-alias _gunalign_04 "cl_gunalign 4"
-alias _gunalign_11 "cl_gunalign 2"
-alias _gunalign_12 "cl_gunalign 1"
-alias _gunalign_13 "cl_gunalign 4"
-alias _gunalign_14 "cl_gunalign 3"
-alias _gunalign_update "_gunalign_$v_flipped$menu_cl_gunalign"
-
-set _menu_alpha "" // will be set by menu QC to the current fading of the menu, can be used by CSQC to fade items
-set _menu_initialized 0 "is 0 on first menu loading, 1 later"
-
-seta cl_noantilag 0 "turn this on if you believe antilag is bad"
-
-set cl_accuracy_data_share 0 "1 share my weapon accuracy data statistics with other players, 0 keep my weapon accuracy data statistics hidden"
-set cl_accuracy_data_receive 0 "1 receive weapon accuracy data statistics at the end of the match"
-
-set developer_csqcentities 0 "csqc entity spam"
-
-seta cl_forceplayermodels 0 "make everyone look like your own model (requires server to have sv_defaultcharacter 0)"
-seta cl_forceplayercolors 0 "make enemies look like your own color (requires server to have sv_defaultcharacter 0); set it to 2 to enable it even in teamplay (only when there is exactly one enemy team)"
-seta cl_forcemyplayermodel "" "set to the model file name you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
-seta cl_forcemyplayerskin 0 "set to the skin number you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
-seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_color) for your own player model (ignored in teamplay; does not affect how enemies look with cl_forceplayermodels)"
-seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce perceived lag"
-seta cl_movement_intermissionrunning 0 "keep velocity after the match ends, players may appear to continue running while stationary"
-
-set debugdraw 0
-set debugdraw_filter ""
-set debugdraw_filterout ""
-set debugtrace 0
-
-// FIXME remove this when the engine feature FINALLY MAYBE works
-r_glsl_skeletal 0
-
-// animation tuning
-set cl_lerpanim_maxdelta_framegroups 0.05 // must be faster than fastest weapon refire
-set cl_lerpanim_maxdelta_server 0.1 // must be slower than slowest server controlled anim (e.g. animinfo stuff)
-
-// autodemo deleting
-seta cl_autodemo_delete_keeprecords 0 "when 1, records with a newly made race/cts demo are kept even if cl_autodemo_delete is used to delete demos"
-
-// freeze camera
-set cl_lockview 0 "when 1, the camera does not move any more"
-
-// we now use mastervolume
-volume 1
-
-// sucks less than the old one
-cl_decals_newsystem 1
-
-scr_conalpha 1
-scr_conalpha2factor 0.3
-scr_conalpha3factor 1
-scr_conalphafactor 0.8
-scr_conbrightness 0.35
-scr_conforcewhiledisconnected 1
-scr_conscroll2_x 0.11
-scr_conscroll2_y 0.2
-scr_conscroll3_x 0
-scr_conscroll3_y 0
-scr_conscroll_x -0.1
-scr_conscroll_y -0.3
-
-scr_conforcewhiledisconnected 0
-scr_infobar_height 12
-
-// DP cannot properly detect this, so rather turn off the detection
-r_texture_dds_load_alphamode 2
-r_texture_dds_swdecode 1 // SW decode to quarter res if we want to load DDS but don't support the extension for it
-r_texture_dds_load_logfailure 0 // this engine feature SUCKS
-set vid_netwmfullscreen 0 // doesn't support non-native res
-
-// particles optimization
-r_drawparticles_nearclip_min 8
-r_drawparticles_nearclip_max 16
-
-r_cullentities_trace 0
-
-// exact gloss looks better, e.g. on g-23
-r_shadow_glossexact 1
-r_shadow_glossintensity 1
-
-// use fake light if map has no lightmaps
-r_fakelight 1
-
-r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
-r_water_refractdistort 0.019
-
-set cl_rainsnow_maxdrawdist 2048
-
-// equalize looks better than fullbright
-r_equalize_entities_fullbright 1
-
-// safe font defaults
-r_font_hinting 1
-r_font_disable_freetype 0
-r_font_size_snapping 4
-
-// database management
-set cl_db_saveasdump 0 "write client.db in dump format (loads slower, easier to read/parse)"
-
-// uid2name
-seta cl_allow_uid2name -1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid2name (allows showing your name in race rankings for instance)"
-seta cl_allow_uidtracking 1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid tracking (allows associating your data with your player ID)"
-// FIXME set to -1 before release, once we have a dialog for this!
-
-// polygonoffset for submodel SUCKS SUCKS SUCKS (only a hack for quake1, we don't need that)
-r_polygonoffset_submodel_offset 0
-r_polygonoffset_submodel_factor 0
-// decals: need a higher polygonoffset than default to not compete with _decal surfaces too much
-r_polygonoffset_decals_offset -28
-r_polygonoffset_decals_factor 0
-
-// loading screen
-scr_loadingscreen_background 0
-scr_loadingscreen_barcolor "0 0.5 1"
-scr_loadingscreen_barheight 12
-scr_loadingscreen_count 1
-scr_loadingscreen_firstforstartup 1
-scr_loadingscreen_scale 999
-scr_loadingscreen_scale_base 1
-scr_loadingscreen_scale_limit 2
-
-// other config files
-exec effects-normal.cfg
-exec crosshairs.cfg
-exec gamemodes-client.cfg
-exec notifications.cfg
-
-seta cl_physics "default" "client selected physics set"
-
-// hud cvar descriptions and common settings
-exec _hud_common.cfg
-exec _hud_descriptions.cfg
-// exec the default skin config
-// please add any new cvars into the hud_save script in qcsrc/client/hud_config.qc for consistency
-exec hud_luma.cfg
-
-// enable menu syncing - must be after files that call menu_sync on startup - see alias menu_sync ""
-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_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_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"
-
-// Facility for config.cfg use ONLY.
-// Interpreted in post-config.cfg.
-seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
-set menu_reverted_nonsaved_cvars "" "These cvars are currently marked as saved in the flags, but have been reverted and won't stay saved. INTERNAL USE ONLY."
diff --git a/defaultOverkill.cfg b/defaultOverkill.cfg
deleted file mode 100644 (file)
index f63f689..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-// ==============
-//  Overkill Mod
-// ==============
-
-exec defaultServer.cfg
-exec balance-overkill.cfg
-exec physicsOverkill.cfg
-
-// general gameplay
-set g_overkill 1
-
-// hack - eventually, we should be able to choose overkill models in menu like for vanilla
-set sv_defaultcharacter 1
-set sv_defaultplayermodel "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-set sv_defaultplayermodel_red "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
-set sv_defaultplayermodel_blue "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-set sv_defaultplayermodel_yellow "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
-set sv_defaultplayermodel_pink "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-
-set g_respawn_ghosts 0
-
-set g_nades 1
-set g_nades_nade_small 1
-set g_nades_spread 0
-set g_nades_nade_refire 10
-set g_nades_nade_newton_style 2
-
-set g_dodging 1
-set sv_dodging_wall_dodging 1
-
-set g_spawn_near_teammate "!g_assault !g_freezetag"
-set g_spawn_near_teammate_ignore_spawnpoint 1
-set g_spawnshieldtime 0.5
-set g_respawn_delay_forced 2
-
-set g_lms_start_armor 100
diff --git a/defaultServer.cfg b/defaultServer.cfg
deleted file mode 100644 (file)
index 4cabc22..0000000
+++ /dev/null
@@ -1,556 +0,0 @@
-// this should reset most cvars and aliases affecting gameplay to their defaults
-// note that it doesn't reset all server cvars,
-// some are shared with the client and so are left in defaultXonotic.cfg
-
-
-// taunts and voices
-set sv_taunt 1 "allow taunts on the server"
-set sv_autotaunt 1 "allow autotaunts on the server"
-
-// server settings
-hostname "Xonotic $g_xonoticversion Server"
-set sv_mapchange_delay 5
-set minplayers 0 "number of players playing at the same time (if not enough real players are there the remaining slots are filled with bots)"
-
-// restart server if all players hit "ready"-button
-set sv_ready_restart 0 "allow a map to be restarted once all players pressed the \"ready\" button"
-set sv_ready_restart_after_countdown 0 "reset players and map items after the countdown ended, instead of at the beginning of the countdown"
-set sv_ready_restart_repeatable 0      "allows the players to restart the game as often as needed"
-
-//nifreks lockonrestart feature, used in team-based game modes, if set to 1 and all players readied up no other player can then join the game anymore, useful to block spectators from joining
-set teamplay_lockonrestart 0 "lock teams once all players readied up and the game restarted (no new players can join after restart unless using the server-command unlockteams)"
-
-set g_maxplayers 0     "maximum number of players allowed to play at the same time, set to 0 to allow all players to join the game"
-set g_maxplayers_spectator_blocktime 5 "if the players voted for the \"nospectators\" command, this setting defines the number of seconds a observer/spectator has time to join the game before he gets kicked"
-
-// tournament mod
-set g_warmup 0 "split the game into a warmup- and match-stage"
-set g_warmup_limit 0   "limit warmup-stage to this time (in seconds); if set to -1 the warmup-stage is not affected by any timelimit, if set to 0 the usual timelimit also affects warmup-stage"
-set g_warmup_allow_timeout 0   "allow calling timeouts in the warmup-stage (if sv_timeout is set to 1)"
-set g_warmup_allguns 1 "provide more weapons on start while in warmup: 0 = normal start weapons, 1 = all guns available on the map, 2 = all normal weapons"
-set g_warmup_majority_factor 0.8 "minimum percentage of players ready needed for warmup to end"
-
-set g_chat_nospectators 0      "if 0 spec/observer chat is always visible to the player, if 1 it is never visible to players, if 2 it is only visible to players during warmup stage"
-set sv_vote_nospectators 0     "only players can call a vote (thus spectators and observers can't call a vote): 0 = all people can vote, 1 = spectators can vote in warmup stage, 2 = only players can vote (no exceptions)."
-
-alias g_tourney "g_tourney_$1"
-alias g_tourney_1 "g_warmup 1; g_chat_nospectators 2; sv_vote_nospectators 1"
-alias g_tourney_0 "g_warmup 0; g_chat_nospectators 0; sv_vote_nospectators 0"
-
-set sv_timeout 0       "allow a player to call a timeout, this will pause the game for some time"
-set sv_timeout_length 120      "how long the game will be paused at max, in seconds"
-set sv_timeout_number 2        "how many timeouts one player is allowed to call (gets reset after a restart)"
-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_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"
-set g_telefrags_avoid 1 "when teleporters have a random destination, avoid teleporting to locations where a telefrag would happen"
-set g_teleport_maxspeed 0 "maximum speed that a player can keep when going through a teleporter (if a misc_teleporter_dest also has a cap the smallest one of these will be used), 0 = don't limit, -1 = keep no speed"
-
-set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns"
-set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate"
-set g_respawn_ghosts_maxtime 6 "maximum amount of time a respawn ghost can last, minimum time is half this value. 0 disables and ghosts fade when the body would"
-
-set sv_gibhealth 100 "Minus health a dead body must have in order to get gibbed"
-
-// use default physics
-set sv_friction_on_land 0
-set sv_friction_slick 0.5
-
-set sv_slick_applygravity 0
-
-set sv_aircontrol_backwards 0 "apply forward aircontrol options to backward movement"
-set sv_aircontrol_sidewards 0 "apply forward aircontrol options to sideward movement"
-
-set sv_player_viewoffset "0 0 35" "view offset of the player model"
-set sv_player_mins "-16 -16 -24" "playermodel mins"
-set sv_player_maxs "16 16 45" "playermodel maxs"
-set sv_player_crouch_viewoffset "0 0 20" "view offset of the player model when crouched"
-set sv_player_crouch_mins "-16 -16 -24" "mins of a crouched playermodel"
-set sv_player_crouch_maxs "16 16 25" "maxs of a crouched playermodel"
-
-set sv_doublejump 0 "allow Quake 2-style double jumps"
-set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
-set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
-set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
-set sv_track_canjump 0 "track if the player released the jump key between 2 jumps to decide if they are able to jump or not"
-set sv_jumpvelocity_crouch 0 "jump height while crouching, set to 0 to use regular jump height"
-
-set sv_precacheplayermodels 1
-set sv_precacheweapons 0
-set sv_precacheitems 0
-set sv_spectator_speed_multiplier 1.5
-set sv_spectator_speed_multiplier_min 1
-set sv_spectator_speed_multiplier_max 5
-set sv_spectate 1 "if set to 1, new clients are allowed to spectate or observe the game, if set to 0 joining clients spawn as players immediately (no spectating)"
-set sv_defaultcharacter 0 "master switch, if set to 1 the further configuration for replacing all player models, skins and colors is taken from the sv_defaultplayermodel, sv_defaultplayerskin and sv_defaultplayercolors variables"
-set sv_defaultcharacterskin 0 "if set to 1 the further configuration for replacing all skins is taken from the sv_defaultplayerskin variables"
-set sv_defaultplayermodel "models/player/erebus.iqm" "default model selection, only works if sv_defaultcharacter is set to 1; you may append a :<skinnumber> suffix to model names; you can specify multiple, separated by space, and a random one will be chosen"
-set sv_defaultplayerskin 0 "each model has 1 or more skins (combination of model and skin = character), set which skin of the model you wish the default character to have, only works if sv_defaultcharacter is set to 1; can be overridden by :<skinnumber> suffix in sv_defaultplayermodel"
-set sv_defaultplayermodel_red ""       "\"\" means see sv_defaultplayermodel"
-set sv_defaultplayerskin_red 0
-set sv_defaultplayermodel_blue "" "\"\" means see sv_defaultplayermodel"
-set sv_defaultplayerskin_blue 0
-set sv_defaultplayermodel_yellow "" "\"\" means see sv_defaultplayermodel"
-set sv_defaultplayerskin_yellow 0
-set sv_defaultplayermodel_pink "" "\"\" means see sv_defaultplayermodel"
-set sv_defaultplayerskin_pink 0
-set sv_defaultplayercolors ""  "set to 16*shirt+pants to force a color, note: it does NOT depend on defaultcharacter! Set to \"\" to disable"
-set sv_autoscreenshot 0 "if set to 1, the server forces all clients to create a local screenshot once the map ended"
-net_messagetimeout 30
-net_connecttimeout 30
-sv_jumpstep 1 // step up stairs while jumping, makes it easier to reach ledges
-
-set sv_shownames_cull_distance 2500 "distance after which to not send origin/health/armor of another player"
-
-set bot_config_file bots.txt "Name and path of the bot configuration file"
-set bot_number 0       "Minimum number of bots"
-set bot_usemodelnames 0        "Use player model names for bot names"
-set bot_nofire 0       "When set, bots never fire. Mainly for testing in g_waypointeditor mode"
-set bot_prefix [BOT]   "Prefix in front of the bot names"
-set bot_suffix ""      "Suffix behind the bot names"
-set skill_auto 0       "when 1, \"skill\" gets adjusted to match the best player on the map"
-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."
-// general bot AI cvars
-set bot_ai_thinkinterval 0.05
-set bot_ai_strategyinterval 7 "How often a new objective is chosen"
-set bot_ai_strategyinterval_movingtarget 5.5 "How often a new objective is chosen when current objective can move"
-set bot_ai_enemydetectioninterval 2 "How often bots pick a new target"
-set bot_ai_enemydetectionradius 10000 "How far bots can see enemies"
-set bot_ai_dodgeupdateinterval 0.2 "How often scan for items to dodge. Currently not in use."
-set bot_ai_chooseweaponinterval 0.5 "How often the best weapon according to the situation will be chosen"
-set bot_ai_dangerdetectioninterval 0.25 "How often scan for waypoints with dangers near"
-set bot_ai_dangerdetectionupdates 64 "How many waypoints will be considered for danger detection"
-set bot_ai_aimskill_blendrate 2        "How much correction will be applied to the aiming angle"
-set bot_ai_aimskill_fixedrate 15
-set bot_ai_aimskill_firetolerance_distdegrees 100
-set bot_ai_aimskill_firetolerance_mindegrees 2 "Minimum angle tolerance. Used on large distances"
-set bot_ai_aimskill_firetolerance_maxdegrees 60 "Maximum firing angle. Used on close range"
-set bot_ai_aimskill_mouse 1 "How much of the aiming filters are applied"
-set bot_ai_keyboard_distance 250 "Keyboard emulation is disabled after this distance to the goal"
-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_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"
-set bot_ai_ignoregoal_timeout 3        "Ignore goals making bots to get stuck in front of a wall for N seconds"
-set bot_ai_bunnyhop_skilloffset 7      "Bots with skill equal or greater than this value will perform the  \"bunnyhop\" technique"
-set bot_ai_bunnyhop_startdistance 200 "Run to goals located further than this distance"
-set bot_ai_bunnyhop_stopdistance 300 "Stop jumping after reaching this distance to the goal"
-set bot_ai_bunnyhop_firstjumpdelay 0.2 "Start running to the goal only if it was seen for more than N seconds"
-set bot_god 0 "god mode for bots"
-set bot_ai_navigation_jetpack 0 "Enable bots to navigate maps using the jetpack"
-set bot_ai_navigation_jetpack_mindistance 3500 "Bots will try fly to objects located farther than this distance"
-// Better don't touch these, there are hard to tweak!
-set bot_ai_aimskill_order_mix_1st 0.01 "Amount of the 1st filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_2nd 0.1 "Amount of the 2nd filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_3th 0.01 "Amount of the 3th filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_4th 0.05 "Amount of the 4th filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_mix_5th 0.01 "Amount of the 5th filter output to apply to the aiming angle"
-set bot_ai_aimskill_order_filter_1st 0.4 "Position filter"
-set bot_ai_aimskill_order_filter_2nd 0.4 "Movement filter"
-set bot_ai_aimskill_order_filter_3th 0.2 "Acceleration filter"
-set bot_ai_aimskill_order_filter_4th 0.4 "Position prediction filter. Used rarely"
-set bot_ai_aimskill_order_filter_5th 0.5 "Movement prediction filter. Used rarely"
-set bot_ai_timeitems 1 "allow skilled bots to run to important items a little time before respawning"
-set bot_ai_timeitems_minrespawndelay 25 "bots run to items with this minimum respawn delay before respawning"
-
-// waypoint editor enable
-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_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)"
-set bot_ignore_bots 0  "When set, bots don't shoot at other bots"
-set bot_join_empty 0   "When set, bots also play if no player has joined the server"
-set bot_vs_human 0     "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
-
-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_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"
-set g_shootfromfixedorigin "" "if set to a string like 0 y z, the gun is moved to the given y and z coordinates. If set to a string like x y z, the whole shot origin is used"
-set g_pinata 0 "if set to 1 you will not only drop your current weapon when you are killed, but you will drop all weapons that you possessed"
-set g_weapon_stay 0 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
-set g_weapon_throwable 1 "if set to 1, weapons can be dropped"
-set g_powerups -1 "if set to 0 the strength and shield (invincibility) will not spawn on the map, if 1 they will spawn in all game modes, -1 is game mode default"
-set g_use_ammunition 1 "if set to 0 all weapons have unlimited ammunition"
-set g_pickup_items -1 "if set to 0 all items (health, armor, ammo, weapons...) are removed from the map, if 1 they are forced to spawn"
-set g_pickup_respawntime_scaling_reciprocal 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*"
-set g_pickup_respawntime_scaling_offset 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening"
-set g_pickup_respawntime_scaling_linear 1 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `linear` can be used to simply scale the respawn time linearly"
-set g_weaponarena "0"  "put in a list of weapons to enable a weapon arena mode, or try \"all\" or \"most\""
-set g_weaponarena_random "0"   "if set to a number, only that weapon count is given on every spawn (randomly)"
-set g_weaponarena_random_with_blaster "1"      "additionally, always provide the blaster in random weapon arena games"
-set g_spawnpoints_auto_move_out_of_solid 0 "if set to 1 you will see a warning if a spawn point was placed inside a solid"
-set g_forced_respawn 0 "if set to 1 and a player died, that player gets automatically respawned once <g_respawn_delay> seconds are over"
-set g_fullbrightplayers 0 "brightens up player models (note that the color, skin or model of the players does not change!)"
-set g_fullbrightitems 0 "brightens up items"
-set g_nodepthtestplayers 0 "disables depth testing on players"
-set g_nodepthtestitems 0 "disables depth testing on items"
-set g_casings 2 "specifies which casings (0: none, 1: only shotgun casings, 2: shotgun and machine gun casings) are sent to the client"
-set g_norecoil 0 "if set to 1 shooting weapons won't make you crosshair to move upwards (recoil)"
-set g_maplist_mostrecent "" "contains the name of the maps that were most recently played"
-set g_maplist_mostrecent_count 3       "number of most recent maps that are blocked from being played again"
-set g_maplist_index 0  "this is used internally for saving position in maplist cycle"
-set g_maplist_selectrandom 0   "if 1, a random map will be chosen as next map - DEPRECATED in favor of g_maplist_shuffle"
-set g_maplist_shuffle 1        "new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list"
-set g_maplist_check_waypoints 0        "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
-
-set g_items_mindist 4000 "starting distance for the fading of items"
-set g_items_maxdist 4500 "maximum distance at which an item can be viewed, after which it will be invisible"
-
-set g_grab_range 200 "distance at which dragable objects can be grabbed"
-
-set g_cloaked 0 "display all players mostly invisible"
-set g_player_alpha 1
-set g_player_brightness 0      "set to 2 for brighter players"
-set g_balance_cloaked_alpha 0.25
-
-set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
-set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"
-
-set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
-set g_grappling_hook_useammo 0 "use ammunition with the off-hand grappling hook"
-
-set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effects such as particles and sounds, see cl_spawn_ cvars for more info"
-set g_spawn_furthest 0.5 "this amount of the spawns shall be far away from any players"
-set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay"
-// respawn delay
-set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again"
-set g_respawn_delay_small_count 0 "Player count per team for g_respawn_delay_small. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
-set g_respawn_delay_large 2 "large game number of seconds you have to wait before you can respawn again"
-set g_respawn_delay_large_count 8 "Player count per team for g_respawn_delay_large. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
-set g_respawn_delay_max 5 "number of seconds you can wait before you're forced to respawn (only effective with g_forced_respawn 1)"
-set g_respawn_delay_forced 0 "enforce regular respawn delay (prevent gamemode specific respawn delays)"
-set g_respawn_waves 0 "respawn in waves (every n seconds), intended to decrease overwhelming base attacks"
-
-// overtime
-set timelimit_overtime 2 "duration in minutes of one added overtime, added to the timelimit"
-set timelimit_overtimes 0 "how many overtimes to add at max"
-set timelimit_suddendeath 5 "number of minutes suddendeath mode lasts after all overtimes were added and still no winner was found"
-
-// common team values
-set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
-set g_tdm_on_dm_maps 0 "when this is set, all DM maps automatically support TDM"
-
-set teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
-set g_mirrordamage 0.7              "for teamplay_mode 4: mirror damage factor"
-set g_mirrordamage_virtual 1        "for teamplay_mode 4: do not actually apply mirror damage, just show graphics effect for it"
-set g_mirrordamage_onlyweapons 0    "for teamplay_mode 4: only apply mirror damage if the attack was from a weapon"
-set g_friendlyfire 0.5              "for teamplay_mode 4: friendly fire factor"
-set g_friendlyfire_virtual 1        "for teamplay_mode 4: do not actually apply friendly fire, just show graphics effect for it"
-set g_friendlyfire_virtual_force 1  "for teamplay_mode 4: apply force even though damage was made virtual only"
-set g_teamdamage_threshold 40       "for teamplay_mode 4: threshold over which to apply mirror damage"
-set g_teamdamage_resetspeed 20      "for teamplay_mode 4: how fast player's teamdamage count decreases"
-
-set g_balance_teams 1  "automatically balance out players entering instead of asking them for their preferred team"
-set g_balance_teams_prevent_imbalance  1       "prevent players from changing to larger teams"
-set g_balance_teams_scorefactor 0.25 "at the end of the game, take score into account instead of team size by this amount (beware: values over 0.5 mean that a x:0 score imbalance will cause ALL new players to prefer the losing team at the end, despite numbers)"
-set g_changeteam_banned 0      "not allowed to change team"
-set g_changeteam_fragtransfer 0        "% of frags you get to keep when you change teams (rounded down)"
-
-set sv_teamnagger 1 "enable a nag message when the teams are unbalanced"
-
-set g_bloodloss 0   "amount of health below which blood loss occurs"
-
-set g_footsteps 1      "serverside footstep sounds"
-
-set g_throughfloor_debug 0 "enable debugging messages for throughfloor calculations"
-set g_throughfloor_damage_max_stddev 2 "Maximum standard deviation for splash damage"
-set g_throughfloor_force_max_stddev 10 "Maximum standard deviation for splash force"
-set g_throughfloor_min_steps_player 1 "Minimum number of steps for splash damage"
-set g_throughfloor_min_steps_other 1 "Minimum number of steps for splash damage"
-set g_throughfloor_max_steps_player 100 "Maximum number of steps for splash damage"
-set g_throughfloor_max_steps_other 10 "Maximum number of steps for splash damage"
-// note: for damage X, 0.25 * ((1-g_throughfloor_damage)*X / g_throughfloor_damage_max_stddev)^2 steps are used
-// for these numbers:
-//   damage  25: 3
-//   damage  60: 15
-//   damage  80: 25
-//   damage 200: 157
-//   force  250: 10
-//   force  300: 15
-//   force  600: 57
-
-sv_maxvelocity 1000000000
-sv_sound_land ""
-sv_sound_watersplash ""
-
-// startmap_dm is used when running with the -listen or -dedicated commandline options
-set serverconfig server.cfg
-alias loadconfig "cvar_resettodefaults_saveonly; exec ${* !}"
-set _sv_init 0
-alias startmap_dm "set _sv_init 0; map _init/_init; exec $serverconfig; set _sv_init 1"
-
-// score log
-set sv_logscores_console 0     "print scores to server console"
-set sv_logscores_file 0        "print scores to file"
-set sv_logscores_filename scores.log   "filename"
-set sv_logscores_bots 0        "exclude bots by default"
-
-// spam (frag/capture) log
-set sv_eventlog 0      "the master switch for efficiency reasons"
-set sv_eventlog_console 1
-set sv_eventlog_files 0
-set sv_eventlog_files_timestamps 1
-set sv_eventlog_files_counter 0
-set sv_eventlog_files_nameprefix xonotic
-set sv_eventlog_files_namesuffix .log
-
-set nextmap "" "override the maplist when switching to the next map"
-set lastlevel ""
-set quit_when_empty 0  "set to 1, then the server exits when the next level would start but is empty"
-set quit_and_redirect ""       "set to an IP to redirect all players at the end of the match to another server. Set to \"self\" to let all players reconnect at the end of the match (use it to make seamless engine updates)"
-set quit_and_redirect_timer 1.5 "set to number of seconds after quit before performing the connect operation of quit_and_redirect"
-
-// Green's fullbright skins, updated by Samual
-alias sv_fbskin_unique "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors \"\""
-alias sv_fbskin_green "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 51"
-alias sv_fbskin_red "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 68"
-alias sv_fbskin_orange "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 238"
-alias sv_fbskin_rainbow "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 95"
-
-alias sv_fbskin_off "sv_defaultcharacter 0; sv_defaultplayerskin 0; sv_defaultplayercolors \"\""
-
-set sv_servermodelsonly 1
-
-sv_curl_defaulturl "http://www.xonotic.org/contentdownload/getmap.php?file="
-set sv_curl_serverpackages_auto 1 "automatically add packs with *.serverpackage files to sv_curl_serverpackages"
-
-set sv_motd ""
-
-set g_waypoints_for_items 0    "make waypoints out of items, values: 0 = never, 1 = unless the mapper prevents it by worldspawn.spawnflags & 1, 2 = always"
-
-set g_maplist_votable 6 "number of maps that are shown in the map voting at the end of a match"
-set g_maplist_votable_keeptwotime 15 "show only 2 options after this amount of time during map vote screen"
-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_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_timeout 20
-set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
-
-set g_chat_flood_spl 3 "normal chat: seconds between lines to not count as flooding"
-set g_chat_flood_lmax 2        "normal chat: maximum number of lines per chat message at once"
-set g_chat_flood_burst 2       "normal chat: allow bursts of so many chat lines"
-set g_chat_flood_spl_team 1    "team chat: seconds between lines to not count as flooding"
-set g_chat_flood_lmax_team 2   "team chat: maximum number of lines per chat message at once"
-set g_chat_flood_burst_team 2  "team chat: allow bursts of so many chat lines"
-set g_chat_flood_spl_tell 1    "private chat: seconds between lines to not count as flooding"
-set g_chat_flood_lmax_tell 2   "private chat: maximum number of lines per chat message at once"
-set g_chat_flood_burst_tell 2  "private chat: allow bursts of so many chat lines"
-set g_chat_flood_notify_flooder 1      "when 0, the flooder still can see his own message"
-set g_chat_teamcolors 0        "colorize nicknames in team color for chat"
-set g_chat_tellprivacy 1 "when disabled, tell messages are also sent to the server console log... otherwise they're kept private between players."
-set g_nick_flood_timeout 120 "time after which nick flood protection resets (set to 0 to disable nick flood checking)"
-set g_nick_flood_penalty 0.5 "duration of the nick flood penalty"
-set g_nick_flood_penalty_yellow 3 "number of changes to allow before warning and movement blocking"
-set g_nick_flood_penalty_red 30 "number of changes to allow before totally disorienting the player"
-
-set sv_waypointsprite_deployed_lifetime 10
-set sv_waypointsprite_deadlifetime 1
-set sv_waypointsprite_limitedrange 5120
-
-set sv_itemstime 1 "enable networking of time left until respawn for items such as mega health/armor and powerups"
-
-set g_ban_default_bantime 5400 "90 minutes"
-set g_ban_default_masksize 3   "masksize 0 means banning by UID only, 1 means banning by /8 (IPv6: /32) network, 2 means banning by /16 (IPv6: /48) network, 3 means banning by /24 (IPv6: /56) network, 4 means banning by single IP (IPv6: /64 network)"
-set g_banned_list ""   "format: IP remainingtime IP remainingtime ..."
-set g_banned_list_idmode "1"   "when set, the IP banning system always uses the ID over the IP address (so a user in a banned IP range can connect if they have a valid signed ID)"
-
-// useful vote aliases
-set timelimit_increment 5
-set timelimit_decrement 5
-set timelimit_min 5
-set timelimit_max 60
-
-sv_gameplayfix_delayprojectiles 0
-sv_gameplayfix_q2airaccelerate 1
-sv_gameplayfix_stepmultipletimes 1
-
-// delay for "kill" to prevent abuse
-set g_balance_kill_delay 2
-set g_balance_kill_antispam 5
-
-// this feature is currently buggy in the engine (it appears to PREVENT any dropping in lots of maps, leading to weirdly aligned entities, and in some cases even CAUSES them to drop through solid, like in facing worlds nex)
-sv_gameplayfix_droptofloorstartsolid 0
-
-set sv_foginterval 1 "force enable fog in regular intervals"
-
-set sv_maxidle 0 "kick players idle for more than this amount of time in seconds"
-set sv_maxidle_spectatorsareidle 0 "when sv_maxidle is not 0, assume spectators are idle too"
-set sv_maxidle_slots 0 "when not 0, only kick idlers when this many or less player slots are available"
-set sv_maxidle_slots_countbots 1 "count bots as player slots"
-
-sv_allowdownloads_inarchive 1 // for csprogs.dat
-sv_allowdownloads 0 // download protocol is evil
-
-set g_jump_grunt 0     "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
-
-set g_maplist_allow_hidden 0           "allow hidden maps to be, e.g., voted for and in the maplist"
-set g_maplist_allow_frustrating 0      "allow impossible maps to be, e.g., voted for and in the maplist (if set to 2, ONLY impossible maps are allowed)"
-
-set sv_clones 0        "number of clones a player may make (reset by the \"kill\" command)"
-
-set g_ban_sync_uri ""  "sync using this ban list provider (empty string to disable)"
-set g_ban_sync_interval 5      "sync every 5 minutes"
-set g_ban_sync_trusted_servers ""      "request ban lists from these xonotic servers (do not include your own server there, or unbanning may fail)"
-set g_ban_sync_timeout 45      "time out in seconds for the ban sync requests"
-set g_ban_sync_trusted_servers_verify 0        "when set to 1, additional bans sent by the servers are ignored, and only bans for the requested IP are used"
-
-set g_showweaponspawns 1 "1: display waypoints for weapon spawns found on the map when a weapon key is pressed and the weapon is not owned; 2: for dropped weapons too; 3: for all the weapons sharing the same impulse"
-
-// ballistics use physical units, but qu based
-//   Quake-Newton: 1 qN  = 1 qu * 1 g / 1 s^2
-//   Quake-Joule:  1 qJ  = 1 qN * 1 qu
-//   Quake-Pascal: 1 qPa = 1 qN / 1 qu^2
-
-set g_ballistics_mindistance 2 // enable ballistics starting from 2 qu
-set g_ballistics_density_player 0.50 // players are 2x as easy to pass as walls
-set g_ballistics_density_corpse 0.10 // corpses are 10x as easy to pass as walls
-set g_ballistics_penetrate_clips 0 "allow ballistics to pass through weapon clips"
-
-sv_status_show_qcstatus 1      "Xonotic uses this field instead of frags"
-set g_full_getstatus_responses 0       "this currently breaks qstat"
-
-// "Gentle mode": show no blood
-set sv_gentle 0                "force gentle mode for everyone, also remove references to acts of killing from the messages"
-
-set g_jetpack 0 "Jetpack mutator"
-
-set g_hitplots 0 "when set to 1, hitplots are stored by the server to provide a means of proving that a triggerbot was used"
-set g_hitplots_individuals "" "the individuals, by IP, that should have their hitplots recorded"
-
-set bot_navigation_ignoreplayers 0 // FIXME remove this once the issue is solved
-set bot_sound_monopoly 0 "when enabled, only bots can make any noise"
-
-set g_mapinfo_settemp_acl "+*" "ACL for mapinfo setting cvars"
-
-set g_triggerimpulse_accel_power 1 "trigger_impulse accelerator power (applied BEFORE the multiplier)"
-set g_triggerimpulse_accel_multiplier 1 "trigger_impulse accelerator multiplier (applied AFTER the power)"
-set g_triggerimpulse_directional_multiplier 1 "trigger_impulse directional field multiplier"
-set g_triggerimpulse_radial_multiplier 1 "trigger_impulse radial field multiplier"
-
-set sv_weaponstats_file "" "when set to a file name, per-weapon stats get written to that file"
-
-set rescan_pending 0 "set to 1 to schedule a fs_rescan at the end of this match"
-
-set g_mapinfo_allow_unsupported_modes_and_let_stuff_break "0" "set to 1 to be able to force game types using g_ cvars even if the map does not support them"
-set g_mutatormsg "" "mutator message"
-
-set spawn_debug 0 "use all spawns one by one, then abort, to verify all spawnpoints"
-set loddebug 0 "force this LOD level"
-set speedmeter 0 "print landing speeds"
-set waypoint_benchmark 0 "quit after waypoint loading to benchmark bot navigation code"
-set g_debug_bot_commands 0 "print scripted bot commands before executing"
-
-// weapon accuracy stats
-set sv_accuracy_data_share 1 "1 send weapon accuracy data statistics to spectating clients, depends on cl_accuracy_data_share"
-set sv_accuracy_data_send 1 "1 send weapon accuracy data statistics and improved score info to all the clients at the end of the match, depends on cl_accuracy_data_receive, 0 send the current 'player has won' to all the clients"
-
-// debug
-set _independent_players 0 "DO NOT TOUCH"
-set _notarget 0 "NO, REALLY, DON'T"
-
-// otherwise, antilag breaks
-sv_gameplayfix_consistentplayerprethink 1
-
-// improve some minor details
-sv_gameplayfix_gravityunaffectedbyticrate 1
-sv_gameplayfix_nogravityonground 1
-
-set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
-
-set g_movement_highspeed 1 "movement speed modification factor (only changes movement when above maxspeed)"
-
-set g_maxspeed 0 "player speed limit, faster players are killed (0 for unlimited speed)"
-
-// sv_cullentities_trace is 1, so the client doesn't have to
-sv_cullentities_trace 1
-
-// less "lagging" of other players, but also less PL tolerant... let's try this
-sv_clmovement_inputtimeout 0.066 // slightly less than 2 frames, so only one frame can be compensated
-
-// strength sound settings
-set sv_strengthsound_antispam_time 0.1 "minimum distance of strength sounds"
-set sv_strengthsound_antispam_refire_threshold 0.04 "apply minimum distance only if refire of the gun is smaller than this"
-
-// database management
-set sv_db_saveasdump 0 "write server.db in dump format (loads slower, easier to read/parse)"
-
-// allow fullbright
-set sv_allow_fullbright 1 "when set, clients may use r_fullbright on this server without getting a night vision effect overlay"
-
-// auto-teams (team selection by player ID)
-// any player not listed is forced to spectate
-set g_forced_team_red "" "list of player IDs for red team"
-set g_forced_team_blue "" "list of player IDs for blue team"
-set g_forced_team_yellow "" "list of player IDs for yellow team"
-set g_forced_team_pink "" "list of player IDs for pink team"
-set g_forced_team_otherwise "default" "action if a non listed player joins (can be default for default action, spectate for forcing to spectate, or red, blue, yellow, pink)"
-
-// nice alias to set up a match
-// example: g_forced_team_matchsetup stormkeep "mzDo0nO2y3XpFPNbQAyeUucyaejZ9xpiXLYMGU2x3qM=" "BRLOGENSHFEGLE/+Mq3x2UGMYLXipx9ZjeaycuUeyAQ="
-// will set up a match on stormkeep where mzDo0nO2y3XpFPNbQAyeUucyaejZ9xpiXLYMGU2x3qM= and BRLOGENSHFEGLE/+Mq3x2UGMYLXipx9ZjeaycuUeyAQ= play against each other
-alias g_forced_team_matchsetup "map $1; settemp g_forced_team_red \"$2\"; settemp g_forced_team_blue \"$3\"; settemp g_forced_team_yellow \"$4\"; settemp g_forced_team_pink \"$5\"; settemp g_forced_team_otherwise spectate"
-
-// frozen
-set g_frozen_revive_falldamage 0 "Enable reviving from this amount of fall damage"
-set g_frozen_revive_falldamage_health 40 "Amount of health player has if they revived from falling"
-set g_frozen_damage_trigger 1 "if 1, frozen players falling into the void will die instead of teleporting to spawn"
-set g_frozen_force 0.6 "How much to multiply the force on a frozen player with"
-
-// player statistics
-set g_playerstats_gamereport_uri "http://stats.xonotic.org/stats/submit" "Output player statistics information to either: URL (with ://), console (with a dash like this: -), or supply a filename to output to data directory."
-set g_playerstats_gamereport_ladder ""
-set g_playerstats_playerbasic_uri "http://stats.xonotic.org"
-set g_playerstats_playerdetail_uri "http://stats.xonotic.org/player/me"
-set g_playerstats_playerdetail_autoupdatetime 1800 // automatically update every 30 minutes anyway
-
-// autoscreenshots
-set g_max_info_autoscreenshot 3 "how many info_autoscreenshot entities are allowed"
-
-// mod names for server browser
-// note: the lowest of these that mismatches default is used
-set g_mod_physics "" "Current physics config name"
-set g_mod_balance "" "Current balance config name"
-set g_mod_config  "" "Current config mod name"
-
-// other config files
-exec balance-xonotic.cfg
-exec physicsX.cfg
-exec turrets.cfg
-exec gamemodes-server.cfg
-exec mutators.cfg
-exec monsters.cfg
-exec minigames.cfg
-exec physics.cfg
-
-set sv_join_notices ""
-set sv_join_notices_time 15
-
-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"
diff --git a/defaultXDF.cfg b/defaultXDF.cfg
deleted file mode 100644 (file)
index d504b2a..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-// ================
-//  Xonotic Defrag
-// ================
-
-exec defaultServer.cfg
-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_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
-// g_playerclip_collisions 0 // do not check playerclips
-set g_powerups 0  // set to -1 or patch xonotic
-set g_spawnpoints_auto_move_out_of_solid 1
-set g_start_delay 3
-set g_use_ammunition 0 "if set to 0 all weapons have unlimited ammunition"
-set g_weapon_stay 1 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
-set teamplay_mode 2 // friendly fire and self damage
-set sv_vote_nospectators 1
-set timelimit_override 20
-set g_buffs_cooldown_respawn 0.1
-
-// game mode settings
-set g_cts_finish_kill_delay 2
-set g_cts_respawn_delay 0
-set g_cts_selfdamage 0
diff --git a/defaultXPM.cfg b/defaultXPM.cfg
deleted file mode 100644 (file)
index fd34497..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-// ==================
-//  Xonotic Pro-Mode
-// ==================
-
-exec defaultServer.cfg
-exec balance-xpm.cfg
-
-// general gameplay
-set g_norecoil 1
-set g_shootfromeye 1 // hit where you point at with the crosshair (promoders don't care about ugliness)
-set g_balance_kill_antispam 0
-set g_forced_respawn 1
-set teamplay_mode 2 // friendly fire and self damage
-set sv_vote_nospectators 1
-set g_chat_nospectators 2
-set g_warmup 1
-set g_balance_teams 0
-set g_spawnshieldtime 0
-set g_spawn_furthest 1
-set sv_autoscreenshot 1
-set sv_ready_restart 1
-set sv_ready_restart_after_countdown 1
-set g_monsters 0
-set g_turrets 0
-set g_vehicles 0
-set sv_showspectators 0
diff --git a/defaultXonotic.cfg b/defaultXonotic.cfg
deleted file mode 100644 (file)
index bac826e..0000000
+++ /dev/null
@@ -1,147 +0,0 @@
-// Xonotic version (formatted for machines)
-// used to determine if a client version is compatible
-// this doesn't have to be bumped with every release
-// bump when clients become incompatible or any other perfectly good reason
-// (e.g. game data incompatibility, engine version incompatibility, etc
-// note: this automatically filters the server browser, clients of the new
-// version won't see old servers, and clients of the old version won't see new
-// servers either
-//
-// e.g. Xonotic 1.5.1 RC1 will be 15101
-set g_xonoticversion git "Xonotic version (formatted for humans)"
-
-gameversion 802 // 0.8.2
-gameversion_min 0 // git builds see all versions
-gameversion_max 65535 // git builds see all versions
-
-// compatibility guideline:
-//   version a.b.c   = a0b0c
-//   gameversion_min = a0(b-1)00 // show servers of the previous "line"
-//   gameversion_max = a0(b+1)99 // show servers of the next "line"
-// so, for a given gameversion, _min and _max calculate as follows:
-//   gameversion_min = (gameversion / 100) * 100 - 100
-//   gameversion_max = (gameversion / 100) * 100 + 199
-
-seta g_configversion 0 "Configuration file version (used to upgrade settings) 0: first run, or previous start was <2.4.1  Later, it's overridden by config.cfg, version ranges are defined in config_update.cfg"
-
-exec defaultClient.cfg
-exec defaultServer.cfg
-
-set ekg 0      "Throw huge amounts of gibs"
-
-_cl_playermodel "models/player/erebus.iqm"
-
-locs_enable 0
-pausable 0
-set samelevel 0 "when 1, always play the same level over and over again"
-
-fs_empty_files_in_pack_mark_deletions 1 // makes patches able to delete files
-
-// singleplayer campaign
-set g_campaign 0
-set g_campaign_forceteam 0 "Forces the player to a given team in campaign mode, 1 = red, 2 = blue, 3 = yellow, 4 = pink"
-seta g_campaign_name "xonoticbeta"
-seta g_campaign_skill -1 // -2 easy -1 medium 0 hard
-
-alias singleplayer_start "g_campaign_index 0; set scmenu_campaign_goto 0"
-alias singleplayer_continue "set scmenu_campaign_goto -1"
-alias singleplayer_levellist "set scmenu_campaign_dump 1; togglemenu; wait; togglemenu"
-
-// campaign internal, set when loading a campaign map1G
-set _campaign_index ""
-set _campaign_name ""
-set _campaign_testrun 0 "To verify the campaign file, set this to 1, then start the first campaign level from the menu. If you end up in the menu again, it's good, if you get a QC crash, it's bad."
-
-// used by both server and menu to maintain the available list of maps
-seta g_maplist "" "the list of maps to be cycled among (is autogenerated if empty)"
-
-// we must change its default from 1.0 to 1 to be consistent with menuqc
-set slowmo 1
-
-// ticrate
-//sys_ticrate 0.0166667 // 60fps. This would be ideal, but kills home routers.
-sys_ticrate 0.0333333 // Use 30fps instead.
-
-// Audio track names (for old-style "cd loop NUMBER" usage)
-set _cdtrack_first "1"
-alias _cdtrack_0 "g_cdtracks_remaplist \"$g_cdtracks_remaplist $1\""
-alias _cdtrack_1 "g_cdtracks_remaplist \"$1\"; set _cdtrack_first 0"
-alias _cdtrack "_cdtrack_$_cdtrack_first $2"
-set g_cdtracks_remaplist ""
-exec cdtracks.cfg
-unset _cdtrack_first
-unalias _cdtrack_0
-unalias _cdtrack_1
-unalias _cdtrack
-
-cd remap $g_cdtracks_remaplist
-set sv_intermission_cdtrack ""
-
-set g_cdtracks_dontusebydefault "rising-of-the-phoenix"
-seta menu_cdtrack "rising-of-the-phoenix"
-
-// these entities are not referenced by anything directly, they just represent
-// teams and are found by find() when needed
-prvm_leaktest_ignore_classnames "ctf_team dom_team tdm_team"
-prvm_backtraceforwarnings 1
-
-set _urllib_nextslot 0 "temp variable"
-
-set g_debug_defaultsounds 0 "always use default sounds"
-
-// define some engine cvars that we need even on dedicated server
-set r_showbboxes 0
-
-// support Q1BSP maps
-mod_q1bsp_polygoncollisions 1
-
-// match q3map2
-mod_obj_orientation 0
-
-// UTF-8
-utf8_enable 1
-
-// this is mainly for _decal entities (their shaders should use "polygonoffset" shader parameter) - this is "good enough" as it seems, but smaller than the decals one so these don't zfight decals
-mod_q3shader_default_polygonoffset -14
-mod_q3shader_default_polygonfactor 0
-
-// random charge stuff :P
-set g_weapon_charge_colormod_hdrmultiplier 4 "how much to multiply the colors by in the colormod vector"
-set g_weapon_charge_colormod_red_half 0
-set g_weapon_charge_colormod_green_half 0.5
-set g_weapon_charge_colormod_blue_half 1
-set g_weapon_charge_colormod_red_full 1
-set g_weapon_charge_colormod_green_full -0.5
-set g_weapon_charge_colormod_blue_full -1
-
-// session locking
-locksession 1
-
-// create this cvar in case the engine did not
-set snd_soundradius 1200
-set snd_softclip 1
-set snd_maxchannelvolume 0
-set snd_streaming_length 2
-seta menu_snd_sliderscale 2 "0: decibels; 1: linear percent; 2: 0..10 scale; 3: slider size percent"
-seta menu_snd_attenuation_method 1 "Use exponential instead of linear falloff for sound attenuation"
-alias snd_attenuation_method_0 "set menu_snd_attenuation_method 0; set snd_soundradius 1200; set snd_attenuation_exponent 1; set snd_attenuation_decibel 0" // Quake default
-alias snd_attenuation_method_1 "set menu_snd_attenuation_method 1; set snd_soundradius 2400; set snd_attenuation_exponent 4; set snd_attenuation_decibel 0" // nice approximation for method 2
-alias snd_attenuation_method_2 "set menu_snd_attenuation_method 2; set snd_soundradius 1200; set snd_attenuation_exponent 0; set snd_attenuation_decibel 10" // warning: plays sounds within up to 6000qu
-snd_attenuation_method_1
-
-// declare the channels we use
-seta snd_channel8volume 1 "QuakeC controlled background music volume"
-seta snd_channel9volume 1 "QuakeC controlled ambient sound volume"
-
-// sound randomization
-snd_identicalsoundrandomization_time -0.1
-snd_identicalsoundrandomization_tics    1
-
-// load console command aliases and settings
-exec commands.cfg
-
-// ... and now that everything is configured/aliased, we can do some things:
-
-// Change g_start_delay based upon if the server is local or not.
-if_client set g_start_delay 0  "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
-if_dedicated set g_start_delay 15      "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
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 48c8253a3a2146538f1a9dfa6cc388f76b616ba4..597bb4660a9f0e063e6009652c8c0997dbbbd99e 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index b7e9a98a3a7a78fa396023d1f3fe615cd4cb4c4a..c9549581bddb35ebfc0fa858b347760aed609b13 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 66eed5aa5d55dc897c6cd748848cd5ed82cb3efe..4ea20a1699d110c6742eab52260963c581b9ee66 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 63dcd134a066f0c4255c4ad380f085249e177d0a..c421e5b325b6925c89b17e2a926fe018e5a170b2 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 4
 gl_flashblend 0
 gl_picmip 0
+gl_texturecompression_2d 0
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 0
 r_bloom 0
 r_coronas 1
index 9018ee2c94375ba8740fa35f3357f55ff1d3cf15..7614417ce2027e42c4d711fce396faaaf7c1cd14 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 0
 cl_playerdetailreduction 4
 gl_flashblend 1
 gl_picmip 1337
+gl_texturecompression_2d 1
+gl_texturecompression_sky 1
 mod_q3bsp_nolightmaps 1
 r_bloom 0
 r_coronas 1
index 0cf3a899cbcebf5fa385a66ffd3fc07f326ca3c0..3ce6f55a7f01483f9a6c94d1c4a9d53405abbe8b 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index 5909f3b83dc956b18141d4c0111b251c60080813..d42d7c58ba07362f3d95b73bd5a6e8b90dab5835 100644 (file)
@@ -8,6 +8,8 @@ cl_spawn_point_particles 1
 cl_playerdetailreduction 0
 gl_flashblend 0
 gl_picmip -1
+gl_texturecompression_2d 0
+gl_texturecompression_sky 0
 mod_q3bsp_nolightmaps 0
 r_bloom 1
 r_coronas 1
index 6790a3b4fb9575ab91e070c57bc984ac97609ba2..41b5fc5dbe745dd85c02b81e6ad2b3ac6d2a574f 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"
 
 
 // ==========================
@@ -477,7 +478,7 @@ seta g_nexball_tackling 1 "Allow ball theft?"
 set g_onslaught 0 "Onslaught: take control points towards the enemy generator and then destroy it"
 set g_onslaught_point_limit 1 "Onslaught point limit overriding the mapinfo specified one (use 0 to play without limit, and -1 to use the mapinfo's limit)"
 set g_onslaught_warmup 5
-set g_onslaught_round_timelimit 280
+set g_onslaught_round_timelimit 500
 set g_onslaught_teleport_radius 200 "Allows teleporting from a control point to another"
 set g_onslaught_teleport_wait 5 "Time before player can teleport again"
 set g_onslaught_spawn_choose 1 "Allow players to choose the control point to be spawned at"
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 c997fea25772cd797dc361c60304db04e7cc3b5b..cfaa1e5804da071f55675621780791861d5b3fc2 100644 (file)
@@ -205,7 +205,6 @@ COLOR_SLIDER_D                '1 1 1'
 COLOR_SLIDER_F                '1 1 1'
 COLOR_SLIDER_N                '1 1 1'
 COLOR_SLIDER_S                '1 1 1'
-TOLERANCE_SLIDER              '0.2 2 0'
 WIDTH_SLIDERTEXT              0.333333333333
 
 // tooltip
index ca0384fb554135f88ed4bf13a41c3b3e849497f9..2ffe29af0c04e785e215421c99c9a450d6b71ae5 100755 (executable)
@@ -252,4 +252,3 @@ COLOR_SLIDER_F                  '1 1 1'
 COLOR_SLIDER_D                  '1 1 1'
 COLOR_SLIDER_S                  '1 1 1'
 WIDTH_SLIDERTEXT                0.333333333333
-TOLERANCE_SLIDER                '0.2 2 0'
index b7011a0b0e18369246a573e86f52dd0d22174bb4..0580e89eb1a152813fe0a25636285f84740a85ce 100644 (file)
@@ -252,4 +252,3 @@ COLOR_SLIDER_F                  '0.5 0.75 1'
 COLOR_SLIDER_D                  '1 1 1'
 COLOR_SLIDER_S                  '0.25 0.25 0.25'
 WIDTH_SLIDERTEXT                0.333333333333
-TOLERANCE_SLIDER                '0.2 2 0'
index 5f4bbaad40211135e157b03f89e82e99ef337475..af7d8ce165a92e7d6941a7692393a7ebdca387bb 100644 (file)
@@ -233,4 +233,3 @@ COLOR_SLIDER_F                  '1 1 1'
 COLOR_SLIDER_D                  '1 1 1'
 COLOR_SLIDER_S                  '1 1 1'
 WIDTH_SLIDERTEXT                0.333333333333
-TOLERANCE_SLIDER                '0.2 2 0'
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 15591688dc9c2eb940eefd45ac5bdc951fe562c3..65ce9094219c56f80574f2735befda22cf3c46bd 100644 (file)
@@ -1,21 +1,25 @@
+ko    Korean "한국의" 33%
 ast   Asturian "Asturianu" 73%
-de    German "Deutsch" 99%
-de_CH German "Deutsch (Schweiz)" 99%
+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" 100%
-it    Italian "Italiano" 100%
+fr    French "Français"
+ga    Irish "Irish" 35%
+it    Italian "Italiano"
 hu    Hungarian "Magyar" 55%
 nl    Dutch "Nederlands" 70%
-pl    Polish "Polski" 80%
-pt    Portuguese "Português" 99%
-ro    Romanian "Romana" 84%
+pl    Polish "Polski" 81%
+pt    Portuguese "Português"
+pt_BR pt_BR "pt_BR" 99%
+ro    Romanian "Romana" 83%
 fi    Finnish "Suomi" 33%
 zh_TW "Chinese (Taiwan)" "國語" 68%
 el    Greek "Ελληνική" 33%
-be    Belarusian "Беларуская" 62%
+be    Belarusian "Беларуская" 61%
 bg    Bulgarian "Български" 68%
-ru    Russian "Русский" 100%
+ru    Russian "Русский"
 sr    Serbian "Српски" 71%
 uk    Ukrainian "Українська" 57%
index 3f1a594d0692979666b44cc660ac2493adf01597..3e9a8f82cb4290cb31780635013b9b5dde6f8dcc 100644 (file)
Binary files a/models/items/a_rockets.md3 and b/models/items/a_rockets.md3 differ
index 27b579027f93063f207b8fbf849e538a7ea4dff3..efdb0b2b075859d0ae67937c7dda6b8bf878f752 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index 44843b7058baf5ccd13a0e37c88694b99620f9a1..fbc6b672c39d97411a589b4165d5ef2fc0b43095 100644 (file)
@@ -1,4 +1,4 @@
-name Gak Masked
+name Gak
 species alien
 sex Male
 weight 87
index 2610d2b92db356797a22a0b52605efc304c05f41..4a35d9099e9daff55753fd47e1a2157bbaaa4f0f 100644 (file)
@@ -11,3 +11,4 @@ bone_aim2 0.2 upperarm_L
 bone_aim3 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index c997d01f36488d7771766fe38956f883b8bcc9bc..76ca617ba11dde4fba964e2babdaf156df10f5ef 100644 (file)
@@ -10,3 +10,4 @@ bone_aim1 0.4 spine4
 bone_aim2 0.35 bip01 r hand
 bone_weapon bip01 r hand
 fixbone 1
+hidden 1
index af0fa9e68477e1b05e3366e6dddb57a1f3547677..afa17824980e02ddc6be90760b998ec8bfd8d1c5 100644 (file)
@@ -54,7 +54,8 @@ set g_instagib_friendlypush 1 "allow pushing teammates with the vaporizer primar
 // ==========
 //  overkill
 // ==========
-set g_overkill 0 "internal cvar, to enable overkill, use  `exec defaultOverkill.cfg`"
+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
@@ -289,7 +294,7 @@ set g_campcheck_distance 1800
 // ==========
 set g_new_toys 0 "Mutator 'New Toys': enable extra fun guns"
 set g_new_toys_autoreplace 2 "0: never replace, 1: always auto replace guns by available new toys, 2: randomly auto replace guns by available new toys"
-set g_new_toys_use_pickupsound 1 "play the 'new toys, new toys!' roflsound when picking up a new toys weapon"
+set g_new_toys_use_pickupsound 0 "play the 'new toys, new toys!' roflsound when picking up a new toys weapon"
 
 
 // =======
@@ -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"
@@ -376,6 +381,13 @@ set g_buffs_flight 0 "flight buff: crouch jump to reverse your gravity!"
 set g_buffs_flight_time 60 "flight buff carry time"
 
 
+// ================
+//  grappling hook
+// ================
+set g_grappling_hook 0 "let players spawn with the grappling hook which allows them to pull themselves up"
+set g_grappling_hook_useammo 0 "use ammunition with the off-hand grappling hook"
+
+
 // ==============
 //  vampire hook
 // ==============
@@ -386,6 +398,12 @@ set g_vampirehook_health_steal "2" "give hooker this much health per damage fram
 set g_vampirehook_teamheal "1" "hooking teammates drains hooker's health"
 
 
+// =================
+//  offhand blaster
+// =================
+set g_offhand_blaster 0 "whether to enable offhand blaster"
+
+
 // ===============
 //  rocket minsta
 // ===============
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 8ae771f1cf468a9ac21ec05d4b94cdc4e2782708..61354633d517a6b9d04acc7a0ec66f0fc0ef199f 100644 (file)
@@ -1,5 +1,5 @@
 g_mod_physics Xonotic
-// current Xonotic physics
+// Xonotic 0.7 physics
 
 sv_gravity 800
 sv_maxspeed 360
index bfea08b5f92df070fbcc59269b5ec65ed7bb3162..d09b2c5ccffa730255a6545d0f411a11adc05fc5 100644 (file)
@@ -29,6 +29,10 @@ ifndef ZIP
     endif
 endif
 
+# Set to empty string to temporarily enable warnings when debugging
+QCCFLAGS_WERROR ?= \
+       -Werror
+
 # We eventually need to get rid of these
 QCCFLAGS_WTFS ?= \
        -Wno-field-redeclared
@@ -48,7 +52,8 @@ QCCFLAGS ?= \
        -std=gmqcc \
        -Ooverlap-locals \
        -O3 \
-       -Werror -Wall \
+       $(QCCFLAGS_WERROR) \
+       -Wall \
        $(QCCFLAGS_WTFS) \
        -flno -futf8 -fno-bail-on-werror \
        -frelaxed-switch -freturn-assignments \
index 240e07a4aed707f674c447d01bd2239a65af117c..ab9184b9b9efccf44caaaa393a6bace1bf0f6e8e 100644 (file)
@@ -6,10 +6,10 @@
 #include <client/mapvoting.qc>
 #include <client/miscfunctions.qc>
 #include <client/player_skeleton.qc>
+#include <client/resources.qc>
 #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..971cc01de6afaf6e3a002942cfac832a15b9d165 100644 (file)
@@ -6,10 +6,10 @@
 #include <client/mapvoting.qh>
 #include <client/miscfunctions.qh>
 #include <client/player_skeleton.qh>
+#include <client/resources.qh>
 #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..0195db43a432e17e1e472155995451a8f703160d 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>
@@ -129,6 +129,9 @@ void Announcer_Gamestart()
 
 void Announcer_Time()
 {
+       if(intermission)
+               return;
+
        float timeleft;
        if(warmup_stage)
        {
index 6d3fb626771723a0d86af77ab2e775f7a24364f7..8eb3ca1dcb1a623111fc2a7a095d31ff946ebdc0 100644 (file)
@@ -103,6 +103,7 @@ float autocvar_con_chatsize;
 float autocvar_con_notify;
 float autocvar_con_notifysize;
 string autocvar_crosshair;
+string autocvar_crosshair_2d = "54";
 float autocvar_crosshair_alpha;
 string autocvar_crosshair_color;
 int autocvar_crosshair_color_special;
@@ -343,7 +344,7 @@ float autocvar_hud_panel_weapons_complainbubble_padding;
 float autocvar_hud_panel_weapons_complainbubble_time;
 int autocvar_hud_panel_weapons_label;
 float autocvar_hud_panel_weapons_label_scale = 0.5;
-bool autocvar_hud_panel_weapons_onlyowned;
+int autocvar_hud_panel_weapons_onlyowned;
 float autocvar_hud_panel_weapons_noncurrent_alpha = 1;
 float autocvar_hud_panel_weapons_noncurrent_scale = 1;
 float autocvar_hud_panel_weapons_selection_radius = 0;
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..1a6a9f88419d8cccc098c2fb78f6e925dc9bf5b7 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);
@@ -331,7 +325,8 @@ void LocalCommand_hud(int request, int argc)
 
                                case "clickradar":
                                {
-                                       HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
+                                       if(!isdemo())
+                                               HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
                                        return;
                                }
                        }
@@ -418,7 +413,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 +422,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..68d1e6bffabb1c327a75d5068b91a7cfd072683e 100644 (file)
@@ -86,8 +86,8 @@ const float BORDER_MULTIPLIER = 4;
 float scoreboard_bottom;
 int weapon_accuracy[Weapons_MAX];
 
-int complain_weapon;
-float complain_weapon_type;
+entity complain_weapon;
+int complain_weapon_type;
 float complain_weapon_time;
 
 PlayerScoreField ps_primary, ps_secondary;
@@ -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..bd94520d4e4292972e51277c0f27d6fc7fd7cd75 100644 (file)
@@ -6,6 +6,7 @@
 #include <common/ent_cs.qh>
 #include <common/mapinfo.qh>
 #include <client/mapvoting.qh>
+#include <client/resources.qh>
 #include <client/teamradar.qh>
 #include <common/mutators/mutator/waypoints/all.qh>
 
@@ -214,9 +215,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)
                {
@@ -354,7 +353,7 @@ void HUD_Radar()
 
        IL_EACH(g_radaricons, it.teamradar_icon, {
                if ( hud_panel_radar_mouse )
-               if ( it.health >= 0 )
+               if ( GetResourceAmount(it, RESOURCE_HEALTH) >= 0 )
                if ( it.team == myteam + 1 || gametype == MAPINFO_TYPE_RACE || !teamplay )
                {
                        vector coord = teamradar_texcoord_to_2dcoord(teamradar_3dcoord_to_texcoord(it.origin));
index 6db88c68b39ee50fce1f8acce9c778465a3223ae..d2fbc8f6b25ce5bb6a5afe05bb2637dfe53bd08c 100644 (file)
@@ -1,2 +1,4 @@
 #pragma once
 #include "../panel.qh"
+
+void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
index 0360eb07e639795ae1b23709617ef05ca2e28caf..91d9f6f70d9757635c97ffe4136d504e325925dd 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,68 @@ 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 ^7field1 field2 ..."));
-       LOG_INFO(_("The following field names are recognized (case insensitive):"));
+       LOG_INFO("^2scoreboard_columns_set ^3default");
+       LOG_INFO(_("^2scoreboard_columns_set ^3field1 field2 ..."));
+       LOG_INFO(_("^2scoreboard_columns_set ^7without arguments reads the arguments from the cvar scoreboard_columns"));
+       LOG_INFO(_("  ^5Note: ^7scoreboard_columns_set without arguments is executed on every map start"));
+       LOG_INFO(_("^2scoreboard_columns_set ^3expand_default ^7loads default layout and expands it into the cvar scoreboard_columns so you can edit it"));
        LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields."));
+       LOG_INFO(_("The following field names are recognized (case insensitive):"));
        LOG_INFO("");
 
-       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 +362,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" \
@@ -401,12 +404,15 @@ void Cmd_Scoreboard_SetFields(int argc)
 
        if(argc == 3)
        {
-               if(argv(2) == "default")
+               if(argv(2) == "default" || argv(2) == "expand_default")
+               {
+                       if(argv(2) == "expand_default")
+                               cvar_set("scoreboard_columns", SCOREBOARD_DEFAULT_COLUMNS);
                        argc = tokenizebyseparator(strcat("0 1 ", SCOREBOARD_DEFAULT_COLUMNS), " ");
+               }
                else if(argv(2) == "all")
                {
-                       string s;
-                       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 +433,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 +451,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 +467,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 +542,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 +550,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 +558,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 +680,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);
 
@@ -1140,6 +1154,11 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                int weapon_stats = weapon_accuracy[i - WEP_FIRST];
 
                WepSet set = it.m_wepset;
+               if(it.spawnflags & WEP_TYPE_OTHER)
+               {
+                       ++nHidden;
+                       continue;
+               }
                if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
                {
                        if (((it.spawnflags & WEP_FLAG_HIDDEN) || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED)))
@@ -1220,6 +1239,8 @@ vector Scoreboard_AccuracyStats_Draw(vector pos, vector rgb, vector bg_size)
                WepSet set = it.m_wepset;
                if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
                        continue;
+               if (it.spawnflags & WEP_TYPE_OTHER)
+                       continue;
 
                float weapon_alpha;
                if (weapon_stats >= 0)
@@ -1467,9 +1488,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..5d75c7dd2a4182fe19d9a4ec67d2940a3d877174 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;
@@ -113,7 +108,14 @@ void HUD_Weapons()
        }
 
        if(!autocvar_hud_panel_weapons_complainbubble || autocvar__hud_configure || time - complain_weapon_time >= when + fadetime)
-               complain_weapon = 0;
+               complain_weapon = NULL;
+
+       entity wepent = viewmodels[0]; // TODO: unhardcode
+
+       if (wepent.switchweapon == WEP_Null)
+               panel_switchweapon = NULL;
+       else if (!panel_switchweapon)
+               panel_switchweapon = wepent.switchweapon;
 
        if(autocvar__hud_configure)
        {
@@ -164,10 +166,18 @@ void HUD_Weapons()
 
                // do we own this weapon?
                weapon_count = 0;
-               for(i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
-                       if((weapons_stat & WepSet_FromWeapon(weaponorder[i])) || (weaponorder[i].m_id == complain_weapon))
-                               ++weapon_count;
-
+               if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
+               {
+                       for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+                               if (weaponorder[i] == panel_switchweapon || weaponorder[i] == complain_weapon)
+                                       ++weapon_count;
+               }
+               else
+               {
+                       for (i = 0; i <= WEP_LAST-WEP_FIRST; ++i)
+                               if ((weapons_stat & WepSet_FromWeapon(weaponorder[i])) || weaponorder[i] == complain_weapon)
+                                       ++weapon_count;
+               }
 
                // might as well commit suicide now, no reason to live ;)
                if (weapon_count == 0)
@@ -378,13 +388,6 @@ void HUD_Weapons()
                switch_speed = frametime * autocvar_hud_panel_weapons_selection_speed;
        vector radius_size = weapon_size * (autocvar_hud_panel_weapons_selection_radius + 1);
 
-       entity wepent = viewmodels[0]; // TODO: unhardcode
-
-       if(wepent.switchweapon == WEP_Null)
-               panel_switchweapon = NULL;
-       else if(!panel_switchweapon)
-               panel_switchweapon = wepent.switchweapon;
-
        // draw background behind currently selected weapon
        // do it earlier to make sure bg is drawn behind every weapon icons while it's moving
        if(panel_switchweapon)
@@ -400,14 +403,22 @@ void HUD_Weapons()
                if(!it || weapon_id < 0) { continue; }
 
                // skip this weapon if we don't own it (and onlyowned is enabled)-- or if weapons_complainbubble is showing for this weapon
-               if(autocvar_hud_panel_weapons_onlyowned)
+               if (autocvar_hud_panel_weapons_onlyowned)
                {
-                       if (!((weapons_stat & WepSet_FromWeapon(it)) || (it.m_id == complain_weapon)))
-                               continue;
+                       if (autocvar_hud_panel_weapons_onlyowned >= 2) // only current
+                       {
+                               if (!(it == panel_switchweapon || it == complain_weapon))
+                                       continue;
+                       }
+                       else
+                       {
+                               if (!((weapons_stat & WepSet_FromWeapon(it)) || (it == complain_weapon)))
+                                       continue;
+                       }
                }
                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;
                }
 
@@ -523,7 +534,7 @@ void HUD_Weapons()
                }
 
                // draw the complain message
-               if(it.m_id == complain_weapon)
+               if(it == complain_weapon)
                {
                        if(fadetime)
                                a = ((complain_weapon_time + when > time) ? 1 : bound(0, (complain_weapon_time + when + fadetime - time) / fadetime, 1));
index 609e03775ece1454ceaab0db07e21c7d50ad47f9..218df18a474fc47746e8a928f77e164ecece995f 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"));
@@ -134,6 +134,8 @@ void CSQC_Init()
        registercvar("cl_jumpspeedcap_min", "");
        registercvar("cl_jumpspeedcap_max", "");
 
+       registercvar("cl_shootfromfixedorigin", "");
+
        registercvar("cl_multijump", "1");
 
        registercvar("cl_spawn_near_teammate", "1");
@@ -341,7 +343,6 @@ void Playerchecker_Think(entity this)
        this.nextthink = time + 0.2;
 }
 
-void TrueAim_Init();
 void PostInit()
 {
        entity playerchecker = new_pure(playerchecker);
@@ -387,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) {
@@ -553,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
@@ -573,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)
@@ -697,10 +692,7 @@ void Spawn_PreDraw(entity this)
 NET_HANDLE(ENT_CLIENT_SPAWNPOINT, bool is_new)
 {
        float teamnum = (ReadByte() - 1);
-       vector spn_origin;
-       spn_origin.x = ReadCoord();
-       spn_origin.y = ReadCoord();
-       spn_origin.z = ReadCoord();
+       vector spn_origin = ReadVector();
 
        this.team = (teamnum + 1);
 
@@ -757,9 +749,7 @@ NET_HANDLE(ENT_CLIENT_SPAWNEVENT, bool is_new)
 
        if(entnum)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
 
                if(is_new)
                {
@@ -954,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);
@@ -962,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;
@@ -990,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;
@@ -1054,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;
 
@@ -1090,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:
@@ -1110,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:
@@ -1126,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:
@@ -1158,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;
@@ -1183,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;
 }
@@ -1252,7 +1216,8 @@ NET_HANDLE(TE_CSQC_PINGPLREPORT, bool isNew)
 
 NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
 {
-       complain_weapon = ReadByte();
+       int weapon_id = ReadByte();
+       complain_weapon = Weapons_from(weapon_id);
        complain_weapon_type = ReadByte();
        return = true;
 
@@ -1261,9 +1226,9 @@ NET_HANDLE(TE_CSQC_WEAPONCOMPLAIN, bool isNew)
 
        switch(complain_weapon_type)
        {
-               case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, complain_weapon); break;
-               case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, complain_weapon); break;
-               default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, complain_weapon); break;
+               case 0: Local_Notification(MSG_MULTI, ITEM_WEAPON_NOAMMO, weapon_id); break;
+               case 1: Local_Notification(MSG_MULTI, ITEM_WEAPON_DONTHAVE, weapon_id); break;
+               default: Local_Notification(MSG_MULTI, ITEM_WEAPON_UNAVAILABLE, weapon_id); break;
        }
 }
 
index a2f4d18bba97e2ef4070fe83ac362d83dd462404..69c3fa3d2b300eb4f54f6fd2a9bf4b8e68db62bf 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];
 
@@ -105,7 +114,6 @@ const int MAX_SPECTATORS = 7;
 int spectatorlist[MAX_SPECTATORS];
 
 int framecount;
-.float health;
 
 float GetSpeedUnitFactor(int speed_unit);
 string GetSpeedUnit(int speed_unit);
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 f23a3976b55c6fcaba36a0ec2d5301f80ab0ba8f..0143d1a0134ac1720a49273a0bb87b408156ab54 100644 (file)
@@ -34,7 +34,7 @@ float PreviewExists(string name);
 vector Rotate(vector v, float a);
 
 
-#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : ((s).health <= 0))
+#define IS_DEAD(s) (((s).classname == "csqcmodel") ? (s).csqcmodel_isdead : (GetResourceAmount((s), RESOURCE_HEALTH) <= 0))
 
 
 // decolorizes and team colors the player name when needed
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;
diff --git a/qcsrc/client/resources.qc b/qcsrc/client/resources.qc
new file mode 100644 (file)
index 0000000..285ebad
--- /dev/null
@@ -0,0 +1,87 @@
+#include "resources.qh"
+#include <common/items/item/ammo.qh>
+
+/// \file
+/// \brief Source file that contains implementation of the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+float GetResourceAmount(entity e, int resource_type)
+{
+       .float resource_field = GetResourceField(resource_type);
+       return e.(resource_field);
+}
+
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount)
+{
+       .float resource_field = GetResourceField(resource_type);
+       if (e.(resource_field) != amount)
+       {
+               e.(resource_field) = amount;
+               return true;
+       }
+       return false;
+}
+
+void SetResourceAmount(entity e, int resource_type, float amount)
+{
+       SetResourceAmountExplicit(e, resource_type, amount);
+}
+
+void TakeResource(entity receiver, int resource_type, float amount)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       SetResourceAmount(receiver, resource_type,
+               GetResourceAmount(receiver, resource_type) - amount);
+}
+
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit)
+{
+       if (amount == 0)
+       {
+               return;
+       }
+       float current_amount = GetResourceAmount(receiver, resource_type);
+       if (current_amount - amount < limit)
+       {
+               amount = limit + current_amount;
+       }
+       TakeResource(receiver, resource_type, amount);
+}
+
+int GetResourceType(.float resource_field)
+{
+       switch (resource_field)
+       {
+               case health: { return RESOURCE_HEALTH; }
+               case armorvalue: { return RESOURCE_ARMOR; }
+               case ammo_shells: { return RESOURCE_SHELLS; }
+               case ammo_nails: { return RESOURCE_BULLETS; }
+               case ammo_rockets: { return RESOURCE_ROCKETS; }
+               case ammo_cells: { return RESOURCE_CELLS; }
+               case ammo_plasma: { return RESOURCE_PLASMA; }
+               case ammo_fuel: { return RESOURCE_FUEL; }
+       }
+       error("GetResourceType: Invalid field.");
+       return 0;
+}
+
+.float GetResourceField(int resource_type)
+{
+       switch (resource_type)
+       {
+               case RESOURCE_HEALTH: { return health; }
+               case RESOURCE_ARMOR: { return armorvalue; }
+               case RESOURCE_SHELLS: { return ammo_shells; }
+               case RESOURCE_BULLETS: { return ammo_nails; }
+               case RESOURCE_ROCKETS: { return ammo_rockets; }
+               case RESOURCE_CELLS: { return ammo_cells; }
+               case RESOURCE_PLASMA: { return ammo_plasma; }
+               case RESOURCE_FUEL: { return ammo_fuel; }
+       }
+       error("GetResourceField: Invalid resource type.");
+       return health;
+}
diff --git a/qcsrc/client/resources.qh b/qcsrc/client/resources.qh
new file mode 100644 (file)
index 0000000..3aaa8aa
--- /dev/null
@@ -0,0 +1,61 @@
+#pragma once
+
+/// \file
+/// \brief Header file that describes the resource system.
+/// \copyright GNU GPLv2 or any later version.
+
+#include <common/resources.qh>
+
+// ============================ Public API ====================================
+
+/// \brief Returns the current amount of resource the given entity has.
+/// \param[in] e Entity to check.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \return Current amount of resource the given entity has.
+float GetResourceAmount(entity e, int resource_type);
+
+/// \brief Sets the resource amount of an entity without calling any hooks.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return Boolean for whether the ammo amount was changed
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount);
+
+/// \brief Sets the current amount of resource the given entity will have.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return No return.
+void SetResourceAmount(entity e, int resource_type, float amount);
+
+/// \brief Takes an entity some resource.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \return No return.
+void TakeResource(entity receiver, int resource_type, float amount);
+
+/// \brief Takes an entity some resource but not less than a limit.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \param[in] limit Limit of resources to take.
+/// \return No return.
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit);
+
+// ===================== Legacy and/or internal API ===========================
+
+/// \brief Converts an entity field to resource type.
+/// \param[in] resource_field Entity field to convert.
+/// \return Resource type (a RESOURCE_* constant).
+int GetResourceType(.float resource_field);
+
+/// \brief Converts resource type (a RESOURCE_* constant) to entity field.
+/// \param[in] resource_type Type of the resource.
+/// \return Entity field for that resource.
+.float GetResourceField(int resource_type);
+
+/// \brief Legacy fields for the resources. To be removed.
+.float health;
+.float armorvalue;
index 8a7d225bff7bdc319260e5e0648a2aaff9b7aa08..7c1ece5a3dc395c0afea7f4f2bfdfd8ab8519d4f 100644 (file)
@@ -2,6 +2,7 @@
 
 #include "autocvars.qh"
 #include "miscfunctions.qh"
+#include "resources.qh"
 #include "hud/_mod.qh"
 
 #include <common/ent_cs.qh>
@@ -157,10 +158,10 @@ void Draw_ShowNames(entity this)
                                        this.healthvalue / autocvar_hud_panel_healtharmor_maxhealth, false, 1, '1 0 0', a,
                                        DRAWFLAG_NORMAL);
                        }
-                       if (this.armorvalue > 0)
+                       if (GetResourceAmount(this, RESOURCE_ARMOR) > 0)
                        {
                                HUD_Panel_DrawProgressBar(pos + eX * 0.5 * mySize.x, sz, "nametag_statusbar",
-                                       this.armorvalue / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
+                                       GetResourceAmount(this, RESOURCE_ARMOR) / autocvar_hud_panel_healtharmor_maxarmor, false, 0, '0 1 0', a,
                                        DRAWFLAG_NORMAL);
                        }
                }
@@ -193,13 +194,13 @@ void Draw_ShowNames_All()
                if (entcs.m_entcs_private)
                {
                        it.healthvalue = entcs.healthvalue;
-                       it.armorvalue = entcs.armorvalue;
+                       SetResourceAmountExplicit(it, RESOURCE_ARMOR, GetResourceAmount(entcs, RESOURCE_ARMOR));
                        it.sameteam = true;
                }
                else
                {
                        it.healthvalue = 0;
-                       it.armorvalue = 0;
+                       SetResourceAmountExplicit(it, RESOURCE_ARMOR, 0);
                        it.sameteam = false;
                }
                bool dead = entcs_IsDead(i) || entcs_IsSpectating(i);
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 7f1654de0660b3d20890730feb19f0417c3252d6..c5f1c2fb4b1468b1b50bf997f366987ce675c83f 100644 (file)
@@ -187,7 +187,7 @@ void teamradar_loadcvars()
        hud_panel_radar_maximized_zoommode = autocvar_hud_panel_radar_maximized_zoommode;
 
        // others default to 0
-       // match this to defaultXonotic.cfg!
+       // match this to default hud cfg file!
        if(!hud_panel_radar_scale) hud_panel_radar_scale = 4096;
        if(!hud_panel_radar_foreground_alpha) hud_panel_radar_foreground_alpha = 0.8 * panel_fg_alpha;
        if(!hud_panel_radar_size.x) hud_panel_radar_size.x = 128;
@@ -208,17 +208,13 @@ NET_HANDLE(ENT_CLIENT_RADARLINK, bool isnew)
 
        if(sendflags & 1)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
        }
 
        if(sendflags & 2)
        {
-               this.velocity_x = ReadCoord();
-               this.velocity_y = ReadCoord();
-               this.velocity_z = ReadCoord();
+               this.velocity = ReadVector();
        }
 
        if(sendflags & 4)
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 6a294d5ad5d35322c4576e063a844bcc0da16a15..2538299475c3b43980a56483ca0995470d5fff97 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);
@@ -460,9 +491,8 @@ vector GetCurrentFov(float fov)
        if(zoomfactor < 1 || zoomfactor > 30)
                zoomfactor = 2.5;
        zoomspeed = autocvar_cl_zoomspeed;
-       if(zoomspeed >= 0)
-       if(zoomspeed < 0.5 || zoomspeed > 16)
-                       zoomspeed = 3.5;
+       if (zoomspeed >= 0 && (zoomspeed < 0.5 || zoomspeed > 16))
+               zoomspeed = 3.5;
 
        zoomdir = button_zoom;
 
@@ -471,9 +501,14 @@ vector GetCurrentFov(float fov)
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        entity wepent = viewmodels[slot];
-                       if(wepent.switchweapon == wepent.activeweapon)
-                       if((wepent.activeweapon == WEP_VORTEX && !WEP_CVAR(vortex, secondary)) || (wepent.activeweapon == WEP_RIFLE && !WEP_CVAR(rifle, secondary))) // do NOT use switchweapon here
-                               zoomdir += button_attack2;
+                       if(wepent.switchweapon != wepent.activeweapon)
+                               continue;
+                       Weapon wep = wepent.activeweapon;
+                       if(wep != WEP_Null && wep.wr_zoomdir)
+                       {
+                               bool do_zoom = wep.wr_zoomdir(wep); // TODO: merge this with wr_zoom?
+                               zoomdir += do_zoom;
+                       }
                }
        }
        if(spectatee_status > 0 || isdemo())
@@ -490,7 +525,11 @@ vector GetCurrentFov(float fov)
 
        if(zoomdir) { zoomin_effect = 0; }
 
-       if(camera_active)
+       if (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2)
+       {
+               current_viewzoom = 1;
+       }
+       else if (camera_active)
        {
                current_viewzoom = min(1, current_viewzoom + drawframetime);
        }
@@ -534,10 +573,10 @@ vector GetCurrentFov(float fov)
 
        if(autocvar_cl_velocityzoom_enabled && autocvar_cl_velocityzoom_type) // _type = 0 disables velocity zoom too
        {
-               if(intermission) { curspeed = 0; }
+               if (intermission || (spectatee_status > 0 && STAT(CAMERA_SPECTATOR) == 2))
+                       curspeed = 0;
                else
                {
-
                        makevectors(view_angles);
                        v = pmove_vel;
                        if(csqcplayer)
@@ -664,6 +703,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;
@@ -732,8 +772,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;
@@ -997,6 +1035,8 @@ void HUD_Crosshair(entity this)
                string wcross_style;
                float wcross_alpha, wcross_resolution;
                wcross_style = autocvar_crosshair;
+               if (csqcplayer.viewloc && (csqcplayer.viewloc.spawnflags & VIEWLOC_FREEAIM) && autocvar_crosshair_2d != "")
+                       wcross_style = autocvar_crosshair_2d;
                if (wcross_style == "0")
                        return;
                wcross_resolution = autocvar_crosshair_size;
@@ -1184,30 +1224,29 @@ void HUD_Crosshair(entity this)
 
                                ring_scale = autocvar_crosshair_ring_size;
 
-                               float weapon_clipload, weapon_clipsize;
-                               weapon_clipload = STAT(WEAPON_CLIPLOAD);
-                               weapon_clipsize = STAT(WEAPON_CLIPSIZE);
+                               entity wepent = viewmodels[0]; // TODO: unhardcode
 
-                               float vortex_charge, vortex_chargepool;
-                               vortex_charge = STAT(VORTEX_CHARGE);
-                               vortex_chargepool = STAT(VORTEX_CHARGEPOOL);
+                               int weapon_clipload = wepent.clip_load;
+                               int weapon_clipsize = wepent.clip_size;
 
-                               float arc_heat = STAT(ARC_HEAT);
+                               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 = vortex_charge;
-
-                               entity wepent = viewmodels[0]; // TODO: unhardcode
+                                       vortex_charge_movingavg = vcharge;
 
                                // handle the values
-                               if (autocvar_crosshair_ring && wepent.activeweapon == WEP_VORTEX && vortex_charge && autocvar_crosshair_ring_vortex) // ring around crosshair representing velocity-dependent damage for the vortex
+                               if (autocvar_crosshair_ring && wepent.activeweapon == WEP_VORTEX && vcharge && autocvar_crosshair_ring_vortex) // ring around crosshair representing velocity-dependent damage for the vortex
                                {
-                                       if (vortex_chargepool || use_vortex_chargepool) {
+                                       if (vchargepool || use_vortex_chargepool) {
                                                use_vortex_chargepool = 1;
-                                               ring_inner_value = vortex_chargepool;
+                                               ring_inner_value = vchargepool;
                                        } else {
-                                               vortex_charge_movingavg = (1 - autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate) * vortex_charge_movingavg + autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate * vortex_charge;
-                                               ring_inner_value = bound(0, autocvar_crosshair_ring_vortex_currentcharge_scale * (vortex_charge - vortex_charge_movingavg), 1);
+                                               vortex_charge_movingavg = (1 - autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate) * vortex_charge_movingavg + autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate * vcharge;
+                                               ring_inner_value = bound(0, autocvar_crosshair_ring_vortex_currentcharge_scale * (vcharge - vortex_charge_movingavg), 1);
                                        }
 
                                        ring_inner_alpha = autocvar_crosshair_ring_vortex_inner_alpha;
@@ -1215,21 +1254,41 @@ void HUD_Crosshair(entity this)
                                        ring_inner_image = "gfx/crosshair_ring_inner.tga";
 
                                        // draw the outer ring to show the current charge of the weapon
-                                       ring_value = vortex_charge;
+                                       ring_value = vcharge;
+                                       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_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, STAT(LAYED_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.
+                                       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.
                                        ring_alpha = autocvar_crosshair_ring_minelayer_alpha;
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring.tga";
                                }
-                               else if (wepent.activeweapon == WEP_HAGAR && STAT(HAGAR_LOAD) && autocvar_crosshair_ring_hagar)
+                               else if (wepent.activeweapon == WEP_HAGAR && wepent.hagar_load && autocvar_crosshair_ring_hagar)
                                {
-                                       ring_value = bound(0, STAT(HAGAR_LOAD) / WEP_CVAR_SEC(hagar, load_max), 1);
+                                       ring_value = bound(0, wepent.hagar_load / WEP_CVAR_SEC(hagar, load_max), 1);
                                        ring_alpha = autocvar_crosshair_ring_hagar_alpha;
                                        ring_rgb = wcross_color;
                                        ring_image = "gfx/crosshair_ring.tga";
@@ -1342,12 +1401,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;
@@ -1389,8 +1444,8 @@ void SpecialCommand()
                vector slot = specialcommand_slots[j];
                if(slot.y)
                        slot.y += SPECIALCOMMAND_SPEED * frametime;
-               if(slot.z)
-                       slot.z = sin(SPECIALCOMMAND_TURNSPEED * M_PI * time);
+               //if(slot.z)
+                       //slot.z = sin(SPECIALCOMMAND_TURNSPEED * M_PI * time);
                if(slot.y >= vid_conheight)
                        slot = '0 0 0';
 
@@ -1400,7 +1455,7 @@ void SpecialCommand()
                        {
                                slot.x = bound(0, (random() * vid_conwidth + 1), vid_conwidth);
                                slot.y = 1; // start it off 0 so we can use it
-                               slot.z = random();
+                               slot.z = floor(random() * Weapons_MAX);
                                sc_spawntime = time + bound(0.4, random(), 0.75); // prevent spawning another one for this amount of time!
                                vector newcolor = randomvec() * 2;
                                newcolor.x = bound(0.4, newcolor.x, 1);
@@ -1414,7 +1469,11 @@ void SpecialCommand()
                        vector splash_size = '0 0 0';
                        splash_size.x = max(vid_conwidth, vid_conheight) * SPECIALCOMMAND_SIZE;
                        splash_size.y = max(vid_conwidth, vid_conheight) * SPECIALCOMMAND_SIZE;
-                       drawpic(vec2(slot), "gfx/smile", vec2(splash_size), specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
+                       entity wep = Weapons_from(slot.z);
+                       if(wep == WEP_Null)
+                               drawpic(vec2(slot), "gfx/smile", vec2(splash_size), specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
+                       else
+                               drawpic_skin(vec2(slot), wep.model2, vec2(splash_size), specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
                        //drawrotpic(vec2(slot), slot.z, "gfx/smile", vec2(splash_size), vec2(splash_size) / 2, specialcommand_colors[j], 0.95, DRAWFLAG_NORMAL);
                }
 
@@ -1504,12 +1563,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);
@@ -1858,6 +1914,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
@@ -2003,7 +2060,7 @@ void CSQC_UpdateView(entity this, float w, float h)
 
        IL_EACH(g_drawables, it.draw, it.draw(it));
 
-       addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS);
+       addentities(MASK_NORMAL | MASK_ENGINE | MASK_ENGINEVIEWMODELS); // TODO: .health is used in cl_deathfade (a feature we have turned off currently)
        renderscene();
 
        // now switch to 2D drawing mode by calling a 2D drawing function
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 a0d66d7..0000000
+++ /dev/null
@@ -1,238 +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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               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_x = ReadCoord();
-                       this.mins_y = ReadCoord();
-                       this.mins_z = ReadCoord();
-                       this.maxs_x = ReadCoord();
-                       this.maxs_y = ReadCoord();
-                       this.maxs_z = ReadCoord();
-               }
-               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_x = ReadCoord();
-                       this.movedir_y = ReadCoord();
-                       this.movedir_z = ReadCoord();
-                       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 3d2d32d9af16bff4eeb0c6ca89d1e7951c71e1c5..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;
@@ -236,15 +236,11 @@ NET_HANDLE(ENT_CLIENT_PROJECTILE, bool isnew)
 
        if (f & 1)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
                if (this.count & 0x80)
                {
-                       this.velocity_x = ReadCoord();
-                       this.velocity_y = ReadCoord();
-                       this.velocity_z = ReadCoord();
+                       this.velocity = ReadVector();
                        if (f & 0x10)
                                this.gravity = ReadCoord();
                        else
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 125ef6bf36c99bf5d25a281e88c2053113109a91..7c5a218b21f15e34ba6ba43ee0d13b4a2b0a801f 100644 (file)
                CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, glowmod_x, 254, -1, 254) \
                CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, glowmod_y, 254, -1, 254) \
                CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, glowmod_z, 254, -1, 254) \
-               CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_x, 254, -1, 254) \
-               CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_y, 254, -1, 254) \
-               CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_z, 254, -1, 254) \
        CSQCMODEL_ENDIF \
+       CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_x, 16, 0, 255) \
+       CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_y, 16, 0, 255) \
+       CSQCMODEL_PROPERTY_SCALED(BIT(8), float, ReadByte, WriteByte, colormod_z, 16, 0, 255) \
        CSQCMODEL_IF(isplayer) \
                CSQCMODEL_PROPERTY(BIT(7), int, ReadByte, WriteByte, anim_state) \
                CSQCMODEL_PROPERTY(BIT(7), float, ReadApproxPastTime, WriteApproxPastTime, anim_time) \
@@ -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 0466c230ab3b709f40343ce3d2bba3c2c3442894..beb8e3e912221911705429fe210042762ed51cb0 100644 (file)
@@ -11,8 +11,6 @@ REGISTRY_CHECK(Deathtypes)
 .entity death_msgmurder;
 .string death_msgextra;
 
-int dt_identity(int i) { return i; }
-
 #define REGISTER_DEATHTYPE(id, msg_death, msg_death_by, extra) \
     REGISTER(Deathtypes, DEATH, id, m_id, new_pure(deathtype)) { \
         this.m_id += DT_FIRST; \
@@ -27,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 0200883b8dbbc89867e6c888b7489889bb606f54..41c5d3017eada07992e8ba6ae102827da85525d4 100644 (file)
@@ -1,9 +1,20 @@
 #pragma once
 
+#ifdef CSQC
+#include <client/resources.qh>
+#endif
+
+
+// This includes some functions useful for debugging.
+// Some more bot-specific ones are in server/pathlib/debug.qc.
+// Look for other useful commands under prvm_* in console (apropos / search).
+
+
 #ifdef CSQC
 .entity tag_entity;
 #endif
 
+
 #ifdef GAMEQC
 .bool debug;
 .int sv_entnum;
@@ -16,9 +27,7 @@ REGISTER_NET_TEMP(net_debug)
                Net_Accept(net_debug);
                this.sv_entnum = ReadShort();
                if (ReadByte()) make_pure(this);
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
                this.debug = true;  // identify server entities by this
                this.classname = strzone(ReadString());
@@ -40,13 +49,14 @@ REGISTER_NET_TEMP(net_debug)
                        o = (this.absmin + this.absmax) / 2;
                if (this.tag_entity)
                        o += this.tag_entity.origin;
-               WriteCoord(channel, o.x); WriteCoord(channel, o.y); WriteCoord(channel, o.z);
+               WriteVector(channel, o);
                WriteString(channel, this.classname);
                WriteString(channel, this.sourceLoc);
                return true;
        }
 #endif
 
+
 #if ENABLE_DEBUGDRAW
 #ifdef GAMEQC
 /**
@@ -153,6 +163,7 @@ bool autocvar_debugdraw;
        }
 #endif
 
+
 #ifdef SVQC
        COMMON_COMMAND(debugdraw_sv, "Dump all server entities")
        {
@@ -185,6 +196,7 @@ bool autocvar_debugdraw;
 #endif
 #endif
 
+
 GENERIC_COMMAND(bufstr_get, "Examine a string buffer object")
 {
        switch (request)
@@ -207,6 +219,7 @@ GENERIC_COMMAND(bufstr_get, "Examine a string buffer object")
        }
 }
 
+
 GENERIC_COMMAND(version, "Print the current version")
 {
        switch (request)
@@ -225,6 +238,7 @@ GENERIC_COMMAND(version, "Print the current version")
        }
 }
 
+
 #ifdef CSQC
 void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
 #endif
@@ -259,6 +273,7 @@ GENERIC_COMMAND(cvar_localchanges, "Print locally changed cvars")
        }
 }
 
+
 #if ENABLE_DEBUGTRACE
 REGISTER_STAT(TRACE_ENT, int)
 #ifdef SVQC
@@ -317,6 +332,7 @@ STATIC_INIT(TRACE_ENT)
 #endif
 #endif
 
+
 GENERIC_COMMAND(find, "Search through entities for matching classname")
 {
        switch (request)
@@ -347,6 +363,7 @@ GENERIC_COMMAND(find, "Search through entities for matching classname")
        }
 }
 
+
 GENERIC_COMMAND(findat, "Search through entities for matching origin")
 {
        switch (request)
@@ -367,3 +384,92 @@ GENERIC_COMMAND(findat, "Search through entities for matching origin")
                }
        }
 }
+
+
+// debug_test() allows drawing text from server on the client anywhere in world coordinates.
+
+#ifdef GAMEQC
+REGISTER_NET_TEMP(debug_text_3d);
+#endif
+
+#ifdef CSQC
+
+CLASS(DebugText3d, Object)
+       // reusing existing fields
+       ATTRIB(DebugText3d, origin, vector);
+       ATTRIB(DebugText3d, message, string); // the text (i wanted to use the .text field but then this whole macro-based-inheritance thing shat itself)
+       ATTRIB(DebugText3d, health, float); // text alignment (recycled field)
+       ATTRIB(DebugText3d, hit_time, float); // when it was created
+       ATTRIB(DebugText3d, fade_rate, float); // how fast is should disappear
+       ATTRIB(DebugText3d, velocity, vector);
+
+       CONSTRUCTOR(DebugText3d, vector pos, string msg, float align, float fade_rate_, vector vel) {
+               CONSTRUCT(DebugText3d);
+               this.origin = pos;
+               this.message = strzone(msg);
+               SetResourceAmount(this, RESOURCE_HEALTH, align);
+               this.hit_time = time;
+               this.fade_rate = fade_rate_;
+               this.velocity = vel;
+               IL_PUSH(g_drawables_2d, this);
+       }
+
+       DESTRUCTOR(DebugText3d) {
+               strfree(this.message);
+       }
+
+       void DebugText3d_draw2d(DebugText3d this) {
+               float since_created = time - this.hit_time;
+               float alpha_ = 1 - since_created * this.fade_rate;
+
+               if (alpha_ < 0) {
+                       delete(this);
+                       return;
+               }
+
+               int size = 8;
+               vector screen_pos = project_3d_to_2d(this.origin) + since_created * this.velocity;
+               float align = GetResourceAmount(this, RESOURCE_HEALTH);
+               if (align > 0)
+                       screen_pos.x -= stringwidth(this.message, true, size * '1 1 0') * min(1, align);
+               if (screen_pos.z < 0) return; // behind camera
+               screen_pos.z = 0;
+
+               vector rgb = '1 1 0';
+               drawcolorcodedstring2_builtin(screen_pos, this.message, size * '1 1 0', rgb, alpha_, DRAWFLAG_NORMAL);
+       }
+       ATTRIB(DebugText3d, draw2d, void(DebugText3d), DebugText3d_draw2d);
+ENDCLASS(DebugText3d)
+
+NET_HANDLE(debug_text_3d, bool is_new) {
+       vector pos = ReadVector();
+       string msg = ReadString();
+       float align = ReadFloat();
+       float duration = ReadFloat();
+       vector vel = ReadVector();
+       make_impure(NEW(DebugText3d, pos, msg, align, 1 / duration, vel));
+       return true;
+}
+
+#endif // CSQC
+
+#ifdef SVQC
+
+// can't use autocvars because they give unused warning unless the macros are expanded
+#define debug_text_3d(...) EVAL(OVERLOAD(debug_text_3d, __VA_ARGS__))
+#define debug_text_3d_2(pos, msg) debug_text_3d_3(pos, msg, cvar("debug_text_3d_default_align"))
+#define debug_text_3d_3(pos, msg, align) debug_text_3d_4(pos, msg, align, cvar("debug_text_3d_default_duration"))
+#define debug_text_3d_4(pos, msg, align, dur) debug_text_3d_5(pos, msg, align, dur, stov(cvar_string("debug_text_3d_default_velocity")))
+#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 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, vel);
+}
+
+#endif // SVQC
index af41054e31c1c40c462ce041a2cc540fa1c570be..9732be2e3bf65e82f125b176f8ed2f709d2879d6 100644 (file)
@@ -11,18 +11,11 @@ NET_HANDLE(net_effect, bool isNew)
        vector vel = '0 0 0';
        int eff_cnt = 1;
        bool eff_trail = eff.eent_eff_trail;
-       vector v;
-       v_x = ReadCoord();
-       v_y = ReadCoord();
-       v_z = ReadCoord();
+       vector v = ReadVector();
 
        bool use_vel = ReadByte();
        if(use_vel)
-       {
-               vel_x = ReadCoord();
-               vel_y = ReadCoord();
-               vel_z = ReadCoord();
-       }
+               vel = ReadVector();
 
        if(!eff_trail)
                eff_cnt = ReadByte();
@@ -44,17 +37,13 @@ bool Net_Write_Effect(entity this, entity client, int sf)
        (Effects_COUNT >= 255)
        ? WriteShort(channel, this.m_id)
        : WriteByte(channel, this.m_id);
-       WriteCoord(channel, this.eent_net_location_x);
-       WriteCoord(channel, this.eent_net_location_y);
-       WriteCoord(channel, this.eent_net_location_z);
+       WriteVector(channel, this.eent_net_location);
 
        // attempt to save a tiny bit more bandwidth by not sending velocity if it isn't set
        if(this.eent_net_velocity)
        {
                WriteByte(channel, true);
-               WriteCoord(channel, this.eent_net_velocity_x);
-               WriteCoord(channel, this.eent_net_velocity_y);
-               WriteCoord(channel, this.eent_net_velocity_z);
+               WriteVector(channel, this.eent_net_velocity);
        }
        else { WriteByte(channel, false); }
 
@@ -86,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 b023734e60ce803985088758aac6d2c690bdca40..c8273ecb2e2057c68fd357399486535b1aae4236 100644 (file)
@@ -8534,6 +8534,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 60f9633027eb2125d0278bd6abaaa2cb9ed1505a..d225b337bc70bfd46d5dd55445d2ba6668b3bd7e 100644 (file)
@@ -20,9 +20,7 @@ void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float ran
 
     WriteHeader(MSG_ALL, casings);
     WriteByte(MSG_ALL, casingtype);
-    WriteCoord(MSG_ALL, org.x);
-    WriteCoord(MSG_ALL, org.y);
-    WriteCoord(MSG_ALL, org.z);
+    WriteVector(MSG_ALL, org);
     WriteShort(MSG_ALL, compressShortVector(vel)); // actually compressed velocity
     WriteByte(MSG_ALL, ang.x * 256 / 360);
     WriteByte(MSG_ALL, ang.y * 256 / 360);
@@ -32,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)
 {
@@ -123,10 +121,7 @@ void Casing_Damage(entity this, float thisdmg, int hittype, vector org, vector t
 NET_HANDLE(casings, bool isNew)
 {
     int _state = ReadByte();
-    vector org;
-    org_x = ReadCoord();
-    org_y = ReadCoord();
-    org_z = ReadCoord();
+    vector org = ReadVector();
     vector vel = decompressShortVector(ReadShort());
     vector ang;
     ang_x = ReadByte() * 360 / 256;
index c85d66eeb6686cee70d27d77482757baf0336550..1fc64d1d259697f7fb04c691a1d83ead70ef220f 100644 (file)
@@ -6,11 +6,10 @@ REGISTER_NET_LINKED(ENT_CLIENT_DAMAGEINFO)
 
 bool Damage_DamageInfo_SendEntity(entity this, entity to, int sf)
 {
+       vector org = vec3(floor(this.origin.x), floor(this.origin.y), floor(this.origin.z));
        WriteHeader(MSG_ENTITY, ENT_CLIENT_DAMAGEINFO);
        WriteShort(MSG_ENTITY, this.projectiledeathtype);
-       WriteCoord(MSG_ENTITY, floor(this.origin.x));
-       WriteCoord(MSG_ENTITY, floor(this.origin.y));
-       WriteCoord(MSG_ENTITY, floor(this.origin.z));
+       WriteVector(MSG_ENTITY, org);
        WriteByte(MSG_ENTITY, bound(1, this.dmg, 255));
        WriteByte(MSG_ENTITY, bound(0, this.dmg_radius, 255));
        WriteByte(MSG_ENTITY, bound(1, this.dmg_edge, 255));
@@ -187,9 +186,7 @@ NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
        w_issilent = (w_deathtype & 0x8000);
        w_deathtype = (w_deathtype & 0x7FFF);
 
-       w_org.x = ReadCoord();
-       w_org.y = ReadCoord();
-       w_org.z = ReadCoord();
+       w_org = ReadVector();
 
        thedamage = ReadByte();
        rad = ReadByte();
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 874c64d5385755189e04766de0279a726cdbb70d..8c0dfd5080312fda7d1ed4d10a66a108bdd34075 100644 (file)
@@ -42,9 +42,7 @@
                        WriteByte(channel, floor(_atten * 64));
                        entcs_force_origin(from);
                        vector o = from.origin + 0.5 * (from.mins + from.maxs);
-                       WriteCoord(channel, o.x);
-                       WriteCoord(channel, o.y);
-                       WriteCoord(channel, o.z);
+                       WriteVector(channel, o);
                }
 
                /**
@@ -79,9 +77,7 @@
                        WriteByte(channel, floor(_atten * 64));
                        entcs_force_origin(from);
                        vector o = from.origin + 0.5 * (from.mins + from.maxs);
-                       WriteCoord(channel, o.x);
-                       WriteCoord(channel, o.y);
-                       WriteCoord(channel, o.z);
+                       WriteVector(channel, o);
                }
        #endif
 
                        int chan = ReadSByte();
                        float vol = ReadByte() / 255;
                        float atten = ReadByte() / 64;
-                       vector o;
-                       o.x = ReadCoord();
-                       o.y = ReadCoord();
-                       o.z = ReadCoord();
+                       vector o = ReadVector();
                        // TODO: is this really what we want to be doing? Footsteps that follow the player at head height?
                        if (who == player_currententnum) e = findfloat(NULL, entnum, who);  // play at camera position for full volume
                        else if (e) e.origin = o;
                        int chan = ReadSByte();
                        float vol = ReadByte() / 255;
                        float atten = ReadByte() / 64;
-                       vector o;
-                       o.x = ReadCoord();
-                       o.y = ReadCoord();
-                       o.z = ReadCoord();
+                       vector o = ReadVector();
                        if (who == player_currententnum) e = findfloat(NULL, entnum, who);  // play at camera position for full volume
                        else if (e) e.origin = o;
                        if (e)
                                .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 6388575b72cb09a5baa576a0e8c3882fdeff8ffb..80a1c98a83f69b6904b2bee67c4bffa818863f7e 100644 (file)
@@ -8,12 +8,8 @@ REGISTER_NET_TEMP(TE_CSQC_ARC)
        {
                WriteHeader(MSG_BROADCAST, TE_CSQC_ARC);
 
-               WriteCoord(MSG_BROADCAST, from.x);
-               WriteCoord(MSG_BROADCAST, from.y);
-               WriteCoord(MSG_BROADCAST, from.z);
-               WriteCoord(MSG_BROADCAST, to.x);
-               WriteCoord(MSG_BROADCAST, to.y);
-               WriteCoord(MSG_BROADCAST, to.z);
+               WriteVector(MSG_BROADCAST, from);
+               WriteVector(MSG_BROADCAST, to);
        }
 
 #elif defined(CSQC)
@@ -89,14 +85,8 @@ void b_make(vector s,vector e, string t,float l,float z)
 
        NET_HANDLE(TE_CSQC_ARC, bool isNew)
        {
-               vector from;
-               from.x = ReadCoord();
-               from.y = ReadCoord();
-               from.z = ReadCoord();
-               vector to;
-               to.x = ReadCoord();
-               to.y = ReadCoord();
-               to.z = ReadCoord();
+               vector from = ReadVector();
+               vector to = ReadVector();
                return = true;
 
                if (autocvar_cl_effects_lightningarc_simple)
index 1b70daee2fbbd5621e8e33198ffcec7c7380b2fd..9849b5be73f8ebf3d1aef3ff5b1e61ec4dfea2d0 100644 (file)
@@ -23,14 +23,10 @@ bool modeleffect_SendEntity(entity this, entity to, int sf)
        WriteShort(MSG_ENTITY, this.modelindex);
        WriteByte(MSG_ENTITY, this.skin);
        WriteByte(MSG_ENTITY, this.frame);
-       WriteCoord(MSG_ENTITY, this.origin.x);
-       WriteCoord(MSG_ENTITY, this.origin.y);
-       WriteCoord(MSG_ENTITY, this.origin.z);
+       WriteVector(MSG_ENTITY, this.origin);
        if(f & 1)
        {
-               WriteCoord(MSG_ENTITY, this.velocity.x);
-               WriteCoord(MSG_ENTITY, this.velocity.y);
-               WriteCoord(MSG_ENTITY, this.velocity.z);
+               WriteVector(MSG_ENTITY, this.velocity);
        }
        if(f & 2)
        {
@@ -84,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;
@@ -124,15 +120,11 @@ NET_HANDLE(ENT_CLIENT_MODELEFFECT, bool isnew)
        e.skin = ReadByte();
        e.frame = ReadByte();
        e.frame1time = time;
-       e.origin_x = ReadCoord();
-       e.origin_y = ReadCoord();
-       e.origin_z = ReadCoord();
+       e.origin = ReadVector();
        setorigin(e, e.origin);
        if(f & 1)
        {
-               e.velocity_x = ReadCoord();
-               e.velocity_y = ReadCoord();
-               e.velocity_z = ReadCoord();
+               e.velocity = ReadVector();
        }
        if(f & 2)
        {
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..86acdc154064ac6d0bc80258e7fca234d369740c 100644 (file)
@@ -1,4 +1,9 @@
 #include "ent_cs.qh"
+#include <common/gamemodes/_mod.qh>
+#include <common/resources.qh>
+#ifdef SVQC
+#include <server/resources.qh>
+#endif
 
 REGISTRY(EntCSProps, BITS(16) - 1)
 #define EntCSProps_from(i) _EntCSProps_from(i, NULL)
@@ -33,14 +38,33 @@ STATIC_INIT(RegisterEntCSProps_renumber) { FOREACH(EntCSProps, true, it.m_id = i
        }
 #endif
 
+#ifdef SVQC
+#define ENTCS_PROP_RESOURCE(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       bool id##_check(entity ent, entity player) { return (GetResourceAmount(ent, checkprop) != GetResourceAmount(player, checkprop)); } \
+       void id##_set(entity ent, entity player) { SetResourceAmountExplicit(ent, checkprop, GetResourceAmount(player, checkprop)); } \
+       void id##_send(int chan, entity ent) { LAMBDA(svsend); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_check = id##_check; \
+               this.m_set = id##_set; \
+               this.m_send = id##_send; \
+       }
+#elif defined(CSQC)
+#define ENTCS_PROP_RESOURCE(id, ispublic, checkprop, setprop, svsend, clreceive) \
+       void id##_receive(entity ent) { LAMBDA(clreceive); } \
+       REGISTER(EntCSProps, ENTCS_PROP, id, m_id, new_pure(entcs_prop)) { \
+               this.m_public = ispublic; \
+               this.m_receive = id##_receive; \
+       }
+#endif
+
 #define ENTCS_SET_NORMAL(var, x) MACRO_BEGIN \
        var = x; \
 MACRO_END
 
 /** the engine player name strings are mutable! */
 #define ENTCS_SET_MUTABLE_STRING(var, x) MACRO_BEGIN \
-       if (var) strunzone(var); \
-       var = strzone(x); \
+       strcpy(var, x); \
 MACRO_END
 
 ENTCS_PROP(ENTNUM, false, sv_entnum, ENTCS_SET_NORMAL, {}, {}) /* sentinel */
@@ -53,21 +77,21 @@ ENTCS_PROP(ANGLES, false, angles_y, ENTCS_SET_NORMAL,
        { WriteByte(chan, ent.angles.y / 360 * 256); },
        { vector v = '0 0 0'; v.y = ReadByte() / 256 * 360; ent.angles = v; })
 
-ENTCS_PROP(HEALTH, false, health, ENTCS_SET_NORMAL,
-       { WriteByte(chan, bound(0, ent.health / 10, 255));  /* FIXME: use a better scale? */ },
+ENTCS_PROP_RESOURCE(HEALTH, false, RESOURCE_HEALTH, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, GetResourceAmount(ent, RESOURCE_HEALTH) / 10, 255));  /* FIXME: use a better scale? */ },
        { ent.healthvalue = ReadByte() * 10; })
 
-ENTCS_PROP(ARMOR, false, armorvalue, ENTCS_SET_NORMAL,
-       { WriteByte(chan, bound(0, ent.armorvalue / 10, 255));  /* FIXME: use a better scale? */ },
-       { ent.armorvalue = ReadByte() * 10; })
+ENTCS_PROP_RESOURCE(ARMOR, false, RESOURCE_ARMOR, ENTCS_SET_NORMAL,
+       { WriteByte(chan, bound(0, GetResourceAmount(ent, RESOURCE_ARMOR) / 10, 255));  /* FIXME: use a better scale? */ },
+       { SetResourceAmountExplicit(ent, RESOURCE_ARMOR, ReadByte() * 10); })
 
 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 +192,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 +210,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..9601731
--- /dev/null
@@ -0,0 +1,648 @@
+#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
+       SetResourceAmountExplicit(this, RESOURCE_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)
+{
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       if (hlth < 0 || hlth >= 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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_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!
+
+       float hlth = GetResourceAmount(this.enemy, RESOURCE_HEALTH);
+       if (hlth < ASSAULT_VALUE_INACTIVE)
+       {
+               if (hlth - this.dmg > 0.5)
+               {
+                       GameRules_scoring_add_team(actor, SCORE, this.dmg);
+                       TakeResource(this.enemy, RESOURCE_HEALTH, this.dmg);
+               }
+               else
+               {
+                       GameRules_scoring_add_team(actor, SCORE, hlth);
+                       GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
+                       SetResourceAmountExplicit(this.enemy, RESOURCE_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(GetResourceAmount(this.assault_decreaser.enemy, RESOURCE_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, GetResourceAmount(it, RESOURCE_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(GetResourceAmount(this.enemy, RESOURCE_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;
+       SetResourceAmountExplicit(this, RESOURCE_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
+bool destructible_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.sprite)
+       {
+               WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       }
+       func_breakable_colormod(targ);
+       return true;
+}
+
+spawnfunc(func_breakable);
+spawnfunc(func_assault_destructible)
+{
+       if (!g_assault) { delete(this); return; }
+
+       this.spawnflags = 3;
+       this.classname = "func_assault_destructible";
+       this.event_heal = destructible_heal;
+       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,
+               {
+                       float hlth = GetResourceAmount(it.enemy, RESOURCE_HEALTH);
+                       if (hlth > 0 && hlth < 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..f4aea43
--- /dev/null
@@ -0,0 +1,492 @@
+#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 (!warmup_stage && round_handler_IsActive() && 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..3f96b41
--- /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(GetResourceAmount(player, RESOURCE_HEALTH), GetResourceAmount(player, RESOURCE_ARMOR), 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';
+       SetResourceAmountExplicit(flag, RESOURCE_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, GetResourceAmount(flag, RESOURCE_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: SetResourceAmountExplicit(flag, RESOURCE_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, GetResourceAmount(flag, RESOURCE_HEALTH)); }
+
+               if((GetResourceAmount(flag, RESOURCE_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
+               {
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
+                       ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
+               }
+               return;
+       }
+       if(autocvar_g_ctf_flag_return_damage)
+       {
+               // reduce health and check if it should be returned
+               TakeResource(this, RESOURCE_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))
+                               {
+                                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
+                                       ctf_CheckFlagReturn(this, RETURN_DROPPED);
+                                       return;
+                               }
+                       }
+                       if(this.ctf_flagdamaged_byworld)
+                       {
+                               TakeResource(this, RESOURCE_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)
+                       {
+                               TakeResource(this, RESOURCE_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))
+                       {
+                               SetResourceAmountExplicit(this, RESOURCE_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)
+               {
+                       SetResourceAmountExplicit(flag, RESOURCE_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;
+       SetResourceAmountExplicit(flag, RESOURCE_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);
+       SetResourceAmountExplicit(flag, RESOURCE_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 (GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR))
+               if (vdist(it.origin - org, <, sradius))
+               {
+                       // get the value of the item
+                       float t = it.bot_pickupevalfunc(this, it) * 0.0001;
+                       if (t > 0)
+                               navigation_routerating(this, it, t * ratingscale, 500);
+               }
+       });
+}
+
+void havocbot_ctf_reset_role(entity this)
+{
+       float cdefense, cmiddle, coffense;
+       entity mf, ef;
+       float c;
+
+       if(IS_DEAD(this))
+               return;
+
+       // 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(GetResourceAmount(this, RESOURCE_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(GetResourceAmount(this, RESOURCE_HEALTH) < 50)
+       {
+               havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+               return;
+       }
+
+       // Set the role timeout if necessary
+       if (!this.havocbot_role_timeout)
+               this.havocbot_role_timeout = time + 120;
+
+       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(GetResourceAmount(player, RESOURCE_HEALTH), GetResourceAmount(player, RESOURCE_ARMOR), 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(GetResourceAmount(frag_target, RESOURCE_HEALTH), GetResourceAmount(frag_target, RESOURCE_ARMOR), 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..2f9643b
--- /dev/null
@@ -0,0 +1,189 @@
+#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) ((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..6190289
--- /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.count = 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.count == 1) // player.killindicator.count == 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..24a8220
--- /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(GetResourceAmount(toucher, RESOURCE_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..7f126ce
--- /dev/null
@@ -0,0 +1,593 @@
+#include "freezetag.qh"
+
+// TODO: sv_freezetag
+#ifdef SVQC
+#include <server/resources.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(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++redalive; break;
+                       case NUM_TEAM_2: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++bluealive; break;
+                       case NUM_TEAM_3: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++yellowalive; break;
+                       case NUM_TEAM_4: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 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 && SAME_TEAM(it, this), {
+               if (!STAT(FROZEN, it) && GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
+       });
+       return last_pl;
+}
+
+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
+}
+
+// to be called when the player is frozen by freezetag (on death, spectator join etc), gives the score
+void freezetag_Freeze(entity targ, entity attacker)
+{
+       if(STAT(FROZEN, targ))
+               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);
+}
+
+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 / (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR));
+                       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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // neccessary to update correctly alive stats
+       if(!STAT(FROZEN, this))
+               freezetag_LastPlayerForTeam_Notify(this);
+       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))
+                       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
+                       Unfreeze(frag_target); // remove ice
+               SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
+               frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
+               return true;
+       }
+
+       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, Unfreeze)
+{
+       entity targ = M_ARGV(0, entity);
+       targ.freezetag_frozen_time = 0;
+       targ.freezetag_frozen_timeout = 0;
+
+       freezetag_count_alive_players();
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
+{
+       if(game_stopped)
+               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);
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
+
+               if(STAT(REVIVE_PROGRESS, player) >= 1)
+               {
+                       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);
+               SetResourceAmountExplicit(player, RESOURCE_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,
+               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (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..3dff701
--- /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, GetResourceAmount(it, RESOURCE_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..c8bfbf2
--- /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 = (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR)) / (GetResourceAmount(ball_owner, RESOURCE_HEALTH) + GetResourceAmount(ball_owner, RESOURCE_ARMOR));
+               navigation_routerating(this, ball_owner, t * ratingscale, 2000);
+       }
+       else // Ball has been dropped so collect.
+               navigation_routerating(this, 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 7eb8ecb4b0bd62a30004870d7c4a869ec87b85da..487012aa50902e7a834fdd708a7c0e45bb2928cc 100644 (file)
@@ -13,8 +13,6 @@ MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase)
 }
 #endif
 #ifdef SVQC
-.float metertime = _STAT(NB_METERSTART);
-
 .entity ballcarried;
 
 int autocvar_g_nexball_goalleadlimit;
@@ -154,9 +152,9 @@ void GiveBall(entity plyr, entity ball)
                ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
                ownr.ballcarried = NULL;
                GameRules_scoring_vip(ownr, false);
-               if(ownr.metertime)
+               if(STAT(NB_METERSTART, ownr))
                {
-                       ownr.metertime = 0;
+                       STAT(NB_METERSTART, ownr) = 0;
                        ownr.(weaponentity).state = WS_READY;
                }
                WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
@@ -197,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;
@@ -223,9 +221,9 @@ void DropBall(entity ball, vector org, vector vel)
        setthink(ball, ResetBall);
        ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
 
-       if(ball.owner.metertime)
+       if(STAT(NB_METERSTART, ball.owner))
        {
-               ball.owner.metertime = 0;
+               STAT(NB_METERSTART, ball.owner) = 0;
                .entity weaponentity = ball.weaponentity_fld;
                ball.owner.(weaponentity).state = WS_READY;
        }
@@ -310,7 +308,7 @@ void football_touch(entity this, entity toucher)
        }
        if (!IS_PLAYER(toucher))
                return;
-       if(toucher.health < 1)
+       if(GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
                return;
        if(!this.cnt)
                this.nextthink = time + autocvar_g_nexball_delay_idle;
@@ -350,7 +348,7 @@ void basketball_touch(entity this, entity toucher)
        }
        if(!this.cnt && IS_PLAYER(toucher) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (toucher != this.nb_dropper || time > this.nb_droptime + autocvar_g_nexball_delay_collect))
        {
-               if(toucher.health <= 0)
+               if(GetResourceAmount(toucher, RESOURCE_HEALTH) < 1)
                        return;
                LogNB("caught", toucher);
                GiveBall(toucher, this);
@@ -830,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';
                                }
                        }
                }
@@ -853,40 +851,35 @@ MUTATOR_HOOKFUNCTION(nb, SpectateCopy)
        entity spectatee = M_ARGV(0, entity);
        entity client = M_ARGV(1, entity);
 
-       client.metertime = spectatee.metertime;
+       STAT(NB_METERSTART, client) = STAT(NB_METERSTART, spectatee);
 }
 
 MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
 {
        entity player = M_ARGV(0, entity);
 
-       player.metertime = 0;
+       STAT(NB_METERSTART, player) = 0;
        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;
 }
 
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(nb, PlayerPhysics)
+MUTATOR_HOOKFUNCTION(nb, PlayerPhysics_UpdateStats)
 {
        entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
 
        if(player.ballcarried)
-       {
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nexball_basketball_carrier_highspeed;
-               player.stat_sv_maxspeed *= autocvar_g_nexball_basketball_carrier_highspeed;
-       }
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nexball_basketball_carrier_highspeed;
 }
 
 MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon)
index 3568f221b63fe53fbc440a282cf037bc14a59e6f..838d0dd7e9cf07e0be6fc7e4ebf894613e452f55 100644 (file)
@@ -11,8 +11,8 @@ METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity we
         if(weapon_prepareattack(thiswep, actor, weaponentity, false, autocvar_g_balance_nexball_primary_refire))
             if(autocvar_g_nexball_basketball_meter)
             {
-                if(actor.ballcarried && !actor.metertime)
-                    actor.metertime = time;
+                if(actor.ballcarried && !STAT(NB_METERSTART, actor))
+                    STAT(NB_METERSTART, actor) = time;
                 else
                     weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
             }
@@ -28,9 +28,9 @@ METHOD(BallStealer, wr_think, void(BallStealer thiswep, entity actor, .entity we
             weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, autocvar_g_balance_nexball_secondary_animtime, w_ready);
         }
 
-    if(!(fire & 1) && actor.metertime && actor.ballcarried)
+    if(!(fire & 1) && STAT(NB_METERSTART, actor) && actor.ballcarried)
     {
-        W_Nexball_Attack(actor, weaponentity, time - actor.metertime);
+        W_Nexball_Attack(actor, weaponentity, time - STAT(NB_METERSTART, actor));
         // DropBall or stealing will set metertime back to 0
         weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, autocvar_g_balance_nexball_primary_animtime, w_ready);
     }
@@ -112,12 +112,12 @@ void W_Nexball_Attack(entity actor, .entity weaponentity, float t)
        if(!(ball = actor.ballcarried))
                return;
 
-       W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+       W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0, WEP_PORTO.m_id); // TODO: use ballstealer weapon here? we don't want duplicates in the scoreboard
        tracebox(w_shotorg, BALL_MINS, BALL_MAXS, w_shotorg, MOVE_WORLDONLY, NULL);
        if(trace_startsolid)
        {
-               if(actor.metertime)
-                       actor.metertime = 0; // Shot failed, hide the power meter
+               if(STAT(NB_METERSTART, actor))
+                       STAT(NB_METERSTART, actor) = 0; // Shot failed, hide the power meter
                return;
        }
 
@@ -146,7 +146,7 @@ void W_Nexball_Attack2(entity actor, .entity weaponentity)
        if(actor.ballcarried.enemy)
        {
                entity _ball = actor.ballcarried;
-               W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0);
+               W_SetupShot(actor, weaponentity, false, 4, SND_NB_SHOOT1, CH_WEAPON_A, 0, WEP_PORTO.m_id | HITTYPE_SECONDARY); // TODO: use the ball stealer weapon here? probably don't want duplicates
                DropBall(_ball, w_shotorg, trigger_push_calculatevelocity(_ball.origin, _ball.enemy, 32, _ball));
                setthink(_ball, W_Nexball_Think);
                _ball.nextthink = time;
@@ -156,7 +156,7 @@ void W_Nexball_Attack2(entity actor, .entity weaponentity)
        if(!autocvar_g_nexball_tackling)
                return;
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0);
+       W_SetupShot(actor, weaponentity, false, 2, SND_NB_SHOOT2, CH_WEAPON_A, 0, WEP_PORTO.m_id);
        entity missile = new(ballstealer);
 
        missile.owner = actor;
index ee348fdbc6244707f53e7b6202aae30cd6392ea7..b8d49b10f2edce3580b517f2556a95f35fd092f7 100644 (file)
@@ -30,7 +30,7 @@ void cpicon_draw(entity this)
        this.cp_bob_spd = this.cp_bob_spd + 1.875 * frametime;
        this.colormod = '1 1 1' * (2 - bound(0, (this.pain_finished - time) / 10, 1));
 
-       if(!this.iscaptured) this.alpha = this.health / this.max_health;
+       if(!this.iscaptured) this.alpha = GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health;
 
        if(this.iscaptured)
        {
@@ -162,19 +162,17 @@ NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
 
        if(sf & CPSF_SETUP)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
 
-               this.health = ReadByte();
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
                this.max_health = ReadByte();
                this.count = ReadByte();
                this.team = ReadByte();
                this.iscaptured = ReadByte();
 
                if(!this.count)
-                       this.count = (this.health - this.max_health) * frametime;
+                       this.count = (GetResourceAmount(this, RESOURCE_HEALTH) - this.max_health) * frametime;
 
                cpicon_changeteam(this);
                cpicon_construct(this, isnew);
@@ -191,9 +189,9 @@ NET_HANDLE(ENT_CLIENT_CONTROLPOINT_ICON, bool isnew)
 
                _tmp = ReadByte();
 
-               if(_tmp != this.health)
+               if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
                        cpicon_damage(this, _tmp);
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
 }
index ac7a066ab17032c3fb0ae3733bdd8ead99c686c8..9d12c5548e6d4eafd4abdb336b6aa7208274bda3 100644 (file)
@@ -48,10 +48,10 @@ void generator_draw(entity this)
        if(time < this.move_time)
                return;
 
-       if(this.health > 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) > 0)
        {
                // damaged fx (less probable the more damaged is the generator)
-               if(random() < 0.9 - this.health / this.max_health)
+               if(random() < 0.9 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
                if(random() < 0.01)
                {
                        pointparticles(EFFECT_ELECTRO_BALLEXPLODE, this.origin + randompos('-50 -50 -20', '50 50 50'), '0 0 0', 1);
@@ -192,12 +192,10 @@ NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
 
        if(sf & GSF_SETUP)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
 
-               this.health = ReadByte();
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, ReadByte());
                this.max_health = ReadByte();
                this.count = ReadByte();
                this.team = ReadByte();
@@ -221,9 +219,9 @@ NET_HANDLE(ENT_CLIENT_GENERATOR, bool isnew)
 
                _tmp = ReadByte();
 
-               if(_tmp != this.health)
+               if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
                        generator_damage(this, _tmp);
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
 }
index ae4d7a4913b3fb8afe2857b2470f179dc9bc0891..5deef7ec22e01351ebf2f8b3796cd4c47b39f3d6 100644 (file)
@@ -9,9 +9,7 @@ REGISTER_NET_LINKED(ENT_ONSCAMERA)
 entity generator_camera;
 NET_HANDLE(ENT_ONSCAMERA, bool isnew)
 {
-       this.origin_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
+       this.origin = ReadVector();
        setorigin(this, this.origin);
 
        this.angles_x = ReadAngle();
@@ -38,7 +36,7 @@ MUTATOR_HOOKFUNCTION(cl_ons, WantEventchase)
        entity gen = NULL;
        if(ons_roundlost)
        {
-               IL_EACH(g_onsgenerators, it.health <= 0,
+               IL_EACH(g_onsgenerators, GetResourceAmount(it, RESOURCE_HEALTH) <= 0,
                {
                        gen = it;
                        break;
index 0941833de8acd7430cc7fb35cef56c104bf405bf..a00af18ff83119b0c991312fefdf3c8f981f0ec2 100644 (file)
@@ -10,11 +10,9 @@ bool cpicon_send(entity this, entity to, int sf)
        WriteByte(MSG_ENTITY, sf);
        if(sf & CPSF_SETUP)
        {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
+               WriteVector(MSG_ENTITY, this.origin);
 
-               WriteByte(MSG_ENTITY, this.health);
+               WriteByte(MSG_ENTITY, GetResourceAmount(this, RESOURCE_HEALTH));
                WriteByte(MSG_ENTITY, this.max_health);
                WriteByte(MSG_ENTITY, this.count);
                WriteByte(MSG_ENTITY, this.team);
@@ -25,10 +23,10 @@ bool cpicon_send(entity this, entity to, int sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
index 1b1619bc44f621458c912c56c8f80573ab1f49c6..a33a4301249c1dd67ef06ddf6b0dd445570d893e 100644 (file)
@@ -6,11 +6,9 @@ bool generator_send(entity this, entity to, int sf)
        WriteByte(MSG_ENTITY, sf);
        if(sf & GSF_SETUP)
        {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
+               WriteVector(MSG_ENTITY, this.origin);
 
-               WriteByte(MSG_ENTITY, this.health);
+               WriteByte(MSG_ENTITY, GetResourceAmount(this, RESOURCE_HEALTH));
                WriteByte(MSG_ENTITY, this.max_health);
                WriteByte(MSG_ENTITY, this.count);
                WriteByte(MSG_ENTITY, this.team);
@@ -20,10 +18,10 @@ bool generator_send(entity this, entity to, int sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
index 5a0e0975e528e7315c90e4ccf6e17199ac32e59e..f0217de7e6cd0d238d0a1ae7a785c88209c42fb0 100644 (file)
@@ -38,9 +38,7 @@ bool clientcamera_send(entity this, entity to, int sf)
 {
        WriteHeader(MSG_ENTITY, ENT_ONSCAMERA);
 
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
+       WriteVector(MSG_ENTITY, this.origin);
 
        WriteAngle(MSG_ENTITY, this.angles_x);
        WriteAngle(MSG_ENTITY, this.angles_y);
@@ -68,7 +66,7 @@ void ons_CaptureShield_Touch(entity this, entity toucher)
        vector mymid = (this.absmin + this.absmax) * 0.5;
        vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
 
-       Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, mymid, normalize(theirmid - mymid) * ons_captureshield_force);
+       Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, mymid, normalize(theirmid - mymid) * ons_captureshield_force);
 
        if(IS_REAL_CLIENT(toucher))
        {
@@ -272,15 +270,11 @@ bool ons_Link_Send(entity this, entity to, int sendflags)
        WriteByte(MSG_ENTITY, sendflags);
        if(sendflags & 1)
        {
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_x);
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_y);
-               WriteCoord(MSG_ENTITY, this.goalentity.origin_z);
+               WriteVector(MSG_ENTITY, this.goalentity.origin);
        }
        if(sendflags & 2)
        {
-               WriteCoord(MSG_ENTITY, this.enemy.origin_x);
-               WriteCoord(MSG_ENTITY, this.enemy.origin_y);
-               WriteCoord(MSG_ENTITY, this.enemy.origin_z);
+               WriteVector(MSG_ENTITY, this.enemy.origin);
        }
        if(sendflags & 4)
        {
@@ -381,7 +375,7 @@ int ons_ControlPoint_Attackable(entity cp, int teamnumber)
        return 0;
 }
 
-void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(damage <= 0) { return; }
 
@@ -406,11 +400,11 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
                ons_notification_time[this.team] = time;
        }
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        if(this.owner.iscaptured)
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        else
-               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - this.health) / (this.count / ONS_CP_THINKRATE));
+               WaypointSprite_UpdateBuildFinished(this.owner.sprite, time + (this.max_health - GetResourceAmount(this, RESOURCE_HEALTH)) / (this.count / ONS_CP_THINKRATE));
        this.pain_finished = time + 1;
        // particles on every hit
        pointparticles(EFFECT_SPARKS, hitloc, force*-1, 1);
@@ -420,7 +414,7 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
        else
                sound(this, CH_TRIGGER, SND_ONS_HIT2, VOL_BASE+0.3, ATTEN_NORM);
 
-       if (this.health < 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) < 0)
        {
                sound(this, CH_TRIGGER, SND_GRENADE_IMPACT, VOL_BASE, ATTEN_NORM);
                pointparticles(EFFECT_ROCKET_EXPLODE, this.origin, '0 0 0', 1);
@@ -453,6 +447,23 @@ void ons_ControlPoint_Icon_Damage(entity this, entity inflictor, entity attacker
        this.SendFlags |= CPSF_STATUS;
 }
 
+bool ons_ControlPoint_Icon_Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if (hlth <= 0 || hlth >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if(targ.owner.iscaptured)
+               WaypointSprite_UpdateHealth(targ.owner.sprite, hlth);
+       else
+               WaypointSprite_UpdateBuildFinished(targ.owner.sprite, time + (targ.max_health - hlth) / (targ.count / ONS_CP_THINKRATE));
+       targ.SendFlags |= CPSF_STATUS;
+       return true;
+}
+
 void ons_ControlPoint_Icon_Think(entity this)
 {
        this.nextthink = time + ONS_CP_THINKRATE;
@@ -475,23 +486,21 @@ void ons_ControlPoint_Icon_Think(entity this)
                _friendly_count = _friendly_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
                _enemy_count = _enemy_count * (autocvar_g_onslaught_cp_proxydecap_dps * ONS_CP_THINKRATE);
 
-               this.health = bound(0, this.health + (_friendly_count - _enemy_count), this.max_health);
+               GiveResourceWithLimit(this, RESOURCE_HEALTH, (_friendly_count - _enemy_count), this.max_health);
                this.SendFlags |= CPSF_STATUS;
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                {
-                       ons_ControlPoint_Icon_Damage(this, this, this, 1, 0, this.origin, '0 0 0');
+                       ons_ControlPoint_Icon_Damage(this, this, this, 1, 0, DMG_NOWEP, this.origin, '0 0 0');
                        return;
                }
        }
 
        if (time > this.pain_finished + 5)
        {
-               if(this.health < this.max_health)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) < this.max_health)
                {
-                       this.health = this.health + this.count;
-                       if (this.health >= this.max_health)
-                               this.health = this.max_health;
-                       WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+                       GiveResourceWithLimit(this, RESOURCE_HEALTH, this.count, this.max_health);
+                       WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
                }
        }
 
@@ -510,7 +519,7 @@ void ons_ControlPoint_Icon_Think(entity this)
        }
 
        // damaged fx
-       if(random() < 0.6 - this.health / this.max_health)
+       if(random() < 0.6 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
        {
                Send_Effect(EFFECT_ELECTRIC_SPARKS, this.origin + randompos('-10 -10 -20', '10 10 20'), '0 0 0', 1);
 
@@ -532,13 +541,13 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
        if(!a)
                return;
 
-       this.health = this.health + this.count;
+       GiveResource(this, RESOURCE_HEALTH, this.count);
 
        this.SendFlags |= CPSF_STATUS;
 
-       if (this.health >= this.max_health)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) >= this.max_health)
        {
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                this.count = autocvar_g_onslaught_cp_regen * ONS_CP_THINKRATE; // slow repair rate from now on
                setthink(this, ons_ControlPoint_Icon_Think);
                sound(this, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILT, VOL_BASE, ATTEN_NORM);
@@ -548,7 +557,7 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
                Send_Effect(EFFECT_CAP(this.owner.team), this.owner.origin, '0 0 0', 1);
 
                WaypointSprite_UpdateMaxHealth(this.owner.sprite, this.max_health);
-               WaypointSprite_UpdateHealth(this.owner.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.owner.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
                if(IS_PLAYER(this.owner.ons_toucher))
                {
@@ -571,7 +580,7 @@ void ons_ControlPoint_Icon_BuildThink(entity this)
        if(this.owner.model != MDL_ONS_CP_PAD2.model_str())
                setmodel_fixsize(this.owner, MDL_ONS_CP_PAD2);
 
-       if(random() < 0.9 - this.health / this.max_health)
+       if(random() < 0.9 - GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health)
                Send_Effect(EFFECT_RAGE, this.origin + 10 * randomvec(), '0 0 -1', 1);
 }
 
@@ -586,15 +595,16 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
 
        e.owner = cp;
        e.max_health = autocvar_g_onslaught_cp_health;
-       e.health = autocvar_g_onslaught_cp_buildhealth;
+       SetResourceAmountExplicit(e, RESOURCE_HEALTH, autocvar_g_onslaught_cp_buildhealth);
        e.solid = SOLID_NOT;
        e.takedamage = DAMAGE_AIM;
        e.bot_attack = true;
        IL_PUSH(g_bot_targets, e);
        e.event_damage = ons_ControlPoint_Icon_Damage;
+       e.event_heal = ons_ControlPoint_Icon_Heal;
        e.team = player.team;
        e.colormap = 1024 + (e.team - 1) * 17;
-       e.count = (e.max_health - e.health) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
+       e.count = (e.max_health - GetResourceAmount(e, RESOURCE_HEALTH)) * ONS_CP_THINKRATE / autocvar_g_onslaught_cp_buildtime; // how long it takes to build
 
        sound(e, CH_TRIGGER, SND_ONS_CONTROLPOINT_BUILD, VOL_BASE, ATTEN_NORM);
 
@@ -604,7 +614,7 @@ void ons_ControlPoint_Icon_Spawn(entity cp, entity player)
 
        Send_Effect(EFFECT_FLAG_TOUCH(player.team), e.origin, '0 0 0', 1);
 
-       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - e.health) / (e.count / ONS_CP_THINKRATE));
+       WaypointSprite_UpdateBuildFinished(cp.sprite, time + (e.max_health - GetResourceAmount(e, RESOURCE_HEALTH)) / (e.count / ONS_CP_THINKRATE));
        WaypointSprite_UpdateRule(cp.sprite,cp.team,SPRITERULE_TEAMPLAY);
        cp.sprite.SendFlags |= 16;
 
@@ -646,7 +656,7 @@ void ons_ControlPoint_UpdateSprite(entity e)
                        else
                        {
                                WaypointSprite_UpdateMaxHealth(e.sprite, e.goalentity.max_health);
-                               WaypointSprite_UpdateHealth(e.sprite, e.goalentity.health);
+                               WaypointSprite_UpdateHealth(e.sprite, GetResourceAmount(e.goalentity, RESOURCE_HEALTH));
                        }
                }
                if(e.lastshielded)
@@ -868,7 +878,7 @@ void ons_camSetup(entity this)
        WriteAngle(MSG_ALL, cam.angles_z);
 }
 
-void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(damage <= 0) return;
        if(warmup_stage || game_stopped) return;
@@ -895,14 +905,15 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                        play2team(this.team, SND(ONS_GENERATOR_UNDERATTACK));
                }
        }
-       this.health = this.health - damage;
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       float hlth = GetResourceAmount(this, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(this.sprite, hlth);
        // choose an animation frame based on health
-       this.frame = 10 * bound(0, (1 - this.health / this.max_health), 1);
+       this.frame = 10 * bound(0, (1 - hlth / this.max_health), 1);
        // see if the generator is still functional, or dying
-       if (this.health > 0)
+       if (hlth > 0)
        {
-               this.lasthealth = this.health;
+               this.lasthealth = hlth;
        }
        else
        {
@@ -918,6 +929,7 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
                this.isshielded = false;
                this.takedamage = DAMAGE_NO; // can't be hurt anymore
                this.event_damage = func_null; // won't do anything if hurt
+               this.event_heal = func_null;
                this.count = 0; // reset counter
                setthink(this, func_null);
                this.nextthink = 0;
@@ -952,31 +964,48 @@ void ons_GeneratorDamage(entity this, entity inflictor, entity attacker, float d
        this.SendFlags |= GSF_STATUS;
 }
 
+bool ons_GeneratorHeal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       float hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       if (hlth <= 0 || hlth >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       hlth = GetResourceAmount(targ, RESOURCE_HEALTH);
+       WaypointSprite_UpdateHealth(targ.sprite, hlth);
+       targ.frame = 10 * bound(0, (1 - hlth / targ.max_health), 1);
+       targ.lasthealth = hlth;
+       targ.SendFlags |= GSF_STATUS;
+       return true;
+}
+
 void ons_GeneratorThink(entity this)
 {
        this.nextthink = time + GEN_THINKRATE;
-       if (!game_stopped)
+
+       if (game_stopped || this.isshielded || time < this.wait)
+               return;
+
+       this.wait = time + 5;
+       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it),
        {
-               if(!this.isshielded && this.wait < time)
+               if (SAME_TEAM(it, this))
                {
-                       this.wait = time + 5;
-                       FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
-                               if(SAME_TEAM(it, this))
-                               {
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
-                                       soundto(MSG_ONE, it, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE);    // FIXME: unique sound?
-                               }
-                               else
-                                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
-                       });
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
+                       msg_entity = it;
+                       soundto(MSG_ONE, this, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE); // FIXME: unique sound?
                }
-       }
+               else
+                       Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
+       });
 }
 
 void ons_GeneratorReset(entity this)
 {
        this.team = this.team_saved;
-       this.lasthealth = this.max_health = this.health = autocvar_g_onslaught_gen_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, autocvar_g_onslaught_gen_health);
+       this.lasthealth = this.max_health = autocvar_g_onslaught_gen_health;
        this.takedamage = DAMAGE_AIM;
        this.bot_attack = true;
        if(!IL_CONTAINS(g_bot_targets, this))
@@ -985,6 +1014,7 @@ void ons_GeneratorReset(entity this)
        this.islinked = true;
        this.isshielded = true;
        this.event_damage = ons_GeneratorDamage;
+       this.event_heal = ons_GeneratorHeal;
        setthink(this, ons_GeneratorThink);
        this.nextthink = time + GEN_THINKRATE;
 
@@ -994,7 +1024,7 @@ void ons_GeneratorReset(entity this)
        this.SendFlags |= GSF_STATUS;
 
        WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-       WaypointSprite_UpdateHealth(this.sprite, this.health);
+       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
        WaypointSprite_UpdateRule(this.sprite,this.team,SPRITERULE_TEAMPLAY);
 
        onslaught_updatelinks();
@@ -1041,11 +1071,13 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
        gen.team_saved = teamnumber;
        IL_PUSH(g_saved_team, gen);
        set_movetype(gen, MOVETYPE_NONE);
-       gen.lasthealth = gen.max_health = gen.health = autocvar_g_onslaught_gen_health;
+       gen.lasthealth = gen.max_health = autocvar_g_onslaught_gen_health;
+       SetResourceAmountExplicit(gen, RESOURCE_HEALTH, autocvar_g_onslaught_gen_health);
        gen.takedamage = DAMAGE_AIM;
        gen.bot_attack = true;
        IL_PUSH(g_bot_targets, gen);
        gen.event_damage = ons_GeneratorDamage;
+       gen.event_heal = ons_GeneratorHeal;
        gen.reset = ons_GeneratorReset;
        setthink(gen, ons_GeneratorThink);
        gen.nextthink = time + GEN_THINKRATE;
@@ -1067,7 +1099,7 @@ void ons_GeneratorSetup(entity gen) // called when spawning a generator entity o
        WaypointSprite_SpawnFixed(WP_Null, gen.origin + CPGEN_WAYPOINT_OFFSET, gen, sprite, RADARICON_NONE);
        WaypointSprite_UpdateRule(gen.sprite, gen.team, SPRITERULE_TEAMPLAY);
        WaypointSprite_UpdateMaxHealth(gen.sprite, gen.max_health);
-       WaypointSprite_UpdateHealth(gen.sprite, gen.health);
+       WaypointSprite_UpdateHealth(gen.sprite, GetResourceAmount(gen, RESOURCE_HEALTH));
 
        InitializeEntity(gen, ons_DelayedGeneratorSetup, INITPRIO_SETLOCATION);
 }
@@ -1085,10 +1117,10 @@ void Onslaught_count_generators()
        for(e = ons_worldgeneratorlist; e; e = e.ons_worldgeneratornext)
        {
                ++total_generators;
-               redowned += (e.team == NUM_TEAM_1 && e.health > 0);
-               blueowned += (e.team == NUM_TEAM_2 && e.health > 0);
-               yellowowned += (e.team == NUM_TEAM_3 && e.health > 0);
-               pinkowned += (e.team == NUM_TEAM_4 && e.health > 0);
+               redowned += (e.team == NUM_TEAM_1 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               blueowned += (e.team == NUM_TEAM_2 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               yellowowned += (e.team == NUM_TEAM_3 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
+               pinkowned += (e.team == NUM_TEAM_4 && GetResourceAmount(e, RESOURCE_HEALTH) > 0);
        }
 }
 
@@ -1155,7 +1187,7 @@ bool Onslaught_CheckWinner()
                        else
                                d = d * tmp_entity.max_health / max(30, 60 * autocvar_timelimit_suddendeath);
 
-                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, tmp_entity.origin, '0 0 0');
+                       Damage(tmp_entity, tmp_entity, tmp_entity, d, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, tmp_entity.origin, '0 0 0');
 
                        tmp_entity.sprite.SendFlags |= 16;
 
@@ -1229,13 +1261,13 @@ void havocbot_goalrating_ons_offenseitems(entity this, float ratingscale, vector
        bool needarmor = false, needweapons = false;
 
        // Needs armor/health?
-       if(this.health<100)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 100)
                needarmor = true;
 
        // 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;
        });
@@ -1254,7 +1286,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 ( ((GetResourceAmount(it, RESOURCE_HEALTH) || GetResourceAmount(it, RESOURCE_ARMOR)) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
                if (vdist(it.origin - org, <, sradius))
                {
                        int t = it.bot_pickupevalfunc(this, it);
@@ -1978,7 +2010,7 @@ MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
                        {
                                entity source_point = ons_Nearest_ControlPoint(player, player.origin, autocvar_g_onslaught_teleport_radius);
 
-                               if ( !source_point && player.health > 0 )
+                               if ( !source_point && GetResourceAmount(player, RESOURCE_HEALTH) > 0 )
                                {
                                        sprint(player, "\nYou need to be next to a control point\n");
                                        return true;
@@ -1993,7 +2025,7 @@ MUTATOR_HOOKFUNCTION(ons, SV_ParseClientCommand)
                                        return true;
                                }
 
-                               if ( player.health <= 0 )
+                               if ( GetResourceAmount(player, RESOURCE_HEALTH) <= 0 )
                                {
                                        player.ons_spawn_by = closest_target;
                                        player.respawn_flags = player.respawn_flags | RESPAWN_FORCE;
@@ -2059,14 +2091,14 @@ MUTATOR_HOOKFUNCTION(ons, SendWaypoint)
                {
                        entity wp_owner = wp.owner;
                        entity e = WaypointSprite_getviewentity(to);
-                       if(SAME_TEAM(e, wp_owner) && wp_owner.goalentity.health >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
+                       if(SAME_TEAM(e, wp_owner) && GetResourceAmount(wp_owner.goalentity, RESOURCE_HEALTH) >= wp_owner.goalentity.max_health) { wp_flag |= 2; }
                        if(!ons_ControlPoint_Attackable(wp_owner, e.team)) { wp_flag |= 2; }
                }
                if(wp.owner.classname == "onslaught_generator")
                {
                        entity wp_owner = wp.owner;
-                       if(wp_owner.isshielded && wp_owner.health >= wp_owner.max_health) { wp_flag |= 2; }
-                       if(wp_owner.health <= 0) { wp_flag |= 2; }
+                       if(wp_owner.isshielded && GetResourceAmount(wp_owner, RESOURCE_HEALTH) >= wp_owner.max_health) { wp_flag |= 2; }
+                       if(GetResourceAmount(wp_owner, RESOURCE_HEALTH) <= 0) { wp_flag |= 2; }
                }
        }
 
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..3109e7c92f93c66adc8c0f5d274bef901bf019e3 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,8 @@ 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),
+    ITEM_FLAG_RESOURCE = BIT(2) ///< Item is is a resource, not a held item.
 };
 
 #define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
index 1d5bd87baceb116b7e241f9955e4e12b8f6d3ee9..4c37464ad83c8de28d6a6f706d8f264ff26727f9 100644 (file)
@@ -1,10 +1,13 @@
 #pragma once
 
 #include "pickup.qh"
+#include <common/items/all.qh>
 #ifdef SVQC
     #include <common/t_items.qh>
+    #include <server/resources.qh>
 #endif
 
+#if 1
 .int ammo_none;
 .int ammo_shells;
 .int ammo_nails;
 .int ammo_plasma;
 .int ammo_fuel;
 #endif
+#endif
+
+#ifdef GAMEQC
+.int spawnflags;
+#endif
 
 #ifdef SVQC
 PROPERTY(float, g_pickup_ammo_anyway);
@@ -38,10 +46,10 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_BULLETS))
+        SetResourceAmountExplicit(item, RESOURCE_BULLETS, g_pickup_nails);
 }
 #endif
 
@@ -51,7 +59,7 @@ ENDCLASS(Bullets)
 REGISTER_ITEM(Bullets, Bullets) {
     this.m_canonical_spawnfunc = "item_bullets";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Bullets_ITEM;
 #endif
     this.netname    =   "bullets";
@@ -72,16 +80,16 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_CELLS))
+        SetResourceAmountExplicit(item, RESOURCE_CELLS, g_pickup_cells);
 }
 #endif
 REGISTER_ITEM(Cells, Ammo) {
     this.m_canonical_spawnfunc = "item_cells";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Cells_ITEM;
 #endif
     this.netname    =   "cells";
@@ -102,16 +110,16 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_PLASMA))
+        SetResourceAmountExplicit(item, RESOURCE_PLASMA, g_pickup_plasma);
 }
 #endif
 REGISTER_ITEM(Plasma, Ammo) {
     this.m_canonical_spawnfunc = "item_plasma";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Plasma_ITEM;
 #endif
     this.netname    =   "plasma";
@@ -132,16 +140,16 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_ROCKETS))
+        SetResourceAmountExplicit(item, RESOURCE_ROCKETS, g_pickup_rockets);
 }
 #endif
 REGISTER_ITEM(Rockets, Ammo) {
     this.m_canonical_spawnfunc = "item_rockets";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Rockets_ITEM;
 #endif
     this.netname    =   "rockets";
@@ -162,10 +170,10 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_SHELLS))
+        SetResourceAmountExplicit(item, RESOURCE_SHELLS, g_pickup_shells);
 }
 #endif
 
@@ -175,7 +183,7 @@ ENDCLASS(Shells)
 REGISTER_ITEM(Shells, Shells) {
     this.m_canonical_spawnfunc = "item_shells";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_Shells_ITEM;
 #endif
     this.netname    =   "shells";
index 7f37c75aec002465260b1852810253e05c6a4b11..ee39aa59242111771347d38005fe0d3c89113e4c 100644 (file)
@@ -22,19 +22,19 @@ 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;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armorsmall;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armorsmall);
 }
 #endif
 
 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 | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorSmall_ITEM;
     this.m_sound                =   SND_ArmorSmall;
 #endif
@@ -60,19 +60,19 @@ 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;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armormedium;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armormedium);
 }
 #endif
 
 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 | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorMedium_ITEM;
     this.m_sound                =   SND_ArmorMedium;
 #endif
@@ -98,19 +98,19 @@ 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;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armorbig;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armorbig);
 }
 #endif
 
 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 | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorBig_ITEM;
     this.m_sound                =   SND_ArmorBig;
 #endif
@@ -138,19 +138,19 @@ 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;
-    if(!item.armorvalue)
-        item.armorvalue = g_pickup_armormega;
+    if(!GetResourceAmount(item, RESOURCE_ARMOR))
+        SetResourceAmountExplicit(item, RESOURCE_ARMOR, g_pickup_armormega);
 }
 #endif
 
 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 | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_ArmorMega_ITEM;
     this.m_sound                =   SND_ArmorMega;
 #endif
index da431086e18587448cf697c8127390fd166134f0..bf515fe4dd7f7c167d31c7f85b6eb3bc9e409fb3 100644 (file)
@@ -22,19 +22,19 @@ 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;
-    if(!item.health)
-        item.health = g_pickup_healthsmall;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthsmall);
 }
 #endif
 
 REGISTER_ITEM(HealthSmall, Health) {
     this.m_canonical_spawnfunc = "item_health_small";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthSmall_ITEM;
     this.m_sound                =   SND_HealthSmall;
 #endif
@@ -60,19 +60,19 @@ 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;
-    if(!item.health)
-        item.health = g_pickup_healthmedium;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthmedium);
 }
 #endif
 
 REGISTER_ITEM(HealthMedium, Health) {
     this.m_canonical_spawnfunc = "item_health_medium";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthMedium_ITEM;
     this.m_sound                =   SND_HealthMedium;
 #endif
@@ -98,19 +98,19 @@ 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;
-    if(!item.health)
-        item.health = g_pickup_healthbig;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthbig);
 }
 #endif
 
 REGISTER_ITEM(HealthBig, Health) {
     this.m_canonical_spawnfunc = "item_health_big";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthBig_ITEM;
     this.m_sound                =   SND_HealthBig;
 #endif
@@ -138,19 +138,19 @@ 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;
-    if(!item.health)
-        item.health = g_pickup_healthmega;
+    if(!GetResourceAmount(item, RESOURCE_HEALTH))
+        SetResourceAmountExplicit(item, RESOURCE_HEALTH, g_pickup_healthmega);
 }
 #endif
 
 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 | ITEM_FLAG_RESOURCE;
     this.m_model                =   MDL_HealthMega_ITEM;
     this.m_sound                =   SND_HealthMega;
 #endif
index 284bf3d390fce1c7b62653a9570b9ef20a7dffe5..760033861a7db8377342bc6ff7dbd6bef1901b4b 100644 (file)
@@ -17,10 +17,10 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_FUEL))
+        SetResourceAmountExplicit(item, RESOURCE_FUEL, g_pickup_fuel_jetpack);
 }
 #endif
 
@@ -35,10 +35,10 @@ REGISTER_ITEM(Jetpack, Powerup) {
     this.m_itemid               =   IT_JETPACK;
 #endif
     this.netname                =   "jetpack";
-    this.m_name                 =   "Jet pack";
+    this.m_name                 =   "Jetpack";
     this.m_icon                 =   "jetpack";
     this.m_color                =   '0.5 0.5 0.5';
-    this.m_waypoint             =   _("Jet Pack");
+    this.m_waypoint             =   _("Jetpack");
     this.m_waypointblink        =   2;
 #ifdef SVQC
     this.m_botvalue             =   3000;
@@ -55,16 +55,16 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_FUEL))
+        SetResourceAmountExplicit(item, RESOURCE_FUEL, g_pickup_fuel);
 }
 #endif
 REGISTER_ITEM(JetpackFuel, Ammo) {
     this.m_canonical_spawnfunc = "item_fuel";
 #ifdef GAMEQC
-       this.spawnflags = ITEM_FLAG_NORMAL;
+       this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_RESOURCE;
     this.m_model    =   MDL_JetpackFuel_ITEM;
 #endif
     this.netname    =   "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 62600a9c4b07fec9deb809985b6c88df86aab09b..0884bc8d79054c29d6d88bacb75ad88de011e09b 100644 (file)
@@ -935,12 +935,12 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                {
                        t = car(s); s = cdr(s);
                        Gametype f = MapInfo_Type_FromString(t);
-                       if(!autocvar_g_mapinfo_ignore_warnings)
-                               LOG_WARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.");
+                       //if(!autocvar_g_mapinfo_ignore_warnings)
+                               //LOG_WARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.");
                        if(f)
                                _MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, true);
                        else if(!autocvar_g_mapinfo_ignore_warnings)
-                               LOG_WARN("Map ", pFilename, " supports unknown game type ", t, ", ignored");
+                               LOG_DEBUG("Map ", pFilename, " supports unknown game type ", t, ", ignored");
                }
                else if(t == "gametype")
                {
@@ -949,7 +949,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        if(f)
                                _MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
                        else if(!autocvar_g_mapinfo_ignore_warnings)
-                               LOG_WARN("Map ", pFilename, " supports unknown game type ", t, ", ignored");
+                               LOG_DEBUG("Map ", pFilename, " supports unknown game type ", t, ", ignored");
                }
                else if(t == "size")
                {
@@ -996,7 +996,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        }
                        else
                        {
-                               LOG_WARN("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored");
+                               LOG_DEBUG("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored");
                        }
                }
                else if(t == "clientsettemp_for_type")
@@ -1013,7 +1013,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gamet
                        }
                        else
                        {
-                               LOG_WARN("Map ", pFilename, " has a client setting for unknown game type ", t, ", ignored");
+                               LOG_DEBUG("Map ", pFilename, " has a client setting for unknown game type ", t, ", ignored");
                        }
                }
                else if(t == "fog")
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..cb17ac4
--- /dev/null
@@ -0,0 +1,388 @@
+#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 = GetResourceAmount(this, RESOURCE_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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_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);
+
+       IL_EACH(g_projectiles, it.classname == "grapplinghook" && it.aiment == this,
+       {
+               RemoveHook(it);
+       });
+}
+
+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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
+       if(this.sprite)
+       {
+               WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_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)
+{
+       // TODO: use a clipgroup for all func_breakables so they don't collide with eachother
+       float oldhit = this.dphitcontentsmask;
+       this.dphitcontentsmask = DPCONTENTS_BODY; // we really only care about when players are standing inside, obey the mapper in other cases!
+       tracebox(this.origin, this.mins, this.maxs, this.origin, MOVE_NORMAL, this);
+       this.dphitcontentsmask = oldhit;
+       if(trace_startsolid || trace_fraction < 1)
+       {
+               this.nextthink = time + 5; // retry every 5 seconds until the area becomes clear
+               return;
+       }
+       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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if(this.sprite)
+       {
+               WaypointSprite_Ping(this.sprite);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
+       }
+       func_breakable_colormod(this);
+
+       if(GetResourceAmount(this, RESOURCE_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(!GetResourceAmount(this, RESOURCE_HEALTH))
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 100);
+       this.max_health = GetResourceAmount(this, RESOURCE_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..44e3128
--- /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 (GetResourceAmount(this, RESOURCE_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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_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)
+{
+       SetResourceAmountExplicit(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_HEALTH) <= damage)
+               {
+                       this.enemy = attacker;
+                       button_fire(this);
+               }
+       }
+       else
+       {
+               TakeResource(this, RESOURCE_HEALTH, damage);
+               if (GetResourceAmount(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_HEALTH))
+       {
+               this.max_health = GetResourceAmount(this, RESOURCE_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..8d40a37
--- /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;
+               SetResourceAmountExplicit(this, RESOURCE_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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
+
+       if (this.itemkeys)
+       {
+               // don't allow opening doors through damage if keys are required
+               return;
+       }
+
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
+       {
+               SetResourceAmountExplicit(this.owner, RESOURCE_HEALTH, this.owner.max_health);
+               this.owner.takedamage = DAMAGE_NO;      // will 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 (GetResourceAmount(toucher, RESOURCE_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 (GetResourceAmount(this, RESOURCE_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(GetResourceAmount(t, RESOURCE_HEALTH) && !GetResourceAmount(this, RESOURCE_HEALTH))
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(t, RESOURCE_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)
+       {
+               SetResourceAmountExplicit(t, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_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 = GetResourceAmount(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_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..39c02a8
--- /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;
+               SetResourceAmountExplicit(this, RESOURCE_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..f06f39e
--- /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;
+
+       SetResourceAmountExplicit(this, RESOURCE_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)
+       {
+               SetResourceAmountExplicit(this, RESOURCE_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)
+       {
+               SetResourceAmountExplicit(this, RESOURCE_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
+               SetResourceAmountExplicit(this, RESOURCE_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..cc909e5
--- /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 (GetResourceAmount(toucher, RESOURCE_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 (GetResourceAmount(toucher, RESOURCE_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..f9e50dc
--- /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;
+       SetBrushEntityModelNoLOD(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;
+       SetBrushEntityModelNoLOD(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..403d956
--- /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) && GetResourceAmount(player, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+                       {
+                               if(IS_PLAYER(head))
+                                       if(GetResourceAmount(head, RESOURCE_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..866fd88
--- /dev/null
@@ -0,0 +1,60 @@
+#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);
+                       bool healed = Heal(toucher, this, GetResourceAmount(this, RESOURCE_HEALTH), this.max_health);
+
+                       if(playthesound || healed)
+                               _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(!GetResourceAmount(this, RESOURCE_HEALTH))
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 10); // TODO: use a special field for this, it doesn't have actual health!
+       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..5447b99
--- /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)
+       {
+               SetResourceAmountExplicit(this, RESOURCE_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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if (GetResourceAmount(this, RESOURCE_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)
+       {
+               SetResourceAmountExplicit(this, RESOURCE_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 (GetResourceAmount(this, RESOURCE_HEALTH))
+       {
+               if (this.spawnflags & SPAWNFLAG_NOTOUCH)
+                       objerror (this, "health and notouch don't make sense\n");
+               this.canteamdamage = true;
+               this.max_health = GetResourceAmount(this, RESOURCE_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..5d7c5b6
--- /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?
+       SetResourceAmountExplicit(this, RESOURCE_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..8e3fd73
--- /dev/null
@@ -0,0 +1,158 @@
+#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 (!?)
+.float swamp_lifetime;  // holds the points remaining until slug dies (not quite health!) 
+.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.swamp_lifetime -= 1;
+
+       //Slug dead? then remove curses.
+       if(GetResourceAmount(this, RESOURCE_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.swamp_lifetime = 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.swamp_lifetime = 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 32383af5718e78fa530de6d2e44b620d0e7603ac..88120a0ea7550acbb93cd46e9b94022165b18ba2 100644 (file)
@@ -12,7 +12,7 @@ METHOD(MageSpike, wr_think, void(MageSpike thiswep, entity actor, .entity weapon
     if (!IS_PLAYER(actor) || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
         if (!actor.target_range) actor.target_range = autocvar_g_monsters_target_range;
         actor.enemy = Monster_FindTarget(actor);
-        W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0);
+        W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MageSpike_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_MAGE.m_id);
        if (!IS_PLAYER(actor)) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
         M_Mage_Attack_Spike(actor, w_shotdir);
         weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
@@ -87,23 +87,31 @@ bool M_Mage_Defend_Heal_Check(entity this, entity targ)
 {
        if(targ == NULL)
                return false;
-       if(targ.health <= 0)
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0)
                return false;
        if(DIFF_TEAM(targ, this) && targ != this.monster_follow)
                return false;
        if(STAT(FROZEN, targ))
                return false;
        if(!IS_PLAYER(targ))
-               return (IS_MONSTER(targ) && targ.health < targ.max_health);
+               return (IS_MONSTER(targ) && GetResourceAmount(targ, RESOURCE_HEALTH) < targ.max_health);
        if(targ.items & ITEM_Shield.m_itemid)
                return false;
 
        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 2: return (targ.armorvalue < autocvar_g_balance_armor_regenstable);
-               case 3: return (targ.health > 0);
+               case 0: return (GetResourceAmount(targ, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable);
+               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 (GetResourceAmount(targ, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable);
+               case 3: return (GetResourceAmount(targ, RESOURCE_HEALTH) > 0);
        }
 
        return false;
@@ -118,7 +126,8 @@ 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), NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, directhitentity);
+       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);
 }
@@ -135,7 +144,7 @@ void M_Mage_Attack_Spike_Touch(entity this, entity toucher)
 // copied from W_Seeker_Think
 void M_Mage_Attack_Spike_Think(entity this)
 {
-       if (time > this.ltime || (this.enemy && this.enemy.health <= 0) || this.owner.health <= 0) {
+       if (time > this.ltime || (this.enemy && GetResourceAmount(this.enemy, RESOURCE_HEALTH) <= 0) || GetResourceAmount(this.owner, RESOURCE_HEALTH) <= 0) {
                this.projectiledeathtype |= HITTYPE_SPLASH;
                M_Mage_Attack_Spike_Explode(this, NULL);
        }
@@ -225,26 +234,32 @@ void M_Mage_Defend_Heal(entity this)
                        switch(this.skin)
                        {
                                case 0:
-                                       if(it.health < autocvar_g_balance_health_regenstable) it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_health_regenstable);
+                               {
+                                       Heal(it, this, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_health_regenstable);
                                        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);
+                               {
+                                       if(GetResourceAmount(this, RESOURCE_CELLS)) GiveResourceWithLimit(it, RESOURCE_CELLS, 1, g_pickup_cells_max);
+                                       if(GetResourceAmount(this, RESOURCE_PLASMA)) GiveResourceWithLimit(it, RESOURCE_PLASMA, 1, g_pickup_plasma_max);
+                                       if(GetResourceAmount(this, RESOURCE_ROCKETS)) GiveResourceWithLimit(it, RESOURCE_ROCKETS, 1, g_pickup_rockets_max);
+                                       if(GetResourceAmount(this, RESOURCE_SHELLS)) GiveResourceWithLimit(it, RESOURCE_SHELLS, 2, g_pickup_shells_max);
+                                       if(GetResourceAmount(this, RESOURCE_BULLETS)) GiveResourceWithLimit(it, RESOURCE_BULLETS, 5, g_pickup_nails_max);
+                                       // TODO: fuel?
                                        fx = EFFECT_AMMO_REGEN;
                                        break;
+                               }
                                case 2:
-                                       if(it.armorvalue < autocvar_g_balance_armor_regenstable)
+                                       if(GetResourceAmount(it, RESOURCE_ARMOR) < autocvar_g_balance_armor_regenstable)
                                        {
-                                               it.armorvalue = bound(0, it.armorvalue + (autocvar_g_monster_mage_heal_allies), autocvar_g_balance_armor_regenstable);
+                                               GiveResourceWithLimit(it, RESOURCE_ARMOR, autocvar_g_monster_mage_heal_allies, autocvar_g_balance_armor_regenstable);
                                                fx = EFFECT_ARMOR_REPAIR;
                                        }
                                        break;
                                case 3:
-                                       it.health = bound(0, it.health - ((it == this)  ? (autocvar_g_monster_mage_heal_self) : (autocvar_g_monster_mage_heal_allies)), autocvar_g_balance_health_regenstable);
+                                       float hp = ((it == this) ? autocvar_g_monster_mage_heal_self : autocvar_g_monster_mage_heal_allies);
+                                       TakeResource(it, RESOURCE_HEALTH, hp); // TODO: use regular damage functions? needs a way to bypass friendly fire checks
                                        fx = EFFECT_RAGE;
                                        break;
                        }
@@ -254,9 +269,9 @@ void M_Mage_Defend_Heal(entity this)
                else
                {
                        Send_Effect(EFFECT_HEALING, it.origin, '0 0 0', 1);
-                       it.health = bound(0, it.health + (autocvar_g_monster_mage_heal_allies), it.max_health);
+                       Heal(it, this, autocvar_g_monster_mage_heal_allies, RESOURCE_LIMIT_NONE);
                        if(!(it.spawnflags & MONSTERFLAG_INVINCIBLE) && it.sprite)
-                               WaypointSprite_UpdateHealth(it.sprite, it.health);
+                               WaypointSprite_UpdateHealth(it.sprite, GetResourceAmount(it, RESOURCE_HEALTH));
                }
        });
 
@@ -271,7 +286,8 @@ 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), NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, this.enemy);
+       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);
 
        setanim(this, this.anim_shoot, true, true, true);
@@ -309,14 +325,14 @@ void M_Mage_Attack_Teleport(entity this, entity targ)
 void M_Mage_Defend_Shield_Remove(entity this)
 {
        this.effects &= ~(EF_ADDITIVE | EF_BLUE);
-       this.armorvalue = autocvar_g_monsters_armor_blockpercent;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 }
 
 void M_Mage_Defend_Shield(entity this)
 {
        this.effects |= (EF_ADDITIVE | EF_BLUE);
        this.mage_shield_delay = time + (autocvar_g_monster_mage_shield_delay);
-       this.armorvalue = (autocvar_g_monster_mage_shield_blockpercent);
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monster_mage_shield_blockpercent);
        this.mage_shield_time = time + (autocvar_g_monster_mage_shield_time);
        setanim(this, this.anim_shoot, true, true, true);
        this.attack_finished_single[0] = time + 1;
@@ -403,16 +419,16 @@ METHOD(Mage, mr_think, bool(Mage thismon, entity actor))
        });
     }
 
-    if(actor.health < (autocvar_g_monster_mage_heal_minhealth) || need_help)
+    if(GetResourceAmount(actor, RESOURCE_HEALTH) < (autocvar_g_monster_mage_heal_minhealth) || need_help)
     if(time >= actor.attack_finished_single[0])
     if(random() < 0.5)
         M_Mage_Defend_Heal(actor);
 
-    if(time >= actor.mage_shield_time && actor.armorvalue)
+    if(time >= actor.mage_shield_time && GetResourceAmount(actor, RESOURCE_ARMOR))
         M_Mage_Defend_Shield_Remove(actor);
 
     if(actor.enemy)
-    if(actor.health < actor.max_health)
+    if(GetResourceAmount(actor, RESOURCE_HEALTH) < actor.max_health)
     if(time >= actor.mage_shield_delay)
     if(random() < 0.5)
         M_Mage_Defend_Shield(actor);
@@ -453,7 +469,7 @@ METHOD(Mage, mr_anim, bool(Mage this, entity actor))
 METHOD(Mage, mr_setup, bool(Mage this, entity actor))
 {
     TC(Mage, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_mage_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_mage_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_mage_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_mage_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_mage_speed_stop); }
index 98fb7667341dc6e13a5cfc168e2d43e76258de6e..18f8f5963f2d9e704cbff2ebbf42618a41b024d4 100644 (file)
@@ -23,7 +23,7 @@ REGISTER_MONSTER(MAGE, NEW(Mage));
 #include <common/items/_mod.qh>
 
 CLASS(MageSpike, PortoLaunch)
-/* flags     */ ATTRIB(MageSpike, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(MageSpike, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MageSpike, impulse, int, 9);
 /* refname   */ ATTRIB(MageSpike, netname, string, "magespike");
 /* wepname   */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
index 338acacd61fdb343357451cc09c801526196cc2e..9981474f9bc7ad92a696dc9f8792d01a88cb0d15 100644 (file)
@@ -42,7 +42,7 @@ void M_Shambler_Attack_Smash(entity this)
        tracebox(this.origin + v_forward * 50, this.mins * 0.5, this.maxs * 0.5, this.origin + v_forward * autocvar_g_monster_shambler_attack_smash_range, MOVE_NORMAL, this);
 
        if(trace_ent.takedamage)
-               Damage(trace_ent, this, this, (autocvar_g_monster_shambler_attack_smash_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_SMASH.m_id, trace_ent.origin, normalize(trace_ent.origin - this.origin));
+               Damage(trace_ent, this, this, (autocvar_g_monster_shambler_attack_smash_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_SMASH.m_id, DMG_NOWEP, trace_ent.origin, normalize(trace_ent.origin - this.origin));
 }
 
 void M_Shambler_Attack_Swing(entity this)
@@ -66,12 +66,12 @@ void M_Shambler_Attack_Lightning_Explode(entity this, entity directhitentity)
                this.velocity = this.oldvelocity;
 
        RadiusDamage (this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_damage), (autocvar_g_monster_shambler_attack_lightning_radius),
-                                       NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, directhitentity);
+                                       NULL, NULL, (autocvar_g_monster_shambler_attack_lightning_force), this.projectiledeathtype, DMG_NOWEP, directhitentity);
 
        FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_shambler_attack_lightning_radius_zap, it != this.realowner && it.takedamage,
        {
                te_csqc_lightningarc(this.origin, it.origin);
-               Damage(it, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, it.origin, '0 0 0');
+               Damage(it, this, this.realowner, (autocvar_g_monster_shambler_attack_lightning_damage_zap) * MONSTER_SKILLMOD(this), DEATH_MONSTER_SHAMBLER_ZAP.m_id, DMG_NOWEP, it.origin, '0 0 0');
        });
 
        setthink(this, SUB_Remove);
@@ -83,17 +83,17 @@ void M_Shambler_Attack_Lightning_Explode_use(entity this, entity actor, entity t
        M_Shambler_Attack_Lightning_Explode(this, trigger);
 }
 
-void M_Shambler_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void M_Shambler_Attack_Lightning_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
 }
 
@@ -136,7 +136,7 @@ void M_Shambler_Attack_Lightning(entity this)
        settouch(gren, M_Shambler_Attack_Lightning_Touch);
 
        gren.takedamage = DAMAGE_YES;
-       gren.health = 50;
+       SetResourceAmountExplicit(gren, RESOURCE_HEALTH, 50);
        gren.damageforcescale = 0;
        gren.event_damage = M_Shambler_Attack_Lightning_Damage;
        gren.damagedbycontents = true;
@@ -246,7 +246,7 @@ METHOD(Shambler, mr_anim, bool(Shambler this, entity actor))
 METHOD(Shambler, mr_setup, bool(Shambler this, entity actor))
 {
     TC(Shambler, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_shambler_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_shambler_health);
     if(!actor.attack_range) actor.attack_range = 150;
     if(!actor.speed) { actor.speed = (autocvar_g_monster_shambler_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_shambler_speed_run); }
index a6551392075891911a85a9893a8e8c2cdf0dc62c..5e2cc0513851594d70a64167656be7196135500d 100644 (file)
@@ -66,7 +66,7 @@ METHOD(SpiderAttack, wr_think, void(SpiderAttack thiswep, entity actor, .entity
                        actor.anim_finished = time + 1;
                }
         if (isPlayer) actor.enemy = Monster_FindTarget(actor);
-        W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0);
+        W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_SpiderAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_SPIDER.m_id);
        if (!isPlayer) w_shotdir = normalize((actor.enemy.origin + '0 0 10') - actor.origin);
                M_Spider_Attack_Web(actor);
         weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, 0, w_ready);
@@ -101,9 +101,9 @@ void M_Spider_Attack_Web_Explode(entity this)
        if(this)
        {
                Send_Effect(EFFECT_ELECTRO_IMPACT, this.origin, '0 0 0', 1);
-               RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, NULL);
+               RadiusDamage(this, this.realowner, 0, 0, 25, NULL, NULL, 25, this.projectiledeathtype, DMG_NOWEP, NULL);
 
-               FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && it.health > 0 && it.monsterid != MON_SPIDER.monsterid,
+               FOREACH_ENTITY_RADIUS(this.origin, 25, it != this && it.takedamage && !IS_DEAD(it) && GetResourceAmount(it, RESOURCE_HEALTH) > 0 && it.monsterid != MON_SPIDER.monsterid,
                {
                        it.spider_slowness = time + (autocvar_g_monster_spider_attack_web_damagetime);
                });
@@ -151,7 +151,7 @@ void M_Spider_Attack_Web(entity this)
        setsize(proj, '-4 -4 -4', '4 4 4');
        proj.takedamage = DAMAGE_NO;
        proj.damageforcescale = 0;
-       proj.health = 500;
+       SetResourceAmountExplicit(proj, RESOURCE_HEALTH, 500);
        proj.event_damage = func_null;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
@@ -227,7 +227,7 @@ METHOD(Spider, mr_anim, bool(Spider this, entity actor))
 METHOD(Spider, mr_setup, bool(Spider this, entity actor))
 {
     TC(Spider, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_spider_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_spider_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_spider_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_spider_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_spider_speed_stop); }
index 3a688de32efce0e1282543bd3e85a55d4563c26b..908f0f942070cd758715adbf72024759e248d62d 100644 (file)
@@ -22,7 +22,7 @@ REGISTER_MONSTER(SPIDER, NEW(Spider));
 #include <common/weapons/_all.qh>
 
 CLASS(SpiderAttack, PortoLaunch)
-/* flags     */ ATTRIB(SpiderAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(SpiderAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(SpiderAttack, impulse, int, 9);
 /* refname   */ ATTRIB(SpiderAttack, netname, string, "spider");
 /* wepname   */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
index 38df673dd1c161d267a4ceeee9b5c63edbf43ae5..f6c905d6d1893bcd4d1d3f134e28d62799da3ae7 100644 (file)
@@ -18,7 +18,7 @@ METHOD(WyvernAttack, wr_think, void(WyvernAttack thiswep, entity actor, .entity
     TC(WyvernAttack, thiswep);
     if (fire & 1)
     if (time > actor.attack_finished_single[0] || weapon_prepareattack(thiswep, actor, weaponentity, false, 1.2)) {
-        if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WyvernAttack_FIRE, CH_WEAPON_B, 0);
+        if (IS_PLAYER(actor)) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WyvernAttack_FIRE, CH_WEAPON_B, 0, DEATH_MONSTER_WYVERN.m_id);
                if (IS_MONSTER(actor)) {
                        actor.attack_finished_single[0] = time + 1.2;
                        actor.anim_finished = time + 1.2;
@@ -71,7 +71,8 @@ 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, NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, NULL);
+       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,
        {
@@ -151,7 +152,7 @@ METHOD(Wyvern, mr_anim, bool(Wyvern this, entity actor))
 METHOD(Wyvern, mr_setup, bool(Wyvern this, entity actor))
 {
     TC(Wyvern, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_wyvern_health);
+    if(!GetResourceAmount(this, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_wyvern_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_wyvern_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_wyvern_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_wyvern_speed_stop); }
index 2326b0dd1157c27a8cb39e0ee5610dad9e0eb25d..2c5df05646e4a1615a12485fe849d06f02d09f6c 100644 (file)
@@ -22,7 +22,7 @@ REGISTER_MONSTER(WYVERN, NEW(Wyvern));
 #include <common/weapons/_all.qh>
 
 CLASS(WyvernAttack, PortoLaunch)
-/* flags     */ ATTRIB(WyvernAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(WyvernAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(WyvernAttack, impulse, int, 9);
 /* refname   */ ATTRIB(WyvernAttack, netname, string, "wyvern");
 /* wepname   */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
index d5011c7f35ca726b0e074244d871b985a881caa0..aaa27d21b2894ed7e86a6fe021993c041b164db4 100644 (file)
@@ -51,7 +51,7 @@ const float zombie_anim_spawn                         = 30;
 
 void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
 {
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        vector angles_face;
@@ -60,7 +60,7 @@ void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
        {
                angles_face = vectoangles(this.moveto - this.origin);
                angles_face = normalize(angles_face) * (autocvar_g_monster_zombie_attack_leap_force);
-               Damage(toucher, this, this, (autocvar_g_monster_zombie_attack_leap_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_ZOMBIE_JUMP.m_id, toucher.origin, angles_face);
+               Damage(toucher, this, this, (autocvar_g_monster_zombie_attack_leap_damage) * MONSTER_SKILLMOD(this), DEATH_MONSTER_ZOMBIE_JUMP.m_id, DMG_NOWEP, toucher.origin, angles_face);
                settouch(this, Monster_Touch); // instantly turn it off to stop damage spam
                this.state = 0;
        }
@@ -74,16 +74,16 @@ void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
 
 void M_Zombie_Defend_Block_End(entity this)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        setanim(this, this.anim_blockend, false, true, true);
-       this.armorvalue = autocvar_g_monsters_armor_blockpercent;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 }
 
 bool M_Zombie_Defend_Block(entity this)
 {
-       this.armorvalue = 0.9;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, 0.9);
        this.state = MONSTER_ATTACK_MELEE; // freeze monster
        this.attack_finished_single[0] = time + 2.1;
        this.anim_finished = this.attack_finished_single[0];
@@ -100,7 +100,7 @@ bool M_Zombie_Attack(int attack_type, entity actor, entity targ, .entity weapone
        {
                case MONSTER_ATTACK_MELEE:
                {
-                       if(random() < 0.3 && actor.health < 75 && actor.enemy.health > 10)
+                       if(random() < 0.3 && GetResourceAmount(actor, RESOURCE_HEALTH) < 75 && GetResourceAmount(actor.enemy, RESOURCE_HEALTH) > 10)
                                return M_Zombie_Defend_Block(actor);
 
                        float anim_chance = random();
@@ -148,7 +148,7 @@ METHOD(Zombie, mr_pain, float(Zombie this, entity actor, float damage_take, enti
 METHOD(Zombie, mr_death, bool(Zombie this, entity actor))
 {
     TC(Zombie, this);
-    actor.armorvalue = autocvar_g_monsters_armor_blockpercent;
+    SetResourceAmountExplicit(actor, RESOURCE_ARMOR, autocvar_g_monsters_armor_blockpercent);
 
     setanim(actor, ((random() > 0.5) ? actor.anim_die1 : actor.anim_die2), false, true, true);
     return true;
@@ -180,7 +180,7 @@ METHOD(Zombie, mr_anim, bool(Zombie this, entity actor))
 METHOD(Zombie, mr_setup, bool(Zombie this, entity actor))
 {
     TC(Zombie, this);
-    if(!actor.health) actor.health = (autocvar_g_monster_zombie_health);
+    if(!GetResourceAmount(actor, RESOURCE_HEALTH)) SetResourceAmountExplicit(actor, RESOURCE_HEALTH, autocvar_g_monster_zombie_health);
     if(!actor.speed) { actor.speed = (autocvar_g_monster_zombie_speed_walk); }
     if(!actor.speed2) { actor.speed2 = (autocvar_g_monster_zombie_speed_run); }
     if(!actor.stopspeed) { actor.stopspeed = (autocvar_g_monster_zombie_speed_stop); }
index 15fba0134200deccbfacf77b8f70af222558ef4f..84355c7f3530ffddcf3dccde86781d487c7fd717 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,9 +81,10 @@ 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))
+       || (!IS_VEHICLE(targ) && (IS_DEAD(targ) || IS_DEAD(this) || GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(this, RESOURCE_HEALTH) <= 0))
        || (this.monster_follow == targ || targ.monster_follow == this)
        || (!IS_VEHICLE(targ) && (targ.flags & FL_NOTARGET))
        || (!autocvar_g_monsters_typefrag && PHYS_INPUT_BUTTON_CHAT(targ))
@@ -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;
@@ -339,9 +337,8 @@ void Monster_Sound(entity this, .string samplefield, float sound_delay, bool del
        string sample = this.(samplefield);
        if (sample != "") sample = GlobalSound_sample(sample, random());
        float myscale = ((this.scale) ? this.scale : 1); // safety net
-       float scale_inverse = 1 / myscale;
        // TODO: change volume depending on size too?
-       sound7(this, chan, sample, VOL_BASE, ATTEN_NORM, scale_inverse * 100, 0);
+       sound7(this, chan, sample, VOL_BASE, ATTEN_NORM, 100 / myscale, 0);
 
        this.msound_delay = time + sound_delay;
 }
@@ -367,7 +364,7 @@ bool Monster_Attack_Melee(entity this, entity targ, float damg, vector anim, flo
        traceline(this.origin + this.view_ofs, this.origin + v_forward * er, 0, this);
 
        if(trace_ent.takedamage)
-               Damage(trace_ent, this, this, damg * MONSTER_SKILLMOD(this), deathtype, trace_ent.origin, normalize(trace_ent.origin - this.origin));
+               Damage(trace_ent, this, this, damg * MONSTER_SKILLMOD(this), deathtype, DMG_NOWEP, trace_ent.origin, normalize(trace_ent.origin - this.origin));
 
        return true;
 }
@@ -378,7 +375,7 @@ bool Monster_Attack_Leap_Check(entity this, vector vel)
                return false; // already attacking
        if(!IS_ONGROUND(this))
                return false; // not on the ground
-       if(this.health <= 0 || IS_DEAD(this))
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0 || IS_DEAD(this))
                return false; // called when dead?
        if(time < this.attack_finished_single[0])
                return false; // still attacking
@@ -489,7 +486,7 @@ void Monster_Miniboss_Check(entity this)
        // g_monsters_miniboss_chance cvar or spawnflags 64 causes a monster to be a miniboss
        if ((this.spawnflags & MONSTERFLAG_MINIBOSS) || (chance < autocvar_g_monsters_miniboss_chance))
        {
-               this.health += autocvar_g_monsters_miniboss_healthboost;
+               GiveResource(this, RESOURCE_HEALTH, autocvar_g_monsters_miniboss_healthboost);
                this.effects |= EF_RED;
                if(!this.weapon)
                        this.weapon = WEP_VORTEX.m_id;
@@ -530,10 +527,11 @@ void Monster_Dead_Fade(entity this)
                        this.pos2 = this.angles;
                }
                this.event_damage = func_null;
+               this.event_heal = func_null;
                this.takedamage = DAMAGE_NO;
                setorigin(this, this.pos1);
                this.angles = this.pos2;
-               this.health = this.max_health;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
                setmodel(this, MDL_Null);
        }
        else
@@ -562,7 +560,7 @@ vector Monster_Move_Target(entity this, entity targ)
 
                // cases where the enemy may have changed their state (don't need to check everything here)
                if((!this.enemy)
-                       || (IS_DEAD(this.enemy) || this.enemy.health < 1)
+                       || (IS_DEAD(this.enemy) || GetResourceAmount(this.enemy, RESOURCE_HEALTH) < 1)
                        || (STAT(FROZEN, this.enemy))
                        || (this.enemy.flags & FL_NOTARGET)
                        || (this.enemy.alpha < 0.5 && this.enemy.alpha != 0)
@@ -720,7 +718,7 @@ void Monster_Move(entity this, float runspeed, float walkspeed, float stpspeed)
                        {
                                this.last_trace = time + 0.4;
 
-                               Damage (this, NULL, NULL, 2, DEATH_DROWN.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, 2, DEATH_DROWN.m_id, DMG_NOWEP, this.origin, '0 0 0');
                                this.angles = '90 90 0';
                                if(random() < 0.5)
                                {
@@ -899,7 +897,7 @@ void Monster_Reset(entity this)
 
        Unfreeze(this); // remove any icy remains
 
-       this.health = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.velocity = '0 0 0';
        this.enemy = NULL;
        this.goalentity = NULL;
@@ -907,13 +905,13 @@ void Monster_Reset(entity this)
        this.moveto = this.origin;
 }
 
-void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void Monster_Dead_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
        Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
-       if(this.health <= -50) // 100 health until gone?
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= -50) // 100 health until gone?
        {
                Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
@@ -935,7 +933,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
        if(STAT(FROZEN, this))
        {
                Unfreeze(this); // remove any icy remains
-               this.health = 0; // reset by Unfreeze
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // reset by Unfreeze (TODO)
        }
 
        monster_dropitem(this, attacker);
@@ -959,6 +957,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
                _setmodel(this, this.mdl_dead);
 
        this.event_damage       = ((gibbed) ? func_null : Monster_Dead_Damage);
+       this.event_heal         = func_null;
        this.solid                      = SOLID_CORPSE;
        this.takedamage         = DAMAGE_AIM;
        this.deadflag           = DEAD_DEAD;
@@ -986,7 +985,7 @@ void Monster_Dead(entity this, entity attacker, float gibbed)
        }
 }
 
-void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void Monster_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if((this.spawnflags & MONSTERFLAG_INVINCIBLE) && deathtype != DEATH_KILL.m_id && !ITEM_DAMAGE_NEEDKILL(deathtype))
                return;
@@ -1003,7 +1002,7 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
        if(deathtype == DEATH_FALL.m_id && this.draggedby != NULL)
                return;
 
-       vector v = healtharmor_applydamage(100, this.armorvalue / 100, deathtype, damage);
+       vector v = healtharmor_applydamage(100, GetResourceAmount(this, RESOURCE_ARMOR) / 100, deathtype, damage);
        float take = v.x;
        //float save = v.y;
 
@@ -1012,12 +1011,12 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
 
        if(take)
        {
-               this.health -= take;
+               TakeResource(this, RESOURCE_HEALTH, take);
                Monster_Sound(this, monstersound_pain, 1.2, true, CH_PAIN);
        }
 
        if(this.sprite)
-               WaypointSprite_UpdateHealth(this.sprite, this.health);
+               WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
        this.dmg_time = time;
 
@@ -1035,7 +1034,7 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
                        Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
        }
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                if(deathtype == DEATH_KILL.m_id)
                        this.candrop = false; // killed by mobkill command
@@ -1044,13 +1043,13 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
                SUB_UseTargets(this, attacker, this.enemy);
                this.target2 = this.oldtarget2; // reset to original target on death, incase we respawn
 
-               Monster_Dead(this, attacker, (this.health <= -100 || deathtype == DEATH_KILL.m_id));
+               Monster_Dead(this, attacker, (GetResourceAmount(this, RESOURCE_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id));
 
                WaypointSprite_Kill(this.sprite);
 
                MUTATOR_CALLHOOK(MonsterDies, this, attacker, deathtype);
 
-               if(this.health <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= -100 || deathtype == DEATH_KILL.m_id) // check if we're already gibbed
                {
                        Violence_GibSplash(this, 1, 0.5, attacker);
 
@@ -1060,6 +1059,18 @@ void Monster_Damage(entity this, entity inflictor, entity attacker, float damage
        }
 }
 
+bool Monster_Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       if(targ.sprite)
+               WaypointSprite_UpdateHealth(targ.sprite, GetResourceAmount(targ, RESOURCE_HEALTH));
+       return true;
+}
+
 // don't check for enemies, just keep walking in a straight line
 void Monster_Move_2D(entity this, float mspeed, bool allow_jumpoff)
 {
@@ -1152,33 +1163,33 @@ void Monster_Frozen_Think(entity this)
 {
        if(STAT(FROZEN, this) == 2)
        {
-               this.revive_progress = bound(0, this.revive_progress + this.ticrate * this.revive_speed, 1);
-               this.health = max(1, this.revive_progress * this.max_health);
-               this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1);
+               STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) + this.ticrate * this.revive_speed, 1);
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, this) * this.max_health));
+               this.iceblock.alpha = bound(0.2, 1 - STAT(REVIVE_PROGRESS, this), 1);
 
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite)
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
-               if(this.revive_progress >= 1)
+               if(STAT(REVIVE_PROGRESS, this) >= 1)
                        Unfreeze(this);
        }
        else if(STAT(FROZEN, this) == 3)
        {
-               this.revive_progress = bound(0, this.revive_progress - this.ticrate * this.revive_speed, 1);
-               this.health = max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * this.revive_progress );
+               STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) - this.ticrate * this.revive_speed, 1);
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(0, autocvar_g_nades_ice_health + (this.max_health-autocvar_g_nades_ice_health) * STAT(REVIVE_PROGRESS, this)));
 
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE) && this.sprite)
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
 
-               if(this.health < 1)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) < 1)
                {
                        Unfreeze(this);
-                       this.health = 0;
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
                        if(this.event_damage)
-                               this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0');
+                               this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, DMG_NOWEP, this.origin, '0 0 0');
                }
 
-               else if ( this.revive_progress <= 0 )
+               else if ( STAT(REVIVE_PROGRESS, this) <= 0 )
                        Unfreeze(this);
        }
        // otherwise, no revival!
@@ -1213,7 +1224,7 @@ void Monster_Think(entity this)
 
        if(this.monster_lifetime && time >= this.monster_lifetime)
        {
-               Damage(this, this, this, this.health + this.max_health, DEATH_KILL.m_id, this.origin, this.origin);
+               Damage(this, this, this, GetResourceAmount(this, RESOURCE_HEALTH) + this.max_health, DEATH_KILL.m_id, DMG_NOWEP, this.origin, this.origin);
                return;
        }
 
@@ -1245,8 +1256,8 @@ bool Monster_Spawn_Setup(entity this)
        mon.mr_setup(mon, this);
 
        // ensure some basic needs are met
-       if(!this.health) { this.health = 100; }
-       if(!this.armorvalue) { this.armorvalue = bound(0.2, 0.5 * MONSTER_SKILLMOD(this), 0.9); }
+       if(!GetResourceAmount(this, RESOURCE_HEALTH)) { SetResourceAmountExplicit(this, RESOURCE_HEALTH, 100); }
+       if(!GetResourceAmount(this, RESOURCE_ARMOR)) { SetResourceAmountExplicit(this, RESOURCE_ARMOR, bound(0.2, 0.5 * MONSTER_SKILLMOD(this), 0.9)); }
        if(!this.target_range) { this.target_range = autocvar_g_monsters_target_range; }
        if(!this.respawntime) { this.respawntime = autocvar_g_monsters_respawn_delay; }
        if(!this.monster_moveflags) { this.monster_moveflags = MONSTER_MOVE_WANDER; }
@@ -1256,13 +1267,13 @@ bool Monster_Spawn_Setup(entity this)
        if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
        {
                Monster_Miniboss_Check(this);
-               this.health *= MONSTER_SKILLMOD(this);
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH) * MONSTER_SKILLMOD(this));
 
                if(!this.skin)
                        this.skin = rint(random() * 4);
        }
 
-       this.max_health = this.health;
+       this.max_health = GetResourceAmount(this, RESOURCE_HEALTH);
        this.pain_finished = this.nextthink;
 
        if(IS_PLAYER(this.monster_follow))
@@ -1291,7 +1302,7 @@ bool Monster_Spawn_Setup(entity this)
                if(!(this.spawnflags & MONSTERFLAG_INVINCIBLE))
                {
                        WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
-                       WaypointSprite_UpdateHealth(this.sprite, this.health);
+                       WaypointSprite_UpdateHealth(this.sprite, GetResourceAmount(this, RESOURCE_HEALTH));
                }
        }
 
@@ -1356,6 +1367,7 @@ bool Monster_Spawn(entity this, bool check_appear, int mon_id)
        this.damagedbycontents  = true;
        this.monsterid                  = mon_id;
        this.event_damage               = Monster_Damage;
+       this.event_heal                 = Monster_Heal;
        settouch(this, Monster_Touch);
        this.use                                = Monster_Use;
        this.solid                              = SOLID_BBOX;
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 107a82030c1f99d76d2aa1140d207c3798a0e150..cf858487058de2bbeac734fff836481bae3e4504 100644 (file)
@@ -65,6 +65,7 @@ MUTATOR_HOOKABLE(IsFlying, EV_IsFlying);
     /**/ i(string, MUTATOR_ARGV_1_string) \
     /**/ o(vector, MUTATOR_ARGV_2_vector) \
     /**/ o(string, MUTATOR_ARGV_3_string) \
+    /**/ o(string, MUTATOR_ARGV_4_string) \
     /**/
 MUTATOR_HOOKABLE(WP_Format, EV_WP_Format);
 
index 9d52fa20c44af25537d2b11bf68b04b2020cac0c..40a763c8ec04b39b9a39dfb3d8d915bf647e1324 100644 (file)
@@ -22,6 +22,7 @@
 #include <common/mutators/mutator/nades/_mod.inc>
 #include <common/mutators/mutator/new_toys/_mod.inc>
 #include <common/mutators/mutator/nix/_mod.inc>
+#include <common/mutators/mutator/offhand_blaster/_mod.inc>
 #include <common/mutators/mutator/overkill/_mod.inc>
 #include <common/mutators/mutator/physical_items/_mod.inc>
 #include <common/mutators/mutator/pinata/_mod.inc>
index f9edf4c56c47868e01161b34793a5c05e33f64d9..6a9261dd41f394cd3496bf119ec6fa92e6ebb0f1 100644 (file)
@@ -22,6 +22,7 @@
 #include <common/mutators/mutator/nades/_mod.qh>
 #include <common/mutators/mutator/new_toys/_mod.qh>
 #include <common/mutators/mutator/nix/_mod.qh>
+#include <common/mutators/mutator/offhand_blaster/_mod.qh>
 #include <common/mutators/mutator/overkill/_mod.qh>
 #include <common/mutators/mutator/physical_items/_mod.qh>
 #include <common/mutators/mutator/pinata/_mod.qh>
index 1164e0ade66efd9dcf05c924fa76ff109dcd0e65..99093d16b1cb351347e4ca38b09476ee07790882 100644 (file)
@@ -19,7 +19,7 @@ MUTATOR_HOOKFUNCTION(bloodloss, PlayerPreThink)
                        if(player.vehicle)
                                vehicles_exit(player.vehicle, VHEF_RELEASE);
                        if(player.event_damage)
-                               player.event_damage(player, player, player, 1, DEATH_ROT.m_id, player.origin, '0 0 0');
+                               player.event_damage(player, player, player, 1, DEATH_ROT.m_id, DMG_NOWEP, player.origin, '0 0 0');
                        player.bloodloss_timer = time + 0.5 + random() * 0.5;
                }
        }
index ee1ca94b50dbecc85afa67911041d18d72356d9f..dc1bfefc264b20d7cd9f6606723facb78bee9980 100644 (file)
@@ -22,7 +22,7 @@ MUTATOR_HOOKFUNCTION(breakablehook, Damage_Calculate)
                // hurt the owner of the hook
                if(DIFF_TEAM(frag_attacker, frag_target.realowner))
                {
-                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, frag_target.realowner.origin, '0 0 0');
+                       Damage (frag_target.realowner, frag_attacker, frag_attacker, 5, WEP_HOOK.m_id | HITTYPE_SPLASH, DMG_NOWEP, frag_target.realowner.origin, '0 0 0'); // TODO: should get weapon entity from mutator hook
                        RemoveHook(frag_target);
                        return; // dead
                }
index 81a638ea7c300f07edffdeadfadd3dd980388d68..35005e7a8fea65285d869afd82a8f247da833f78 100644 (file)
@@ -4,7 +4,7 @@
 #include <common/util.qh>
 
 #ifdef GAMEQC
-REGISTER_WAYPOINT(Buff, _("Buff"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(Buff, _("Buff"), "", '1 0.5 0', 1);
 REGISTER_RADARICON(Buff, 1);
 #endif
 
@@ -43,11 +43,10 @@ STATIC_INIT(REGISTER_BUFFS) {
 }
 
 #ifdef SVQC
-       // .int buffs = _STAT(BUFFS);
        void buff_Init(entity ent);
        void buff_Init_Compat(entity ent, entity replacement);
        #define BUFF_SPAWNFUNC(e, b, t) spawnfunc(item_buff_##e) { \
-               this.buffs = b.m_itemid; \
+               STAT(BUFFS, this) = b.m_itemid; \
                this.team = t; \
                buff_Init(this); \
        }
@@ -65,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 a46a92d0aecdbfebfb844c0cc59610952dbbdf2d..f751eecff091ff08e775bde798813d748fdb0b2f 100644 (file)
@@ -17,6 +17,7 @@ MUTATOR_HOOKFUNCTION(cl_buffs, WP_Format)
         Buff b = Buffs_from(this.wp_extra);
         M_ARGV(2, vector) = b.m_color;
         M_ARGV(3, string) = b.m_prettyName;
+        M_ARGV(4, string) = strcat("buff_", b.m_name);
         return true;
     }
 }
index 6994c81761ad8ac68f289516ea405eda1a75f7c4..27f71b56c24ee02f88798ed51e214c15a5b05127 100644 (file)
@@ -1,9 +1,8 @@
 #include "sv_buffs.qh"
 
-#include <common/triggers/target/music.qh>
+#include <common/mapobjects/target/music.qh>
 #include <common/gamemodes/_mod.qh>
 
-.float buff_time = _STAT(BUFF_TIME);
 void buffs_DelayedInit(entity this);
 
 AUTOCVAR(g_buffs, int, -1, "Enable buffs, -1: enabled but no auto location or replacing powerups, 1: enabled and can replace them");
@@ -83,9 +82,9 @@ bool buff_Waypoint_visible_for_player(entity this, entity player, entity view)
        if(!this.owner.buff_active && !this.owner.buff_activetime)
                return false;
 
-       if (view.buffs)
+       if (STAT(BUFFS, view))
        {
-               return CS(view).cvar_cl_buffs_autoreplace == false || view.buffs != this.owner.buffs;
+               return CS(view).cvar_cl_buffs_autoreplace == false || STAT(BUFFS, view) != STAT(BUFFS, this.owner);
        }
 
        return WaypointSprite_visible_for_player(this, player, view);
@@ -93,7 +92,7 @@ bool buff_Waypoint_visible_for_player(entity this, entity player, entity view)
 
 void buff_Waypoint_Spawn(entity e)
 {
-       entity buff = buff_FirstFromFlags(e.buffs);
+       entity buff = buff_FirstFromFlags(STAT(BUFFS, e));
        entity wp = WaypointSprite_Spawn(WP_Buff, 0, autocvar_g_buffs_waypoint_distance, e, '0 0 1' * e.maxs.z, NULL, e.team, e, buff_waypoint, true, RADARICON_Buff);
        wp.wp_extra = buff.m_id;
        WaypointSprite_UpdateTeamRadar(e.buff_waypoint, RADARICON_Buff, e.glowmod);
@@ -177,15 +176,15 @@ void buff_Touch(entity this, entity toucher)
                return;
        }
 
-       if (toucher.buffs)
+       if (STAT(BUFFS, toucher))
        {
-               if (CS(toucher).cvar_cl_buffs_autoreplace && toucher.buffs != this.buffs)
+               if (CS(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
                {
-                       int buffid = buff_FirstFromFlags(toucher.buffs).m_id;
-                       //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, toucher.buffs);
+                       int buffid = buff_FirstFromFlags(STAT(BUFFS, toucher)).m_id;
+                       //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, STAT(BUFFS, toucher));
                        Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
 
-                       toucher.buffs = 0;
+                       STAT(BUFFS, toucher) = 0;
                        //sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
                }
                else { return; } // do nothing
@@ -194,13 +193,13 @@ void buff_Touch(entity this, entity toucher)
        this.owner = toucher;
        this.buff_active = false;
        this.lifetime = 0;
-       int buffid = buff_FirstFromFlags(this.buffs).m_id;
+       int buffid = buff_FirstFromFlags(STAT(BUFFS, this)).m_id;
        Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
        Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
 
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
        sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
-       toucher.buffs |= (this.buffs);
+       STAT(BUFFS, toucher) |= (STAT(BUFFS, this));
 }
 
 float buff_Available(entity buff)
@@ -226,14 +225,14 @@ void buff_NewType(entity ent)
        });
        entity newbuff = RandomSelection_chosen_ent;
        newbuff.buff_seencount += 1; // lower chances of seeing this buff again soon
-       ent.buffs = newbuff.m_itemid;
+       STAT(BUFFS, ent) = newbuff.m_itemid;
 }
 
 void buff_Think(entity this)
 {
-       if(this.buffs != this.oldbuffs)
+       if(STAT(BUFFS, this) != this.oldbuffs)
        {
-               entity buff = buff_FirstFromFlags(this.buffs);
+               entity buff = buff_FirstFromFlags(STAT(BUFFS, this));
                this.color = buff.m_color;
                this.glowmod = buff_GlowColor(buff);
                this.skin = buff.m_skin;
@@ -250,7 +249,7 @@ void buff_Think(entity this)
                                WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + this.buff_activetime - frametime);
                }
 
-               this.oldbuffs = this.buffs;
+               this.oldbuffs = STAT(BUFFS, this);
        }
 
        if(!game_stopped)
@@ -262,7 +261,7 @@ void buff_Think(entity this)
        }
 
        if(!this.buff_active && !this.buff_activetime)
-       if(!this.owner || STAT(FROZEN, this.owner) || IS_DEAD(this.owner) || !this.owner.iscreature || this.owner.vehicle || !(this.owner.buffs & this.buffs) || this.pickup_anyway > 0 || (this.pickup_anyway >= 0 && autocvar_g_buffs_pickup_anyway))
+       if(!this.owner || STAT(FROZEN, this.owner) || IS_DEAD(this.owner) || !this.owner.iscreature || this.owner.vehicle || !(STAT(BUFFS, this.owner) & STAT(BUFFS, this)) || this.pickup_anyway > 0 || (this.pickup_anyway >= 0 && autocvar_g_buffs_pickup_anyway))
        {
                buff_SetCooldown(this, autocvar_g_buffs_cooldown_respawn + frametime);
                this.owner = NULL;
@@ -346,9 +345,9 @@ void buff_Init(entity this)
 
        if(!teamplay && this.team) { this.team = 0; }
 
-       entity buff = buff_FirstFromFlags(this.buffs);
+       entity buff = buff_FirstFromFlags(STAT(BUFFS, this));
 
-       if(!this.buffs || !buff_Available(buff))
+       if(!STAT(BUFFS, this) || !buff_Available(buff))
                buff_NewType(this);
 
        this.classname = "item_buff";
@@ -396,7 +395,7 @@ void buff_Init_Compat(entity ent, entity replacement)
        else if (ent.spawnflags & 4)
                ent.team = NUM_TEAM_2;
 
-       ent.buffs = replacement.m_itemid;
+       STAT(BUFFS, ent) = replacement.m_itemid;
 
        buff_Init(ent);
 }
@@ -405,7 +404,7 @@ void buff_SpawnReplacement(entity ent, entity old)
 {
        setorigin(ent, old.origin);
        ent.angles = old.angles;
-       ent.noalign = (old.noalign || (old.spawnflags & 1));
+       ent.noalign = Item_ShouldKeepPosition(old);
 
        buff_Init(ent);
 }
@@ -413,7 +412,7 @@ void buff_SpawnReplacement(entity ent, entity old)
 void buff_Vengeance_DelayedDamage(entity this)
 {
        if(this.enemy)
-               Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
+               Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, DMG_NOWEP, this.enemy.origin, '0 0 0');
 
        delete(this);
        return;
@@ -454,28 +453,28 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
 
        if(frag_deathtype == DEATH_BUFF.m_id) { return; }
 
-       if(frag_target.buffs & BUFF_RESISTANCE.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_RESISTANCE.m_itemid)
        {
                float reduced = frag_damage * autocvar_g_buffs_resistance_blockpercent;
                frag_damage = bound(0, frag_damage - reduced, frag_damage);
        }
 
-       if(frag_target.buffs & BUFF_SPEED.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_SPEED.m_itemid)
        if(frag_target != frag_attacker)
                frag_damage *= autocvar_g_buffs_speed_damage_take;
 
-       if(frag_target.buffs & BUFF_MEDIC.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_MEDIC.m_itemid)
        if((GetResourceAmount(frag_target, RESOURCE_HEALTH) - frag_damage) <= 0)
        if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
        if(frag_attacker)
        if(random() <= autocvar_g_buffs_medic_survive_chance)
                frag_damage = max(5, GetResourceAmount(frag_target, RESOURCE_HEALTH) - autocvar_g_buffs_medic_survive_health);
 
-       if(frag_target.buffs & BUFF_JUMP.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_JUMP.m_itemid)
        if(frag_deathtype == DEATH_FALL.m_id)
                frag_damage = 0;
 
-       if(frag_target.buffs & BUFF_VENGEANCE.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_VENGEANCE.m_itemid)
        if(frag_attacker)
        if(frag_attacker != frag_target)
        if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
@@ -489,22 +488,22 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
                dmgent.nextthink = time + 0.1;
        }
 
-       if(frag_target.buffs & BUFF_BASH.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_BASH.m_itemid)
        if(frag_attacker != frag_target)
                frag_force = '0 0 0';
 
-       if(frag_attacker.buffs & BUFF_BASH.m_itemid)
+       if(STAT(BUFFS, frag_attacker) & BUFF_BASH.m_itemid)
        if(frag_force)
        if(frag_attacker == frag_target)
                frag_force *= autocvar_g_buffs_bash_force_self;
        else
                frag_force *= autocvar_g_buffs_bash_force;
 
-       if(frag_attacker.buffs & BUFF_DISABILITY.m_itemid)
+       if(STAT(BUFFS, frag_attacker) & BUFF_DISABILITY.m_itemid)
        if(frag_target != frag_attacker)
                frag_target.buff_disability_time = time + autocvar_g_buffs_disability_slowtime;
 
-       if(frag_target.buffs & BUFF_INFERNO.m_itemid)
+       if(STAT(BUFFS, frag_target) & BUFF_INFERNO.m_itemid)
        {
                if(frag_deathtype == DEATH_FIRE.m_id)
                        frag_damage = 0;
@@ -512,13 +511,13 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
                        frag_damage *= 0.5; // TODO: cvarize?
        }
 
-       if(frag_attacker.buffs & BUFF_LUCK.m_itemid)
+       if(STAT(BUFFS, frag_attacker) & BUFF_LUCK.m_itemid)
        if(frag_attacker != frag_target)
        if(autocvar_g_buffs_luck_damagemultiplier > 0)
        if(random() <= autocvar_g_buffs_luck_chance)
                frag_damage *= autocvar_g_buffs_luck_damagemultiplier;
 
-       if(frag_attacker.buffs & BUFF_INFERNO.m_itemid)
+       if(STAT(BUFFS, frag_attacker) & BUFF_INFERNO.m_itemid)
        if(frag_target != frag_attacker) {
                float btime = buff_Inferno_CalculateTime(
                        frag_damage,
@@ -532,7 +531,7 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
        }
 
        // this... is ridiculous (TODO: fix!)
-       if(frag_attacker.buffs & BUFF_VAMPIRE.m_itemid)
+       if(STAT(BUFFS, frag_attacker) & BUFF_VAMPIRE.m_itemid)
        if(!frag_target.vehicle)
        if(!ITEM_DAMAGE_NEEDKILL(frag_deathtype))
        if(!IS_DEAD(frag_target))
@@ -545,7 +544,7 @@ MUTATOR_HOOKFUNCTION(buffs, Damage_Calculate)
                float amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
                        GetResourceAmount(frag_target, RESOURCE_HEALTH));
                GiveResourceWithLimit(frag_attacker, RESOURCE_HEALTH, amount, g_pickup_healthsmall_max);
-               if (frag_target.armorvalue)
+               if (GetResourceAmount(frag_target, RESOURCE_ARMOR))
                {
                        amount = bound(0, frag_damage * autocvar_g_buffs_vampire_damage_steal,
                                GetResourceAmount(frag_target, RESOURCE_ARMOR));
@@ -561,8 +560,8 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerSpawn)
 {
        entity player = M_ARGV(0, entity);
 
-       player.buffs = 0;
-       player.buff_time = 0;
+       STAT(BUFFS, player) = 0;
+       STAT(BUFF_TIME, player) = 0;
        PS(player).buff_shield = time + 0.5; // prevent picking up buffs immediately
        // reset timers here to prevent them continuing after re-spawn
        player.buff_disability_time = 0;
@@ -574,7 +573,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics_UpdateStats)
        entity player = M_ARGV(0, entity);
        // these automatically reset, no need to worry
 
-       if(player.buffs & BUFF_SPEED.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_SPEED.m_itemid)
                STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_buffs_speed_speed;
 
        if(time < player.buff_disability_time)
@@ -586,7 +585,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPhysics)
        entity player = M_ARGV(0, entity);
        // these automatically reset, no need to worry
 
-       if(player.buffs & BUFF_JUMP.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_JUMP.m_itemid)
                STAT(MOVEVARS_JUMPVELOCITY, player) = autocvar_g_buffs_jump_height;
 }
 
@@ -605,11 +604,11 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerDies)
 {
        entity frag_target = M_ARGV(2, entity);
 
-       if(frag_target.buffs)
+       if(STAT(BUFFS, frag_target))
        {
-               int buffid = buff_FirstFromFlags(frag_target.buffs).m_id;
+               int buffid = buff_FirstFromFlags(STAT(BUFFS, frag_target)).m_id;
                Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
-               frag_target.buffs = 0;
+               STAT(BUFFS, frag_target) = 0;
 
                if(frag_target.buff_model)
                {
@@ -625,15 +624,15 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerUseKey, CBC_ORDER_FIRST)
 
        entity player = M_ARGV(0, entity);
 
-       if(player.buffs)
+       if(STAT(BUFFS, player))
        {
-               int buffid = buff_FirstFromFlags(player.buffs).m_id;
+               int buffid = buff_FirstFromFlags(STAT(BUFFS, player)).m_id;
                Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
                Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
 
-               player.buffs = 0;
+               STAT(BUFFS, player) = 0;
                PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
-               //player.buff_time = 0; // already notified
+               //STAT(BUFF_TIME, player) = 0; // already notified
                sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
                return true;
        }
@@ -644,7 +643,7 @@ MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
        if(MUTATOR_RETURNVALUE || game_stopped) return;
        entity player = M_ARGV(0, entity);
 
-       if(player.buffs & BUFF_SWAPPER.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_SWAPPER.m_itemid)
        {
                float best_distance = autocvar_g_buffs_swapper_range;
                entity closest = NULL;
@@ -702,7 +701,7 @@ MUTATOR_HOOKFUNCTION(buffs, ForbidThrowCurrentWeapon)
                        sound(closest, CH_TRIGGER, SND_KA_RESPAWN, VOL_BASE, ATTEN_NORM);
 
                        // TODO: add a counter to handle how many times one can teleport, and a delay to prevent spam
-                       player.buffs = 0;
+                       STAT(BUFFS, player) = 0;
                        return true;
                }
        }
@@ -734,36 +733,40 @@ MUTATOR_HOOKFUNCTION(buffs, CustomizeWaypoint)
 
        // if you have the invisibility powerup, sprites ALWAYS are restricted to your team
        // but only apply this to real players, not to spectators
-       if((wp.owner.flags & FL_CLIENT) && (wp.owner.buffs & BUFF_INVISIBLE.m_itemid) && (e == player))
+       if((wp.owner.flags & FL_CLIENT) && (STAT(BUFFS, wp.owner) & BUFF_INVISIBLE.m_itemid) && (e == player))
        if(DIFF_TEAM(wp.owner, e))
                return true;
 }
 
-MUTATOR_HOOKFUNCTION(buffs, OnEntityPreSpawn, CBC_ORDER_LAST)
+MUTATOR_HOOKFUNCTION(buffs, FilterItem)
 {
        if(autocvar_g_buffs < 0)
-               return; // no auto replacing of entities in this mode
+               return false; // no auto replacing of entities in this mode
 
-       entity ent = M_ARGV(0, entity);
+       entity item = M_ARGV(0, entity);
 
        if(autocvar_g_buffs_replace_powerups)
-       switch(ent.classname)
        {
-               case "item_strength":
-               case "item_shield":
+               switch(item.classname)
                {
-                       entity e = spawn();
-                       buff_SpawnReplacement(e, ent);
-                       return true;
+                       case "item_strength":
+                       case "item_shield":
+                       {
+                               entity e = spawn();
+                               buff_SpawnReplacement(e, item);
+                               return true;
+                       }
                }
        }
+
+       return false;
 }
 
 MUTATOR_HOOKFUNCTION(buffs, WeaponRateFactor)
 {
        entity player = M_ARGV(1, entity);
 
-       if(player.buffs & BUFF_SPEED.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_SPEED.m_itemid)
                M_ARGV(0, float) *= autocvar_g_buffs_speed_rate;
 
        if(time < player.buff_disability_time)
@@ -774,7 +777,7 @@ MUTATOR_HOOKFUNCTION(buffs, WeaponSpeedFactor)
 {
        entity player = M_ARGV(1, entity);
 
-       if(player.buffs & BUFF_SPEED.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_SPEED.m_itemid)
                M_ARGV(0, float) *= autocvar_g_buffs_speed_weaponspeed;
 
        if(time < player.buff_disability_time)
@@ -789,7 +792,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
        if(game_stopped || IS_DEAD(player) || frametime || !IS_PLAYER(player)) return;
 
-       if(player.buffs & BUFF_FLIGHT.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_FLIGHT.m_itemid)
        {
                if(!PHYS_INPUT_BUTTON_CROUCH(player))
                        player.buff_flight_crouchheld = false;
@@ -812,10 +815,10 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
        // 2: notify carrier as well
        int buff_lost = 0;
 
-       if(player.buff_time && player.buffs)
-       if(time >= player.buff_time)
+       if(STAT(BUFF_TIME, player) && STAT(BUFFS, player))
+       if(time >= STAT(BUFF_TIME, player))
        {
-               player.buff_time = 0;
+               STAT(BUFF_TIME, player) = 0;
                buff_lost = 2;
        }
 
@@ -823,9 +826,9 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
 
        if(buff_lost)
        {
-               if(player.buffs)
+               if(STAT(BUFFS, player))
                {
-                       int buffid = buff_FirstFromFlags(player.buffs).m_id;
+                       int buffid = buff_FirstFromFlags(STAT(BUFFS, player)).m_id;
                        if(buff_lost == 2)
                        {
                                Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
@@ -833,17 +836,17 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                        }
                        else
                                Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
-                       player.buffs = 0;
+                       STAT(BUFFS, player) = 0;
                        PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
                }
        }
 
-       if(player.buffs & BUFF_MAGNET.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_MAGNET.m_itemid)
        {
                vector pickup_size;
                IL_EACH(g_items, it.itemdef,
                {
-                       if(it.buffs)
+                       if(STAT(BUFFS, it))
                                pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_buff;
                        else
                                pickup_size = '1 1 1' * autocvar_g_buffs_magnet_range_item;
@@ -856,7 +859,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                });
        }
 
-       if(player.buffs & BUFF_AMMO.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_AMMO.m_itemid)
        {
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
@@ -866,31 +869,31 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                }
        }
 
-       if((player.buffs & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
+       if((STAT(BUFFS, player) & BUFF_INVISIBLE.m_itemid) && (player.oldbuffs & BUFF_INVISIBLE.m_itemid))
                player.alpha = ((autocvar_g_buffs_invisible_alpha) ? autocvar_g_buffs_invisible_alpha : -1); // powerups reset alpha, so we must enforce this (TODO)
 
-       if(player.buffs & BUFF_MEDIC.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_MEDIC.m_itemid)
        if(time >= player.buff_medic_healtime)
        {
                buff_Medic_Heal(player);
                player.buff_medic_healtime = time + autocvar_g_buffs_medic_heal_delay;
        }
 
-#define BUFF_ONADD(b) if ( (player.buffs & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
-#define BUFF_ONREM(b) if (!(player.buffs & (b).m_itemid) &&  (player.oldbuffs & (b).m_itemid))
+#define BUFF_ONADD(b) if ( (STAT(BUFFS, player) & (b).m_itemid) && !(player.oldbuffs & (b).m_itemid))
+#define BUFF_ONREM(b) if (!(STAT(BUFFS, player) & (b).m_itemid) &&  (player.oldbuffs & (b).m_itemid))
 
-       if(player.buffs != player.oldbuffs)
+       if(STAT(BUFFS, player) != player.oldbuffs)
        {
-               entity buff = buff_FirstFromFlags(player.buffs);
+               entity buff = buff_FirstFromFlags(STAT(BUFFS, player));
                float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
-               player.buff_time = (bufftime) ? time + bufftime : 0;
+               STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
 
                BUFF_ONADD(BUFF_AMMO)
                {
                        player.buff_ammo_prev_infitems = (player.items & IT_UNLIMITED_WEAPON_AMMO);
                        player.items |= IT_UNLIMITED_WEAPON_AMMO;
 
-                       if(player.buffs & BUFF_AMMO.m_itemid)
+                       if(STAT(BUFFS, player) & BUFF_AMMO.m_itemid)
                        {
                                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                                {
@@ -910,7 +913,7 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                        else
                                player.items &= ~IT_UNLIMITED_WEAPON_AMMO;
 
-                       if(player.buffs & BUFF_AMMO.m_itemid)
+                       if(STAT(BUFFS, player) & BUFF_AMMO.m_itemid)
                        {
                                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                                {
@@ -923,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;
@@ -932,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;
@@ -948,8 +951,8 @@ MUTATOR_HOOKFUNCTION(buffs, PlayerPreThink)
                BUFF_ONREM(BUFF_FLIGHT)
                        player.gravity = ((player.trigger_gravity_check) ? player.trigger_gravity_check.enemy.gravity : player.buff_flight_oldgravity);
 
-               player.oldbuffs = player.buffs;
-               if(player.buffs)
+               player.oldbuffs = STAT(BUFFS, player);
+               if(STAT(BUFFS, player))
                {
                        if(!player.buff_model)
                                buffs_BuffModel_Spawn(player);
@@ -988,22 +991,22 @@ MUTATOR_HOOKFUNCTION(buffs, SpectateCopy)
        entity spectatee = M_ARGV(0, entity);
        entity client = M_ARGV(1, entity);
 
-       client.buffs = spectatee.buffs;
-       client.buff_time = spectatee.buff_time;
+       STAT(BUFFS, client) = STAT(BUFFS, spectatee);
+       STAT(BUFF_TIME, client) = STAT(BUFF_TIME, spectatee);
 }
 
 MUTATOR_HOOKFUNCTION(buffs, PlayerRegen)
 {
        entity player = M_ARGV(0, entity);
 
-       if(player.buffs & BUFF_MEDIC.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_MEDIC.m_itemid)
        {
                M_ARGV(2, float) = autocvar_g_buffs_medic_rot; // rot_mod
                M_ARGV(4, float) = M_ARGV(1, float) = autocvar_g_buffs_medic_max; // limit_mod = max_mod
                M_ARGV(2, float) = autocvar_g_buffs_medic_regen; // regen_mod
        }
 
-       if(player.buffs & BUFF_SPEED.m_itemid)
+       if(STAT(BUFFS, player) & BUFF_SPEED.m_itemid)
                M_ARGV(2, float) = autocvar_g_buffs_speed_regen; // regen_mod
 }
 
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 987645aaa0c719a5546ceeb03d47ee9b2901c804..8fbfa533dd1fd230058a52045159f46bd6e1ccbf 100644 (file)
@@ -63,9 +63,9 @@ MUTATOR_HOOKFUNCTION(campcheck, PlayerPreThink)
                        {
                                Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CAMPCHECK);
                                if(player.vehicle)
-                                       Damage(player.vehicle, NULL, NULL, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, player.vehicle.origin, '0 0 0');
+                                       Damage(player.vehicle, NULL, NULL, autocvar_g_campcheck_damage * 2, DEATH_CAMP.m_id, DMG_NOWEP, player.vehicle.origin, '0 0 0');
                                else
-                                       Damage(player, NULL, NULL, bound(0, autocvar_g_campcheck_damage, GetResourceAmount(player, RESOURCE_HEALTH) + GetResourceAmount(player, RESOURCE_ARMOR) * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, player.origin, '0 0 0');
+                                       Damage(player, NULL, NULL, bound(0, autocvar_g_campcheck_damage, GetResourceAmount(player, RESOURCE_HEALTH) + GetResourceAmount(player, RESOURCE_ARMOR) * autocvar_g_balance_armor_blockpercent + 5), DEATH_CAMP.m_id, DMG_NOWEP, player.origin, '0 0 0');
                        }
                        player.campcheck_nextcheck = time + autocvar_g_campcheck_interval;
                        player.campcheck_traveled_distance = 0;
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..d9eacaae0c4e7a1cf2821d4574bb255a572c3bd5 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)
 #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)
@@ -16,6 +16,7 @@ MUTATOR_HOOKFUNCTION(damagetext, PlayerDamaged) {
     const float armor = M_ARGV(3, float);
     const int deathtype = M_ARGV(5, int);
     const float potential_damage = M_ARGV(6, float);
+    if(DEATH_WEAPONOF(deathtype) == WEP_VAPORIZER) return;
     FOREACH_CLIENT(IS_REAL_CLIENT(it), {
         if (
             (SV_DAMAGETEXT_ALL()) ||
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..3f8d087166353715a224acd0d7bbf4383cdb2154 100644 (file)
@@ -16,16 +16,16 @@ 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;
+    if(!GetResourceAmount(item, RESOURCE_CELLS))
+        SetResourceAmountExplicit(item, RESOURCE_CELLS, autocvar_g_instagib_ammo_drop);
 }
 #endif
 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 85bef1d49c4562a40b68dbd4e5f146551a523422..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)
@@ -84,59 +98,59 @@ void instagib_ammocheck(entity this)
                this.instagib_needammo = true;
                if (hp <= 5)
                {
-                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_INSTAGIB_TERMINATED);
                }
                else if (hp <= 10)
                {
-                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 5, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_1);
                }
                else if (hp <= 20)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_2);
                }
                else if (hp <= 30)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_3);
                }
                else if (hp <= 40)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_4);
                }
                else if (hp <= 50)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_5);
                }
                else if (hp <= 60)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_6);
                }
                else if (hp <= 70)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_7);
                }
                else if (hp <= 80)
                {
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_8);
                }
                else if (hp <= 90)
                {
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_INSTAGIB_FINDAMMO);
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        Send_Notification(NOTIF_ONE, this, MSG_ANNCE, ANNCE_NUM_9);
                }
                else
                {
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_MULTI, MULTI_INSTAGIB_FINDAMMO);
-                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, this.origin, '0 0 0');
+                       Damage(this, this, this, 10, DEATH_NOAMMO.m_id, DMG_NOWEP, this.origin, '0 0 0');
                }
        }
        this.instagib_nextthink = time + 1;
@@ -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);
@@ -253,14 +274,13 @@ MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPowerups)
        }
 }
 
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics)
+MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerPhysics_UpdateStats)
 {
        entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
 
        if(player.items & ITEM_Speed.m_itemid)
-               player.stat_sv_maxspeed = player.stat_sv_maxspeed * autocvar_g_instagib_speed_highspeed;
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_instagib_speed_highspeed;
 }
 
 MUTATOR_HOOKFUNCTION(mutator_instagib, PlayerDamage_SplitHealthArmor)
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 e68c687bdeb65058bac0c887c5f8aab8967bd560..443fe2478139a9527df39ab979f13a85805f09f8 100644 (file)
@@ -7,10 +7,10 @@ MUTATOR_HOOKFUNCTION(invincibleprojectiles, EditProjectile)
 {
        entity proj = M_ARGV(1, entity);
 
-       if(proj.health)
+       if(GetResourceAmount(proj, RESOURCE_HEALTH))
        {
                // disable health which in effect disables damage calculations
-               proj.health = 0;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, 0);
        }
 }
 
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 3dc7e4e0e3e050c4eb7e72d838945492aa552750..68a3af3baf76d5ae65f46819004a865c91ce604e 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);
 
@@ -168,7 +177,7 @@ void nade_timer_think(entity this)
 
 void nade_burn_spawn(entity _nade)
 {
-       CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[true], true);
+       CSQCProjectile(_nade, true, Nades_from(STAT(NADE_BONUS_TYPE, _nade)).m_projectile[true], true);
 }
 
 void nade_spawn(entity _nade)
@@ -186,7 +195,7 @@ void nade_spawn(entity _nade)
 
        _nade.effects |= EF_LOWPRECISION;
 
-       CSQCProjectile(_nade, true, Nades_from(_nade.nade_type).m_projectile[false], true);
+       CSQCProjectile(_nade, true, Nades_from(STAT(NADE_BONUS_TYPE, _nade)).m_projectile[false], true);
 }
 
 void napalm_damage(entity this, float dist, float damage, float edgedamage, float burntime)
@@ -370,11 +379,11 @@ void nade_napalm_boom(entity this)
        CSQCProjectile(fountain, true, PROJECTILE_NAPALM_FOUNTAIN, true);
 }
 
-void nade_ice_freeze(entity freezefield, entity frost_target, float freeze_time)
+void nade_ice_freeze(entity freezefield, entity frost_target, float freezetime)
 {
        frost_target.frozen_by = freezefield.realowner;
        Send_Effect(EFFECT_ELECTRO_IMPACT, frost_target.origin, '0 0 0', 1);
-       Freeze(frost_target, 1/freeze_time, 3, false);
+       Freeze(frost_target, 1 / freezetime, 3, false);
 
        Drop_Special_Items(frost_target);
 }
@@ -397,7 +406,7 @@ void nade_ice_think(entity this)
                        sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
 
                        RadiusDamage(this, this.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
-                               autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, this.enemy);
+                               autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, DMG_NOWEP, this.enemy);
                        Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
                                autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this);
                }
@@ -635,7 +644,7 @@ void nade_heal_touch(entity this, entity toucher)
                }
                else if ( health_factor < 0 )
                {
-                       Damage(toucher,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,toucher.origin,'0 0 0');
+                       Damage(toucher,this,this.realowner,-health_factor,DEATH_NADE_HEAL.m_id,DMG_NOWEP,toucher.origin,'0 0 0');
                }
 
        }
@@ -643,8 +652,8 @@ void nade_heal_touch(entity this, entity toucher)
        if ( IS_REAL_CLIENT(toucher) || IS_VEHICLE(toucher) )
        {
                entity show_red = (IS_VEHICLE(toucher)) ? toucher.owner : toucher;
-               show_red.stat_healing_orb = time+0.1;
-               show_red.stat_healing_orb_alpha = 0.75 * (this.ltime - time) / this.orb_lifetime;
+               STAT(HEALING_ORB, show_red) = time+0.1;
+               STAT(HEALING_ORB_ALPHA, show_red) = 0.75 * (this.ltime - time) / this.orb_lifetime;
        }
 }
 
@@ -665,12 +674,41 @@ 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;
        bool nade_blast = true;
 
-       switch ( Nades_from(this.nade_type) )
+       switch ( Nades_from(STAT(NADE_BONUS_TYPE, this)) )
        {
                case NADE_TYPE_NAPALM:
                        nade_blast = autocvar_g_nades_napalm_blast;
@@ -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);
@@ -722,12 +765,12 @@ void nade_boom(entity this)
        if(nade_blast)
        {
                RadiusDamage(this, this.realowner, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage,
-                                autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, this.enemy);
+                                autocvar_g_nades_nade_radius, this, NULL, autocvar_g_nades_nade_force, this.projectiledeathtype, DMG_NOWEP, this.enemy);
                Damage_DamageInfo(this.origin, autocvar_g_nades_nade_damage, autocvar_g_nades_nade_edgedamage, autocvar_g_nades_nade_radius, '1 1 1' * autocvar_g_nades_nade_force, this.projectiledeathtype, 0, this);
        }
 
        if(this.takedamage)
-       switch ( Nades_from(this.nade_type) )
+       switch ( Nades_from(STAT(NADE_BONUS_TYPE, this)) )
        {
                case NADE_TYPE_NAPALM: nade_napalm_boom(this); break;
                case NADE_TYPE_ICE: nade_ice_boom(this); break;
@@ -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,
@@ -749,11 +793,11 @@ void nade_boom(entity this)
 void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, string pntype);
 void nade_pickup(entity this, entity thenade)
 {
-       spawn_held_nade(this, thenade.realowner, autocvar_g_nades_pickup_time, thenade.nade_type, thenade.pokenade_type);
+       spawn_held_nade(this, thenade.realowner, autocvar_g_nades_pickup_time, STAT(NADE_BONUS_TYPE, thenade), thenade.pokenade_type);
 
        // set refire so player can't even
        this.nade_refire = time + autocvar_g_nades_nade_refire;
-       this.nade_timer = 0;
+       STAT(NADE_TIMER, this) = 0;
 
        if(this.nade)
                this.nade.nade_time_primed = thenade.nade_time_primed;
@@ -815,7 +859,7 @@ void nade_beep(entity this)
        this.nextthink = max(this.wait, time);
 }
 
-void nade_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void nade_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
        {
@@ -824,7 +868,7 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
                return;
        }
 
-       if(this.nade_type == NADE_TYPE_TRANSLOCATE.m_id || this.nade_type == NADE_TYPE_SPAWN.m_id)
+       if(STAT(NADE_BONUS_TYPE, this) == NADE_TYPE_TRANSLOCATE.m_id || STAT(NADE_BONUS_TYPE, this) == NADE_TYPE_SPAWN.m_id)
                return;
 
        if (MUTATOR_CALLHOOK(Nade_Damage, this, DEATH_WEAPONOF(deathtype), force, damage)) {}
@@ -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
        {
@@ -874,7 +918,7 @@ void nade_damage(entity this, entity inflictor, entity attacker, float damage, i
        SetResourceAmount(this, RESOURCE_HEALTH, hp);
 
 
-       if ( this.nade_type != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
+       if ( STAT(NADE_BONUS_TYPE, this) != NADE_TYPE_HEAL.m_id || IS_PLAYER(attacker) )
                this.realowner = attacker;
 
        if(hp <= 0)
@@ -899,7 +943,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        makevectors(e.v_angle);
 
        // NOTE: always throw from first weapon entity?
-       W_SetupShot(e, _nade.weaponentity_fld, false, false, SND_Null, CH_WEAPON_A, 0);
+       W_SetupShot(e, _nade.weaponentity_fld, false, false, SND_Null, CH_WEAPON_A, 0, DEATH_NADE.m_id);
 
        vector offset = (v_forward * autocvar_g_nades_throw_offset.x)
                      + (v_right * autocvar_g_nades_throw_offset.y)
@@ -934,7 +978,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        settouch(_nade, nade_touch);
        _nade.spawnshieldtime = time + 0.1; // prevent instantly picking up again
        SetResourceAmount(_nade, RESOURCE_HEALTH, autocvar_g_nades_nade_health);
-       _nade.max_health = _nade.health;
+       _nade.max_health = GetResourceAmount(_nade, RESOURCE_HEALTH);
        _nade.takedamage = DAMAGE_AIM;
        _nade.event_damage = nade_damage;
        setcefc(_nade, func_null);
@@ -952,9 +996,9 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        IL_PUSH(g_bot_dodge, _nade);
        _nade.projectiledeathtype = DEATH_NADE.m_id;
        _nade.toss_time = time;
-       _nade.solid = SOLID_CORPSE; //((_nade.nade_type == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
+       _nade.solid = SOLID_CORPSE; //((STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_TRANSLOCATE) ? SOLID_CORPSE : SOLID_BBOX);
 
-       if(_nade.nade_type == NADE_TYPE_TRANSLOCATE.m_id || _nade.nade_type == NADE_TYPE_SPAWN.m_id)
+       if(STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_TRANSLOCATE.m_id || STAT(NADE_BONUS_TYPE, _nade) == NADE_TYPE_SPAWN.m_id)
                _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
        else
                _nade.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY;
@@ -968,7 +1012,7 @@ void toss_nade(entity e, bool set_owner, vector _velocity, float _time)
        }
 
        e.nade_refire = time + autocvar_g_nades_nade_refire;
-       e.nade_timer = 0;
+       STAT(NADE_TIMER, e) = 0;
 }
 
 void nades_GiveBonus(entity player, float score)
@@ -976,19 +1020,19 @@ void nades_GiveBonus(entity player, float score)
        if (autocvar_g_nades)
        if (autocvar_g_nades_bonus)
        if (IS_REAL_CLIENT(player))
-       if (IS_PLAYER(player) && player.bonus_nades < autocvar_g_nades_bonus_max)
+       if (IS_PLAYER(player) && STAT(NADE_BONUS, player) < autocvar_g_nades_bonus_max)
        if (STAT(FROZEN, player) == 0)
        if (!IS_DEAD(player))
        {
-               if ( player.bonus_nade_score < 1 )
-                       player.bonus_nade_score += score/autocvar_g_nades_bonus_score_max;
+               if ( STAT(NADE_BONUS_SCORE, player) < 1 )
+                       STAT(NADE_BONUS_SCORE, player) += score/autocvar_g_nades_bonus_score_max;
 
-               if ( player.bonus_nade_score >= 1 )
+               if ( STAT(NADE_BONUS_SCORE, player) >= 1 )
                {
                        Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
                        play2(player, SND(KH_ALARM));
-                       player.bonus_nades++;
-                       player.bonus_nade_score -= 1;
+                       STAT(NADE_BONUS, player)++;
+                       STAT(NADE_BONUS_SCORE, player) -= 1;
                }
        }
 }
@@ -996,7 +1040,7 @@ void nades_GiveBonus(entity player, float score)
 /** Remove all bonus nades from a player */
 void nades_RemoveBonus(entity player)
 {
-       player.bonus_nades = player.bonus_nade_score = 0;
+       STAT(NADE_BONUS, player) = STAT(NADE_BONUS_SCORE, player) = 0;
 }
 
 MUTATOR_HOOKFUNCTION(nades, PutClientInServer)
@@ -1021,7 +1065,7 @@ bool nade_customize(entity this, entity client)
        {
                //this.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
                if(!this.traileffectnum)
-                       this.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(this.nade_type).m_projectile[false], this.team).eent_eff_name);
+                       this.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(STAT(NADE_BONUS_TYPE, this)).m_projectile[false], this.team).eent_eff_name);
                this.alpha = 1;
        }
 
@@ -1032,11 +1076,11 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
 {
        entity n = new(nade), fn = new(fake_nade);
 
-       n.nade_type = max(1, ntype);
+       STAT(NADE_BONUS_TYPE, n) = max(1, ntype);
        n.pokenade_type = pntype;
 
-       if(Nades_from(n.nade_type) == NADE_TYPE_Null)
-               n.nade_type = NADE_TYPE_NORMAL.m_id;
+       if(Nades_from(STAT(NADE_BONUS_TYPE, n)) == NADE_TYPE_Null)
+               STAT(NADE_BONUS_TYPE, n) = NADE_TYPE_NORMAL.m_id;
 
        .entity weaponentity = weaponentities[0]; // TODO: unhardcode
 
@@ -1044,8 +1088,8 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
        //setattachment(n, player, "bip01 l hand");
        n.exteriormodeltoclient = player;
        setcefc(n, nade_customize);
-       n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(n.nade_type).m_projectile[false], player.team).eent_eff_name);
-       n.colormod = Nades_from(n.nade_type).m_color;
+       n.traileffectnum = _particleeffectnum(Nade_TrailEffect(Nades_from(STAT(NADE_BONUS_TYPE, n)).m_projectile[false], player.team).eent_eff_name);
+       n.colormod = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_color;
        n.realowner = nowner;
        n.colormap = player.colormap;
        n.glowmod = player.glowmod;
@@ -1056,16 +1100,18 @@ 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), "");
        fn.realowner = fn.owner = player;
-       fn.colormod = Nades_from(n.nade_type).m_color;
+       fn.colormod = Nades_from(STAT(NADE_BONUS_TYPE, n)).m_color;
        fn.colormap = player.colormap;
        fn.glowmod = player.glowmod;
        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;
@@ -1074,7 +1120,7 @@ void spawn_held_nade(entity player, entity nowner, float ntime, int ntype, strin
 void nade_prime(entity this)
 {
        if(autocvar_g_nades_bonus_only)
-       if(!this.bonus_nades)
+       if(!STAT(NADE_BONUS, this))
                return; // only allow bonus nades
 
        if(this.nade)
@@ -1086,13 +1132,13 @@ void nade_prime(entity this)
        int ntype;
        string pntype = this.pokenade_type;
 
-       if(this.items & ITEM_Strength.m_itemid && autocvar_g_nades_bonus_onstrength)
-               ntype = this.nade_type;
-       else if (this.bonus_nades >= 1)
+       if((this.items & ITEM_Strength.m_itemid) && autocvar_g_nades_bonus_onstrength)
+               ntype = STAT(NADE_BONUS_TYPE, this);
+       else if (STAT(NADE_BONUS, this) >= 1)
        {
-               ntype = this.nade_type;
+               ntype = STAT(NADE_BONUS_TYPE, this);
                pntype = this.pokenade_type;
-               this.bonus_nades -= 1;
+               STAT(NADE_BONUS, this) -= 1;
        }
        else
        {
@@ -1164,7 +1210,7 @@ void nades_Clear(entity player)
                delete(player.fake_nade);
 
        player.nade = player.fake_nade = NULL;
-       player.nade_timer = 0;
+       STAT(NADE_TIMER, player) = 0;
 }
 
 MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
@@ -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,13 +1264,13 @@ 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)
        {
-               player.nade_timer = bound(0, (time - held_nade.nade_time_primed) / held_nade.nade_lifetime, 1);
-               // LOG_TRACEF("%d %d", player.nade_timer, time - held_nade.nade_time_primed);
+               STAT(NADE_TIMER, player) = bound(0, (time - held_nade.nade_time_primed) / held_nade.nade_lifetime, 1);
+               // LOG_TRACEF("%d %d", STAT(NADE_TIMER, player), time - held_nade.nade_time_primed);
                makevectors(player.angles);
                held_nade.velocity = player.velocity;
                setorigin(held_nade, player.origin + player.view_ofs + v_forward * 8 + v_right * -8 + v_up * 0);
@@ -1253,23 +1299,32 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
 
                        if(autocvar_g_nades_bonus_client_select)
                        {
-                               player.nade_type = CS(player).cvar_cl_nade_type;
+                               STAT(NADE_BONUS_TYPE, player) = CS(player).cvar_cl_nade_type;
                                player.pokenade_type = CS(player).cvar_cl_pokenade_type;
                        }
                        else
                        {
-                               player.nade_type = autocvar_g_nades_bonus_type;
+                               STAT(NADE_BONUS_TYPE, player) = autocvar_g_nades_bonus_type;
                                player.pokenade_type = autocvar_g_nades_pokenade_monster_type;
                        }
 
-                       player.nade_type = bound(1, player.nade_type, Nades_COUNT);
+                       STAT(NADE_BONUS_TYPE, player) = bound(1, STAT(NADE_BONUS_TYPE, player), Nades_COUNT);
 
-                       if(player.bonus_nade_score >= 0 && autocvar_g_nades_bonus_score_max)
+                       if(STAT(NADE_BONUS_SCORE, player) >= 0 && autocvar_g_nades_bonus_score_max)
                                nades_GiveBonus(player, time_score / autocvar_g_nades_bonus_score_max);
                }
                else
                {
-                       player.bonus_nades = player.bonus_nade_score = 0;
+                       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;
                }
        }
 
@@ -1295,10 +1350,10 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
 
        if(n > 0 && STAT(FROZEN, player) == 3) // OK, there is at least one teammate reviving us
        {
-               player.revive_progress = bound(0, player.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               SetResourceAmount(player, RESOURCE_HEALTH, max(1, player.revive_progress * start_health));
+               STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+               SetResourceAmount(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * start_health));
 
-               if(player.revive_progress >= 1)
+               if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
                        Unfreeze(player);
 
@@ -1307,21 +1362,19 @@ MUTATOR_HOOKFUNCTION(nades, PlayerPreThink)
                }
 
                FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
-                       it.revive_progress = player.revive_progress;
+                       STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
                        it.reviving = false;
                });
        }
 }
 
-MUTATOR_HOOKFUNCTION(nades, PlayerPhysics)
+MUTATOR_HOOKFUNCTION(nades, PlayerPhysics_UpdateStats)
 {
        entity player = M_ARGV(0, entity);
+       // these automatically reset, no need to worry
 
-       if (STAT(ENTRAP_ORB, player) > time)
-       {
-               player.stat_sv_maxspeed *= autocvar_g_nades_entrap_speed;
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_nades_entrap_speed;
-       }
+       if(STAT(ENTRAP_ORB, player) > time)
+               STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nades_entrap_speed;
 }
 
 MUTATOR_HOOKFUNCTION(nades, MonsterMove)
@@ -1333,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)
@@ -1345,9 +1404,9 @@ MUTATOR_HOOKFUNCTION(nades, PlayerSpawn)
                player.nade_refire  = time + autocvar_g_nades_nade_refire;
 
        if(autocvar_g_nades_bonus_client_select)
-               player.nade_type = CS(player).cvar_cl_nade_type;
+               STAT(NADE_BONUS_TYPE, player) = CS(player).cvar_cl_nade_type;
 
-       player.nade_timer = 0;
+       STAT(NADE_TIMER, player) = 0;
 
        if (!player.offhand) player.offhand = OFFHAND_NADE;
 
@@ -1406,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);
@@ -1462,15 +1518,17 @@ MUTATOR_HOOKFUNCTION(nades, SpectateCopy)
        entity spectatee = M_ARGV(0, entity);
        entity client = M_ARGV(1, entity);
 
-       client.nade_timer = spectatee.nade_timer;
-       client.nade_type = spectatee.nade_type;
+       STAT(NADE_TIMER, client) = STAT(NADE_TIMER, spectatee);
+       STAT(NADE_BONUS_TYPE, client) = STAT(NADE_BONUS_TYPE, spectatee);
        client.pokenade_type = spectatee.pokenade_type;
-       client.bonus_nades = spectatee.bonus_nades;
-       client.bonus_nade_score = spectatee.bonus_nade_score;
-       client.stat_healing_orb = spectatee.stat_healing_orb;
-       client.stat_healing_orb_alpha = spectatee.stat_healing_orb_alpha;
+       STAT(NADE_BONUS, client) = STAT(NADE_BONUS, spectatee);
+       STAT(NADE_BONUS_SCORE, client) = STAT(NADE_BONUS_SCORE, spectatee);
+       STAT(HEALING_ORB, client) = STAT(HEALING_ORB, spectatee);
+       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 3618fd4181c0a4854704905e0e29a7b54ac971fb..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)) {
@@ -64,20 +67,15 @@ Nade Nade_FromProjectile(int proj)
 
 .entity nade;
 .entity fake_nade;
-.float nade_timer = _STAT(NADE_TIMER);
 .float nade_refire;
-.float bonus_nades = _STAT(NADE_BONUS);
 .float nade_special_time;
-.float bonus_nade_score = _STAT(NADE_BONUS_SCORE);
-.int nade_type = _STAT(NADE_BONUS_TYPE);
 .string pokenade_type;
 .entity nade_damage_target;
 .float cvar_cl_nade_type;
 .string cvar_cl_pokenade_type;
 .float toss_time;
-.float stat_healing_orb = _STAT(HEALING_ORB);
-.float stat_healing_orb_alpha = _STAT(HEALING_ORB_ALPHA);
 .float nade_show_particles;
+.float nade_veil_prevalpha;
 
 bool orb_send(entity this, entity to, int sf);
 
@@ -101,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 498d878d2d272341bd2ba9b04fd8908393a5e713..1fdf5fd7aad1a5e2ef0e85c68d326da0fb6845bc 100644 (file)
@@ -32,7 +32,7 @@ void orb_setup(entity e)
 
        e.draw = orb_draw;
        IL_PUSH(g_drawables, e);
-       e.health = 255;
+       SetResourceAmountExplicit(e, RESOURCE_HEALTH, 255);
        set_movetype(e, MOVETYPE_NONE);
        e.solid = SOLID_NOT;
        e.drawmask = MASK_NORMAL;
@@ -50,13 +50,9 @@ NET_HANDLE(Nade_Orb, bool isNew)
        Net_Accept(Nade_Orb);
        int sf = ReadByte();
        if (sf & 1) {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
-               this.colormod_x = ReadCoord();
-               this.colormod_y = ReadCoord();
-               this.colormod_z = ReadCoord();
+               this.colormod = ReadVector();
                this.orb_lifetime = ReadByte();
                this.orb_radius = ReadShort();
                this.ltime = time + ReadByte()/10.0;
@@ -74,13 +70,9 @@ bool orb_send(entity this, entity to, int sf)
        WriteHeader(channel, Nade_Orb);
        WriteByte(channel, sf);
        if (sf & 1) {
-               WriteCoord(channel, this.origin.x);
-               WriteCoord(channel, this.origin.y);
-               WriteCoord(channel, this.origin.z);
+               WriteVector(channel, this.origin);
 
-               WriteCoord(channel, this.colormod.x);
-               WriteCoord(channel, this.colormod.y);
-               WriteCoord(channel, this.colormod.z);
+               WriteVector(channel, this.colormod);
 
                WriteByte(channel, this.orb_lifetime);
                //WriteByte(MSG_ENTITY, this.ltime - time + 1);
index ec2593215a09b5187abd522608e07dc6f978e141..37dac8f93123d0624d78e44f90e918e828c659d8 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
        {
@@ -108,7 +108,7 @@ REGISTER_MUTATOR(nt, expr_evaluate(autocvar_g_new_toys) && !cvar("g_instagib") &
 .string new_toys;
 
 float autocvar_g_new_toys_autoreplace;
-bool autocvar_g_new_toys_use_pickupsound = true;
+bool autocvar_g_new_toys_use_pickupsound = false;
 const float NT_AUTOREPLACE_NEVER = 0;
 const float NT_AUTOREPLACE_ALWAYS = 1;
 const float NT_AUTOREPLACE_RANDOM = 2;
@@ -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 eb14a3159efd0f9f9e4e6fbdcc46cecb6718cb0e..586deda3efbb4aa6fcc5dc6d00de5bad6d5184c5 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];
@@ -130,7 +130,7 @@ void NIX_GiveCurrentWeapon(entity this)
        }
 
        // get weapon info
-       entity e = Weapons_from(nix_weapon);
+       entity wpn = Weapons_from(nix_weapon);
 
        if(nix_nextchange != this.nix_lastchange_id) // this shall only be called once per round!
        {
@@ -142,7 +142,7 @@ void NIX_GiveCurrentWeapon(entity this)
                SetResourceAmount(this, RESOURCE_FUEL, 0);
                if(this.items & IT_UNLIMITED_WEAPON_AMMO)
                {
-                       switch (e.ammo_type)
+                       switch (wpn.ammo_type)
                        {
                                case RESOURCE_SHELLS:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_pickup_shells_max);  break;
                                case RESOURCE_BULLETS: SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_pickup_nails_max);   break;
@@ -154,7 +154,7 @@ void NIX_GiveCurrentWeapon(entity this)
                }
                else
                {
-                       switch (e.ammo_type)
+                       switch (wpn.ammo_type)
                        {
                                case RESOURCE_SHELLS:  SetResourceAmount(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammo_shells);  break;
                                case RESOURCE_BULLETS: SetResourceAmount(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammo_nails);   break;
@@ -171,27 +171,15 @@ void NIX_GiveCurrentWeapon(entity this)
                else
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CENTER_NIX_NEWWEAPON, nix_weapon);
 
-               e.wr_resetplayer(e, this);
+               wpn.wr_resetplayer(wpn, this);
 
                // all weapons must be fully loaded when we spawn
-               if(e.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
+               if (wpn.spawnflags & WEP_FLAG_RELOADABLE) // prevent accessing undefined cvars
                {
-                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+                       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                        {
                                .entity weaponentity = weaponentities[slot];
-                               this.(weaponentity).(weapon_load[nix_weapon]) = e.reloading_ammo;
-                       }
-               }
-
-               // vortex too
-               if(WEP_CVAR(vortex, charge))
-               {
-                       if(WEP_CVAR_SEC(vortex, chargepool))
-                               this.vortex_chargepool_ammo = 1;
-                       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-                       {
-                               .entity weaponentity = weaponentities[slot];
-                               this.(weaponentity).vortex_charge = WEP_CVAR(vortex, charge_start);
+                               this.(weaponentity).(weapon_load[nix_weapon]) = wpn.reloading_ammo;
                        }
                }
 
@@ -207,7 +195,7 @@ void NIX_GiveCurrentWeapon(entity this)
 
        if(!(this.items & IT_UNLIMITED_WEAPON_AMMO) && time > this.nix_nextincr)
        {
-               switch (e.ammo_type)
+               switch (wpn.ammo_type)
                {
                        case RESOURCE_SHELLS:  GiveResource(this, RESOURCE_SHELLS, autocvar_g_balance_nix_ammoincr_shells);  break;
                        case RESOURCE_BULLETS: GiveResource(this, RESOURCE_BULLETS, autocvar_g_balance_nix_ammoincr_nails);   break;
@@ -220,23 +208,22 @@ 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;
-
-    Weapon w = Weapons_from(nix_weapon);
-    for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-    {
-       .entity weaponentity = weaponentities[slot];
-       if(this.(weaponentity).m_weapon == WEP_Null && slot != 0)
-               continue;
-
-               if(this.(weaponentity).m_switchweapon != w)
-               if(!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
+               STAT(WEAPONS, this) |= WEPSET(BLASTER);
+       STAT(WEAPONS, this) |= wpn.m_wepset;
+
+       for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               if (this.(weaponentity).m_weapon == WEP_Null && slot != 0)
+                       continue;
+
+               if (this.(weaponentity).m_switchweapon != wpn)
+               if (!client_hasweapon(this, this.(weaponentity).m_switchweapon, weaponentity, true, false))
                {
-                       if(client_hasweapon(this, w, weaponentity, true, false))
-                               W_SwitchWeapon(this, w, weaponentity);
+                       if (client_hasweapon(this, wpn, weaponentity, true, false))
+                               W_SwitchWeapon(this, wpn, weaponentity);
                }
        }
 }
@@ -256,15 +243,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;
        }
diff --git a/qcsrc/common/mutators/mutator/offhand_blaster/_mod.inc b/qcsrc/common/mutators/mutator/offhand_blaster/_mod.inc
new file mode 100644 (file)
index 0000000..41bb01e
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc>
+#endif
diff --git a/qcsrc/common/mutators/mutator/offhand_blaster/_mod.qh b/qcsrc/common/mutators/mutator/offhand_blaster/_mod.qh
new file mode 100644 (file)
index 0000000..5e11096
--- /dev/null
@@ -0,0 +1,4 @@
+// generated file; do not modify
+#ifdef SVQC
+    #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh>
+#endif
diff --git a/qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc b/qcsrc/common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc
new file mode 100644 (file)
index 0000000..3a10055
--- /dev/null
@@ -0,0 +1,26 @@
+#include "sv_offhand_blaster.qh"
+
+string autocvar_g_offhand_blaster = "0";
+
+REGISTER_MUTATOR(offhand_blaster, expr_evaluate(autocvar_g_offhand_blaster));
+
+MUTATOR_HOOKFUNCTION(offhand_blaster, BuildMutatorsString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ":offhand_blaster");
+}
+
+MUTATOR_HOOKFUNCTION(offhand_blaster, BuildMutatorsPrettyString)
+{
+       M_ARGV(0, string) = strcat(M_ARGV(0, string), ", Offhand blaster");
+}
+
+MUTATOR_HOOKFUNCTION(offhand_blaster, BuildGameplayTipsString)
+{
+    M_ARGV(0, string) = strcat(M_ARGV(0, string), "\n\n^3offhand blaster^8 is enabled, press 'e' to use it\n");
+}
+
+MUTATOR_HOOKFUNCTION(offhand_blaster, PlayerSpawn)
+{
+       entity player = M_ARGV(0, entity);
+       player.offhand = 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.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..003cd3a
--- /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, EFFECT_RIFLE);
+
+       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..27502a7
--- /dev/null
@@ -0,0 +1,155 @@
+#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, EFFECT_RIFLE);
+
+       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..37d82e2
--- /dev/null
@@ -0,0 +1,219 @@
+#include "okrpc.qh"
+
+#ifdef SVQC
+
+void W_OverkillRocketPropelledChainsaw_Explode(entity this, entity directhitentity)
+{
+       this.event_damage = func_null;
+       this.takedamage = DAMAGE_NO;
+
+       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(okrpc, damage), WEP_CVAR_PRI(okrpc, edgedamage), WEP_CVAR_PRI(okrpc, radius), NULL, NULL, WEP_CVAR_PRI(okrpc, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+
+       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 (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
+               return;
+
+       if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
+               return; // g_projectiles_damage says to halt
+
+       TakeResource(this, RESOURCE_HEALTH, damage);
+
+       if (GetResourceAmount(this, RESOURCE_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))
+               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);
+       SetResourceAmountExplicit(missile, RESOURCE_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');
+
+       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.qc b/qcsrc/common/mutators/mutator/overkill/rpc.qc
deleted file mode 100644 (file)
index b38e0ee..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-#include "rpc.qh"
-
-#ifdef SVQC
-
-void W_RocketPropelledChainsaw_Explode(entity this, entity directhitentity)
-{
-       this.event_damage = func_null;
-       this.takedamage = DAMAGE_NO;
-
-       RadiusDamage (this, this.realowner, WEP_CVAR(rpc, damage), WEP_CVAR(rpc, edgedamage), WEP_CVAR(rpc, radius), NULL, NULL, WEP_CVAR(rpc, force), this.projectiledeathtype, directhitentity);
-
-       delete(this);
-}
-
-void W_RocketPropelledChainsaw_Explode_think(entity this)
-{
-       W_RocketPropelledChainsaw_Explode(this, NULL);
-}
-
-void W_RocketPropelledChainsaw_Touch (entity this, entity toucher)
-{
-       if(WarpZone_Projectile_Touch(this, toucher))
-               if(wasfreed(this))
-                       return;
-
-       W_RocketPropelledChainsaw_Explode(this, toucher);
-}
-
-void W_RocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, 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_RocketPropelledChainsaw_Explode_think);
-}
-
-void W_RocketPropelledChainsaw_Think(entity this)
-{
-       if(this.cnt <= time)
-       {
-               delete(this);
-               return;
-       }
-
-       this.cnt = vlen(this.velocity);
-       this.wait = this.cnt * sys_frametime;
-       this.pos1 = normalize(this.velocity);
-
-       tracebox(this.origin, this.mins, this.maxs, this.origin + this.pos1 * (2 * this.wait), MOVE_NORMAL, this);
-       if(IS_PLAYER(trace_ent))
-               Damage (trace_ent, this, this.realowner, WEP_CVAR(rpc, damage2), this.projectiledeathtype, this.origin, normalize(this.origin - trace_ent.origin) * WEP_CVAR(rpc, force));
-
-       this.velocity = this.pos1 * (this.cnt + (WEP_CVAR(rpc, speedaccel) * sys_frametime));
-
-       UpdateCSQCProjectile(this);
-       this.nextthink = time;
-}
-
-void W_RocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity weaponentity)
-{
-       entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor);
-       entity flash = spawn ();
-
-       W_DecreaseAmmo(thiswep, actor, WEP_CVAR(rpc, ammo), weaponentity);
-       W_SetupShot_ProjectileSize (actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(rpc, damage));
-       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(rpc, damage) * 2;
-
-       missile.takedamage = DAMAGE_YES;
-       missile.damageforcescale = WEP_CVAR(rpc, damageforcescale);
-       missile.health = WEP_CVAR(rpc, health);
-       missile.event_damage = W_RocketPropelledChainsaw_Damage;
-       missile.damagedbycontents = true;
-       IL_PUSH(g_damagedbycontents, missile);
-       set_movetype(missile, MOVETYPE_FLY);
-
-       missile.projectiledeathtype = WEP_RPC.m_id;
-       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(rpc, speed), 0);
-
-       settouch(missile, W_RocketPropelledChainsaw_Touch);
-
-       setthink(missile, W_RocketPropelledChainsaw_Think);
-       missile.cnt = time + WEP_CVAR(rpc, 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.pos1 = missile.velocity;
-
-       MUTATOR_CALLHOOK(EditProjectile, actor, missile);
-}
-
-METHOD(RocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
-{
-    PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR(rpc, speed), 0, WEP_CVAR(rpc, lifetime), false);
-}
-
-METHOD(RocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
-{
-    if(WEP_CVAR(rpc, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(rpc, ammo)) {
-        thiswep.wr_reload(thiswep, actor, weaponentity);
-    } else
-    {
-        if (fire & 1)
-        {
-            if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(rpc, refire)))
-            {
-                W_RocketPropelledChainsaw_Attack(thiswep, actor, weaponentity);
-                weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(rpc, animtime), w_ready);
-            }
-        }
-
-        if (fire & 2)
-        {
-            // to-do
-        }
-    }
-}
-
-METHOD(RocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
-{
-    float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(rpc, ammo);
-    ammo_amount += actor.(weaponentity).(weapon_load[WEP_RPC.m_id]) >= WEP_CVAR(rpc, ammo);
-    return ammo_amount;
-}
-
-METHOD(RocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
-{
-    return false;
-}
-
-METHOD(RocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
-{
-    W_Reload(actor, weaponentity, WEP_CVAR(rpc, ammo), SND_RELOAD);
-}
-
-METHOD(RocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
-{
-    if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
-        return WEAPON_RPC_SUICIDE_SPLASH;
-    else
-        return WEAPON_RPC_SUICIDE_DIRECT;
-}
-
-METHOD(RocketPropelledChainsaw, 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_RPC_MURDER_SPLASH;
-    else
-        return WEAPON_RPC_MURDER_DIRECT;
-}
-
-#endif
-
-#ifdef CSQC
-
-METHOD(RocketPropelledChainsaw, 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/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 5611042b0b3100f1bb8cb0dcd2e06e546fa9720a..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,48 +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;
-
-                       Weapon oldwep = player.(weaponentity).m_weapon;
-                       player.(weaponentity).m_weapon = WEP_BLASTER;
-                       W_Blaster_Attack(
-                               player,
-                               weaponentity,
-                               WEP_BLASTER.m_id | HITTYPE_SECONDARY,
-                               WEP_CVAR_SEC(vaporizer, shotangle),
-                               WEP_CVAR_SEC(vaporizer, damage),
-                               WEP_CVAR_SEC(vaporizer, edgedamage),
-                               WEP_CVAR_SEC(vaporizer, radius),
-                               WEP_CVAR_SEC(vaporizer, force),
-                               WEP_CVAR_SEC(vaporizer, speed),
-                               WEP_CVAR_SEC(vaporizer, spread),
-                               WEP_CVAR_SEC(vaporizer, delay),
-                               WEP_CVAR_SEC(vaporizer, lifetime)
-                       );
-                       player.(weaponentity).m_weapon = oldwep;
+                       continue;
                }
+               weapon.wr_think(weapon, player, weaponentity, 2);
        }
-
        PHYS_INPUT_BUTTON_ATCK2(player) = false;
 }
 
@@ -184,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;
                }
@@ -230,13 +225,20 @@ MUTATOR_HOOKFUNCTION(ok, FilterItem)
        {
                return false;
        }
+       switch(item.itemdef)
+       {
+               case ITEM_HealthMega: return autocvar_g_overkill_filter_healthmega;
+               case ITEM_ArmorMedium: return autocvar_g_overkill_filter_armormedium;
+               case ITEM_ArmorBig: return autocvar_g_overkill_filter_armorbig;
+               case ITEM_ArmorMega: return autocvar_g_overkill_filter_armormega;
+       }
        if (!autocvar_g_powerups || !autocvar_g_overkill_powerups_replace)
        {
                return true;
        }
        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);
@@ -245,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);
@@ -259,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;
@@ -267,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;
@@ -297,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 38cd7474b786c34343e4acf30009421d3fb8ec05..63b43e018378c32be72c64437eff5fd475a7f307 100644 (file)
@@ -79,7 +79,7 @@ void physical_item_touch(entity this, entity toucher)
        }
 }
 
-void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void physical_item_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(!this.cnt) // not for dropped items
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
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 61c302c3e7e0fa74bdd67d0a81a67ea00012efe1..ee2a5be7f504d11c376bd85b31ec28b505b7eeec 100644 (file)
@@ -91,7 +91,7 @@ MUTATOR_HOOKFUNCTION(spawn_near_teammate, PlayerSpawn)
 
                        if (PHYS_INPUT_BUTTON_CHAT(it)) continue;
                        if (!SAME_TEAM(player, it)) continue;
-                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && it.health < autocvar_g_balance_health_regenstable) continue;
+                       if (autocvar_g_spawn_near_teammate_ignore_spawnpoint_check_health && GetResourceAmount(it, RESOURCE_HEALTH) < autocvar_g_balance_health_regenstable) continue;
                        if (IS_DEAD(it)) continue;
                        if (time < it.msnt_timer) continue;
                        if (time < it.spawnshieldtime) continue;
index a1b38fb6e750a2a44b6638189b6d18f3d89a3f0d..6be2c5963b69f4515b05b97be642e82b4b18560b 100644 (file)
@@ -20,7 +20,7 @@ void PlayerTouchExplode(entity p1, entity p2)
 
        entity e = spawn();
        setorigin(e, org);
-       RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, NULL);
+       RadiusDamage(e, NULL, autocvar_g_touchexplode_damage, autocvar_g_touchexplode_edgedamage, autocvar_g_touchexplode_radius, NULL, NULL, autocvar_g_touchexplode_force, DEATH_TOUCHEXPLODE.m_id, DMG_NOWEP, NULL);
        delete(e);
 }
 
index 199b4e202a7351a9b2d25bfb4364ec02119a259d..56198186f1492b1e27648ca7abe6491b6c0f4ce8 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)
 {
@@ -14,7 +14,7 @@ MUTATOR_HOOKFUNCTION(vampire, PlayerDamage_SplitHealthArmor)
        if(!IS_DEAD(frag_target))
        {
                GiveResource(frag_attacker, RESOURCE_HEALTH,
-                       bound(0, damage_take, frag_target.health));
+                       bound(0, damage_take, GetResourceAmount(frag_target, RESOURCE_HEALTH)));
        }
 }
 
index ce9e270654cb498281e01db990aa652e0ae8f8c1..115e6ca9109341fcaa4c61974eaafe416b342f15 100644 (file)
@@ -21,18 +21,16 @@ MUTATOR_HOOKFUNCTION(vh, GrappleHookThink)
        if(!STAT(FROZEN, thehook.aiment))
        if(time >= game_starttime)
        if(DIFF_TEAM(thehook.owner, thehook.aiment) || autocvar_g_vampirehook_teamheal)
-       if(thehook.aiment.health > 0)
+       if(GetResourceAmount(thehook.aiment, RESOURCE_HEALTH) > 0)
        if(autocvar_g_vampirehook_damage)
        {
                thehook.last_dmg = time + autocvar_g_vampirehook_damagerate;
                thehook.owner.damage_dealt += autocvar_g_vampirehook_damage;
-               Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, thehook.origin, '0 0 0');
-               if(SAME_TEAM(thehook.owner, thehook.aiment))
-                       thehook.aiment.health = min(thehook.aiment.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
-               else
-                       thehook.owner.health = min(thehook.owner.health + autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
+               Damage(dmgent, thehook, thehook.owner, autocvar_g_vampirehook_damage, WEP_HOOK.m_id, DMG_NOWEP, thehook.origin, '0 0 0');
+               entity targ = ((SAME_TEAM(thehook.owner, thehook.aiment)) ? thehook.aiment : thehook.owner);
+               Heal(targ, thehook.owner, autocvar_g_vampirehook_health_steal, g_pickup_healthsmall_max);
 
                if(dmgent == thehook.owner)
-                       dmgent.health -= autocvar_g_vampirehook_damage; // FIXME: friendly fire?!
+                       TakeResource(dmgent, RESOURCE_HEALTH, autocvar_g_vampirehook_damage); // FIXME: friendly fire?!
        }
 }
index 73f22b836ce6485c9a5e9164e96bf5238a14e95e..b527bdc1a84b020088603478e4007db063ce5c75 100644 (file)
@@ -1,64 +1,64 @@
 /** If you register a new waypoint, make sure to add it to this list */
 
-REGISTER_WAYPOINT(Waypoint, _("Waypoint"), '0 1 1', 1);
-REGISTER_WAYPOINT(Helpme, _("Help me!"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(Here, _("Here"), '0 1 0', 1);
-REGISTER_WAYPOINT(Danger, _("DANGER"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(Waypoint, _("Waypoint"), "", '0 1 1', 1);
+REGISTER_WAYPOINT(Helpme, _("Help me!"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(Here, _("Here"), "", '0 1 0', 1);
+REGISTER_WAYPOINT(Danger, _("DANGER"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(Frozen, _("Frozen!"), '0.25 0.90 1', 1);
+REGISTER_WAYPOINT(Frozen, _("Frozen!"), "", '0.25 0.90 1', 1);
 
-REGISTER_WAYPOINT(Item, _("Item"), '1 0 1', 1);
+REGISTER_WAYPOINT(Item, _("Item"), "", '1 0 1', 1);
 
-REGISTER_WAYPOINT(RaceCheckpoint, _("Checkpoint"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(RaceFinish, _("Finish"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(RaceStart, _("Start"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(RaceStartFinish, _("Start"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(RaceCheckpoint, _("Checkpoint"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(RaceFinish, _("Finish"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(RaceStart, _("Start"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(RaceStartFinish, _("Start"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(AssaultDefend, _("Defend"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(AssaultDestroy, _("Destroy"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(AssaultPush, _("Push"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(AssaultDefend, _("Defend"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(AssaultDestroy, _("Destroy"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(AssaultPush, _("Push"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(FlagCarrier, _("Flag carrier"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagCarrierEnemy, _("Enemy carrier"), '1 1 1', 1);
-REGISTER_WAYPOINT(FlagDropped, _("Dropped flag"), '1 1 1', 1);
-REGISTER_WAYPOINT(FlagBaseNeutral, _("White base"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagBaseRed, _("Red base"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagBaseBlue, _("Blue base"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagBaseYellow, _("Yellow base"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagBasePink, _("Pink base"), '0.8 0.8 0', 1);
-REGISTER_WAYPOINT(FlagReturn, _("Return flag here"), '0 0.8 0.8', 1);
+REGISTER_WAYPOINT(FlagCarrier, _("Flag carrier"), "", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagCarrierEnemy, _("Enemy carrier"), "flag_neutral_carrying", '1 1 1', 1);
+REGISTER_WAYPOINT(FlagDropped, _("Dropped flag"), "flag_neutral_lost", '1 1 1', 1);
+REGISTER_WAYPOINT(FlagBaseNeutral, _("White base"), "flag_neutral_taken", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagBaseRed, _("Red base"), "flag_red_taken", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagBaseBlue, _("Blue base"), "flag_blue_taken", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagBaseYellow, _("Yellow base"), "flag_yellow_taken", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagBasePink, _("Pink base"), "flag_pink_taken", '0.8 0.8 0', 1);
+REGISTER_WAYPOINT(FlagReturn, _("Return flag here"), "", '0 0.8 0.8', 1);
 
-REGISTER_WAYPOINT(DomNeut, _("Control point"), '0 1 1', 1);
-REGISTER_WAYPOINT(DomRed, _("Control point"), '0 1 1', 1);
-REGISTER_WAYPOINT(DomBlue, _("Control point"), '0 1 1', 1);
-REGISTER_WAYPOINT(DomYellow, _("Control point"), '0 1 1', 1);
-REGISTER_WAYPOINT(DomPink, _("Control point"), '0 1 1', 1);
+REGISTER_WAYPOINT(DomNeut, _("Control point"), "dom_icon_blue-highlighted", '0 1 1', 1);
+REGISTER_WAYPOINT(DomRed, _("Control point"), "dom_icon_red-highlighted", '0 1 1', 1);
+REGISTER_WAYPOINT(DomBlue, _("Control point"), "dom_icon_blue-highlighted", '0 1 1', 1);
+REGISTER_WAYPOINT(DomYellow, _("Control point"), "dom_icon_yellow-highlighted", '0 1 1', 1);
+REGISTER_WAYPOINT(DomPink, _("Control point"), "dom_icon_pink-highlighted", '0 1 1', 1);
 
-REGISTER_WAYPOINT(KeyDropped, _("Dropped key"), '0 1 1', 1);
-REGISTER_WAYPOINT(KeyCarrierFriend, _("Key carrier"), '0 1 0', 1);
-REGISTER_WAYPOINT(KeyCarrierFinish, _("Run here"), '0 1 1', 1);
-REGISTER_WAYPOINT(KeyCarrierRed, _("Key carrier"), '0 1 1', 1);
-REGISTER_WAYPOINT(KeyCarrierBlue, _("Key carrier"), '0 1 1', 1);
-REGISTER_WAYPOINT(KeyCarrierYellow, _("Key carrier"), '0 1 1', 1);
-REGISTER_WAYPOINT(KeyCarrierPink, _("Key carrier"), '0 1 1', 1);
+REGISTER_WAYPOINT(KeyDropped, _("Dropped key"), "kh_dropped", '0 1 1', 1);
+REGISTER_WAYPOINT(KeyCarrierFriend, _("Key carrier"), "", '0 1 0', 1);
+REGISTER_WAYPOINT(KeyCarrierFinish, _("Run here"), "", '0 1 1', 1);
+REGISTER_WAYPOINT(KeyCarrierRed, _("Key carrier"), "kh_red_carrying", '0 1 1', 1);
+REGISTER_WAYPOINT(KeyCarrierBlue, _("Key carrier"), "kh_blue_carrying", '0 1 1', 1);
+REGISTER_WAYPOINT(KeyCarrierYellow, _("Key carrier"), "kh_yellow_carrying", '0 1 1', 1);
+REGISTER_WAYPOINT(KeyCarrierPink, _("Key carrier"), "kh_pink_carrying", '0 1 1', 1);
 
-REGISTER_WAYPOINT(KaBall, _("Ball"), '0 1 1', 1);
-REGISTER_WAYPOINT(KaBallCarrier, _("Ball carrier"), '1 0 0', 1);
+REGISTER_WAYPOINT(KaBall, _("Ball"), "notify_ballpickedup", '0 1 1', 1);
+REGISTER_WAYPOINT(KaBallCarrier, _("Ball carrier"), "keepawayball_carrying", '1 0 0', 1);
 
-REGISTER_WAYPOINT(NbBall, _("Ball"), '0.91 0.85 0.62', 1);
-REGISTER_WAYPOINT(NbGoal, _("Goal"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(NbBall, _("Ball"), "", '0.91 0.85 0.62', 1);
+REGISTER_WAYPOINT(NbGoal, _("Goal"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(OnsCP, _("Control point"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(OnsCPDefend, _("Control point"), '1 0.5 0', 0.5);
-REGISTER_WAYPOINT(OnsCPAttack, _("Control point"), '1 0.5 0', 2);
-REGISTER_WAYPOINT(OnsGen, _("Generator"), '1 0.5 0', 1);
-REGISTER_WAYPOINT(OnsGenShielded, _("Generator"), '1 0.5 0', 1);
+REGISTER_WAYPOINT(OnsCP, _("Control point"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(OnsCPDefend, _("Control point"), "", '1 0.5 0', 0.5);
+REGISTER_WAYPOINT(OnsCPAttack, _("Control point"), "", '1 0.5 0', 2);
+REGISTER_WAYPOINT(OnsGen, _("Generator"), "", '1 0.5 0', 1);
+REGISTER_WAYPOINT(OnsGenShielded, _("Generator"), "", '1 0.5 0', 1);
 
-REGISTER_WAYPOINT(Weapon, _("Weapon"), '0 0 0', 1);
+REGISTER_WAYPOINT(Weapon, _("Weapon"), "", '0 0 0', 1);
 
-REGISTER_WAYPOINT(Monster, _("Monster"), '1 0 0', 1);
+REGISTER_WAYPOINT(Monster, _("Monster"), "", '1 0 0', 1);
 
-REGISTER_WAYPOINT(Vehicle, _("Vehicle"), '1 1 1', 1);
-REGISTER_WAYPOINT(VehicleIntruder, _("Intruder!"), '1 1 1', 1);
+REGISTER_WAYPOINT(Vehicle, _("Vehicle"), "", '1 1 1', 1);
+REGISTER_WAYPOINT(VehicleIntruder, _("Intruder!"), "", '1 1 1', 1);
 
-REGISTER_WAYPOINT(Seeker, _("Tagged"), '0.5 1 0', 2);
+REGISTER_WAYPOINT(Seeker, _("Tagged"), "", '0.5 1 0', 2);
index 77c4312001de399edeaaddd1d9a1abcc7de55020..13260023760f977ea1a70cea96c92928635eb10b 100644 (file)
@@ -14,18 +14,20 @@ CLASS(Waypoint, Object)
     ATTRIB(Waypoint, m_id, int, 0);
     ATTRIB(Waypoint, netname, string);
     ATTRIB(Waypoint, m_name, string);
+    ATTRIB(Waypoint, m_icon, string);
     ATTRIB(Waypoint, m_color, vector, '1 1 1');
     ATTRIB(Waypoint, m_blink, int, 1);
-    CONSTRUCTOR(Waypoint, string _netname, string _name, vector _color, int _blink) {
+    CONSTRUCTOR(Waypoint, string _netname, string _name, string _icon, vector _color, int _blink) {
         CONSTRUCT(Waypoint);
         this.netname = _netname;
         this.m_name = _name;
+        this.m_icon = _icon;
         this.m_color = _color;
         this.m_blink = _blink;
     }
 ENDCLASS(Waypoint)
 
-#define REGISTER_WAYPOINT(id, text, color, blink) REGISTER_WAYPOINT_(id, NEW(Waypoint, #id, text, color, blink))
+#define REGISTER_WAYPOINT(id, text, icon, color, blink) REGISTER_WAYPOINT_(id, NEW(Waypoint, #id, text, icon, color, blink))
 
 REGISTRY(RadarIcons, BITS(7))
 #define RadarIcons_from(i) _RadarIcons_from(i, RADARICON_NONE)
@@ -35,7 +37,7 @@ REGISTRY_CHECK(RadarIcons)
 .int m_radaricon;
 #define REGISTER_RADARICON(id, num) REGISTER(RadarIcons, RADARICON, id, m_id, new_pure(RadarIcon)) { this.m_radaricon = num; this.netname = #id; }
 
-REGISTER_WAYPOINT(Null, "", '0 0 0', 1);
+REGISTER_WAYPOINT(Null, "", "", '0 0 0', 1);
 
 REGISTER_RADARICON(NONE,            0);
 REGISTER_RADARICON(FLAG,            1);
index 6dec163fa237c97f0492f9dfc83a32fadb79f425..dcbb65f65cd29472659141b93617b7a8182c2075 100644 (file)
@@ -34,7 +34,7 @@ bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
     {
         if (this.max_health)
         {
-            WriteByte(MSG_ENTITY, (this.health / this.max_health) * 191.0);
+            WriteByte(MSG_ENTITY, (GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 191.0);
         }
         else
         {
@@ -47,9 +47,7 @@ bool WaypointSprite_SendEntity(entity this, entity to, float sendflags)
 
     if (sendflags & 64)
     {
-        WriteCoord(MSG_ENTITY, this.origin.x);
-        WriteCoord(MSG_ENTITY, this.origin.y);
-        WriteCoord(MSG_ENTITY, this.origin.z);
+        WriteVector(MSG_ENTITY, this.origin);
     }
 
     if (sendflags & 1)
@@ -108,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] */
@@ -136,7 +134,7 @@ void Ent_WaypointSprite(entity this, bool isnew)
         int t = ReadByte();
         if (t < 192)
         {
-            this.health = t / 191.0;
+            SetResourceAmountExplicit(this, RESOURCE_HEALTH, t / 191.0);
             this.build_finished = 0;
         }
         else
@@ -144,7 +142,7 @@ void Ent_WaypointSprite(entity this, bool isnew)
             t = (t - 192) * 256 + ReadByte();
             this.build_started = servertime;
             if (this.build_finished)
-                this.build_starthealth = bound(0, this.health, 1);
+                this.build_starthealth = bound(0, GetResourceAmount(this, RESOURCE_HEALTH), 1);
             else
                 this.build_starthealth = 0;
             this.build_finished = servertime + t / 32;
@@ -152,16 +150,14 @@ void Ent_WaypointSprite(entity this, bool isnew)
     }
     else
     {
-        this.health = -1;
+        SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
         this.build_finished = 0;
     }
 
     if (sendflags & 64)
     {
         // unfortunately, this needs to be exact (for the 3D display)
-        this.origin_x = ReadCoord();
-        this.origin_y = ReadCoord();
-        this.origin_z = ReadCoord();
+        this.origin = ReadVector();
         setorigin(this, this.origin);
     }
 
@@ -173,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)
@@ -249,6 +239,8 @@ vector spritelookupcolor(entity this, string s, vector def)
 
 string spritelookuptext(entity this, string s)
 {
+       if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
+               return "Spam"; // no need to translate this debug string
     if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
     if (s == WP_Weapon.netname) return Weapons_from(this.wp_extra).m_name;
     if (s == WP_Item.netname) return Items_from(this.wp_extra).m_waypoint;
@@ -265,6 +257,26 @@ string spritelookuptext(entity this, string s)
 
     return s;
 }
+
+string spritelookupicon(entity this, string s)
+{
+    // TODO: needs icons! //if (s == WP_RaceStartFinish.netname) return (race_checkpointtime || race_mycheckpointtime) ? _("Finish") : _("Start");
+    if (s == WP_Weapon.netname) return Weapons_from(this.wp_extra).model2;
+    if (s == WP_Item.netname) return Items_from(this.wp_extra).m_icon;
+    if (s == WP_Vehicle.netname) return Vehicles_from(this.wp_extra).m_icon;
+    //if (s == WP_Monster.netname) return get_monsterinfo(this.wp_extra).m_icon;
+    if (MUTATOR_CALLHOOK(WP_Format, this, s))
+    {
+        return M_ARGV(4, string);
+    }
+
+    // need to loop, as our netname could be one of three
+    FOREACH(Waypoints, it.netname == s, {
+        return it.m_icon;
+    });
+
+    return s;
+}
 #endif
 
 #ifdef CSQC
@@ -364,18 +376,22 @@ vector drawspritearrow(vector o, float ang, vector rgb, float a, float t)
 }
 
 // returns location of sprite healthbar
-vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s)
+vector drawsprite_TextOrIcon(bool is_text, vector o, float ang, float minwidth, vector rgb, float a, vector sz, string str)
 {
     float algnx, algny;
     float sw, w, h;
     float aspect, sa, ca;
 
-    sw = stringwidth(s, false, fontsize);
+    if (is_text)
+        sw = stringwidth(str, false, sz);
+    else
+        sw = sz.x;
+
     if (sw > minwidth)
         w = sw;
     else
         w = minwidth;
-    h = fontsize.y;
+    h = sz.y;
 
     // how do corners work?
     aspect = vid_conwidth / vid_conheight;
@@ -406,11 +422,14 @@ vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a,
     if (o.x > vid_conwidth - w)
         o.x = vid_conwidth - w;
     if (o.y > vid_conheight - h)
-        o.x = vid_conheight - h;
+        o.y = vid_conheight - h;
 
     o.x += 0.5 * (w - sw);
 
-    drawstring(o, s, fontsize, rgb, a, DRAWFLAG_NORMAL);
+    if (is_text)
+        drawstring(o, str, sz, rgb, a, DRAWFLAG_NORMAL);
+    else
+        drawpic(o, str, sz, rgb, a, DRAWFLAG_NORMAL);
 
     o.x += 0.5 * sw;
     o.y += 0.5 * h;
@@ -564,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) {
@@ -634,46 +654,79 @@ void Draw_WaypointSprite(entity this)
         if (time < this.build_finished + 0.25)
         {
             if (time < this.build_started)
-                this.health = this.build_starthealth;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.build_starthealth);
             else if (time < this.build_finished)
-                this.health = (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, (time - this.build_started) / (this.build_finished - this.build_started) * (1 - this.build_starthealth) + this.build_starthealth);
             else
-                this.health = 1;
+                SetResourceAmountExplicit(this, RESOURCE_HEALTH, 1);
         }
         else
-            this.health = -1;
+            SetResourceAmountExplicit(this, RESOURCE_HEALTH, -1);
     }
 
     o = drawspritearrow(o, ang, rgb, a, SPRITE_ARROW_SCALE * t);
 
-    string txt;
-    if (autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
-        txt = _("Spam");
-    else
+       string pic = "";
+       bool is_text = true;
+       if (!autocvar_g_waypointsprite_text)
+       {
+               string spr_icon = spritelookupicon(this, spriteimage);
+               pic = spr_icon;
+               bool icon_found = !(!spr_icon || spr_icon == "");
+               if (icon_found) // it's valid, but let's make sure it exists!
+               {
+                       pic = strcat(hud_skin_path, "/", spr_icon);
+                       if(precache_pic(pic) == "")
+                       {
+                               pic = strcat("gfx/hud/default/", spr_icon);
+                               if(!precache_pic(pic))
+                                       icon_found = false;
+                       }
+               }
+               if (icon_found)
+                       is_text = false;
+       }
+
+       vector sz;
+       vector txt_color;
+    string txt = string_null;
+    if (is_text)
+    {
         txt = spritelookuptext(this, spriteimage);
-    if (this.helpme && time < this.helpme)
-        txt = sprintf(_("%s needing help!"), txt);
-    if (autocvar_g_waypointsprite_uppercase)
-        txt = strtoupper(txt);
+        if (this.helpme && time < this.helpme)
+            txt = sprintf(_("%s needing help!"), txt);
+        if (autocvar_g_waypointsprite_uppercase)
+            txt = strtoupper(txt);
+        txt_color = rgb;
+        sz = waypointsprite_fontsize * '1 1 0';
+    }
+    else
+    {
+        // for convenience icon path and color are saved to txt and txt_color
+        txt = pic;
+        txt_color = ((autocvar_g_waypointsprite_iconcolor) ? '1 1 1' : rgb);
+        sz = autocvar_g_waypointsprite_iconsize * '1 1 0';
+    }
 
     draw_beginBoldFont();
-    if (this.health >= 0)
+    if (GetResourceAmount(this, RESOURCE_HEALTH) >= 0)
     {
-        o = drawspritetext(o, ang, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
-
-        float align, marg;
+        float align = 0, marg;
         if (this.build_finished)
             align = 0.5;
         else
             align = 0;
         if (cos(ang) > 0)
-            marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * waypointsprite_fontsize;
+            marg = -(SPRITE_HEALTHBAR_MARGIN + SPRITE_HEALTHBAR_HEIGHT + 2 * SPRITE_HEALTHBAR_BORDER) * t - 0.5 * sz.y;
         else
-            marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize;
+            marg = SPRITE_HEALTHBAR_MARGIN * t + 0.5 * sz.y;
+
+        float minwidth = (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t;
+        o = drawsprite_TextOrIcon(is_text, o, ang, minwidth, txt_color, a, sz, txt);
         drawhealthbar(
                 o,
                 0,
-                this.health,
+                GetResourceAmount(this, RESOURCE_HEALTH),
                 '0 0 0',
                 '0 0 0',
                 SPRITE_HEALTHBAR_WIDTH * t,
@@ -690,8 +743,9 @@ void Draw_WaypointSprite(entity this)
     }
     else
     {
-        o = drawspritetext(o, ang, 0, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+        drawsprite_TextOrIcon(is_text, o, ang, 0, txt_color, a, sz, txt);
     }
+
     draw_endBoldFont();
 }
 
@@ -777,9 +831,9 @@ void WaypointSprite_UpdateSprites(entity e, entity _m1, entity _m2, entity _m3)
 void WaypointSprite_UpdateHealth(entity e, float f)
 {
     f = bound(0, f, e.max_health);
-    if (f != e.health || e.pain_finished)
+    if (f != GetResourceAmount(e, RESOURCE_HEALTH) || e.pain_finished)
     {
-        e.health = f;
+        SetResourceAmountExplicit(e, RESOURCE_HEALTH, f);
         e.pain_finished = 0;
         e.SendFlags |= 0x80;
     }
@@ -1106,10 +1160,10 @@ entity WaypointSprite_AttachCarrier(
 {
     WaypointSprite_Kill(carrier.waypointsprite_attached); // FC overrides attached
     entity e = WaypointSprite_Spawn(spr, 0, 0, carrier, '0 0 64', NULL, carrier.team, carrier, waypointsprite_attachedforcarrier, false, icon);
-    if (carrier.health)
+    if (GetResourceAmount(carrier, RESOURCE_HEALTH))
     {
         WaypointSprite_UpdateMaxHealth(e, '1 0 0' * healtharmor_maxdamage(start_health, start_armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id) * 2);
-        WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(carrier.health, carrier.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+        WaypointSprite_UpdateHealth(e, '1 0 0' * healtharmor_maxdamage(GetResourceAmount(carrier, RESOURCE_HEALTH), GetResourceAmount(carrier, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
     }
     return e;
 }
index 6a8d57157c010f0fbb10c9fa22b9865292b31bea..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;
@@ -53,6 +53,9 @@ float autocvar_g_waypointsprite_timealphaexponent;
 bool autocvar_g_waypointsprite_turrets = true;
 float autocvar_g_waypointsprite_turrets_maxdist = 5000;
 bool autocvar_g_waypointsprite_uppercase;
+bool autocvar_g_waypointsprite_text;
+float autocvar_g_waypointsprite_iconsize = 32;
+bool autocvar_g_waypointsprite_iconcolor;
 
 float waypointsprite_fadedistance;
 float waypointsprite_normdistance;
@@ -98,7 +101,7 @@ void drawhealthbar(vector org, float rot, float h, vector sz, vector hotspot, fl
 vector drawspritearrow(vector o, float ang, vector rgb, float a, float t);
 
 // returns location of sprite healthbar
-vector drawspritetext(vector o, float ang, float minwidth, vector rgb, float a, vector fontsize, string s);
+vector drawsprite_TextOrIcon(bool is_text, vector o, float ang, float minwidth, vector rgb, float a, vector sz, string str);
 
 float spritelookupblinkvalue(entity this, string s);
 vector spritelookupcolor(entity this, string s, vector def);
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..a15ef80d1e7f8feece7b0dc8f7927e3962d50db0 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_CENTER_NOTIF(ITEM_BUFF_DROP,                    N_ENABLE,    0, 1, "item_buffname",                      CPID_ITEM, "item_centime 0", _("^BGYou dropped the %s^BG buff!"), "")
     MSG_CENTER_NOTIF(ITEM_BUFF_GOT,                     N_ENABLE,    0, 1, "item_buffname",                      CPID_ITEM, "item_centime 0", _("^BGYou got the %s^BG buff!"), "")
     MSG_CENTER_NOTIF(ITEM_FUELREGEN_GOT,                N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Fuel regenerator"), "")
-    MSG_CENTER_NOTIF(ITEM_JETPACK_GOT,                  N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Jet pack"), "")
+    MSG_CENTER_NOTIF(ITEM_JETPACK_GOT,                  N_ENABLE,    0, 0, "",                                   CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1Jetpack"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_DONTHAVE,              N_ENABLE,    0, 1, "item_wepname",                       CPID_ITEM, "item_centime 0", _("^BGYou do not have the ^F1%s"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_DROP,                  N_ENABLE,    1, 1, "item_wepname item_wepammo",          CPID_ITEM, "item_centime 0", _("^BGYou dropped the ^F1%s^BG%s"), "")
     MSG_CENTER_NOTIF(ITEM_WEAPON_GOT,                   N_ENABLE,    0, 1, "item_wepname",                       CPID_ITEM, "item_centime 0", _("^BGYou got the ^F1%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 3fe2808583b94254d580b3c3960b2610c9192e6f..9ac3e4299901db21051d4ea2f206fe8636bbfa30 100644 (file)
@@ -351,37 +351,50 @@ void _Movetype_LinkEdict_TouchAreaGrid(entity this)  // SV_LinkEdict_TouchAreaGr
     });
 }
 
+bool autocvar__movetype_debug = false;
 void _Movetype_LinkEdict(entity this, bool touch_triggers)  // SV_LinkEdict
 {
-       vector mi, ma;
-       if(this.solid == SOLID_BSP)
+       if(autocvar__movetype_debug)
        {
-               // TODO set the absolute bbox
-               mi = this.mins;
-               ma = this.maxs;
-       }
-       else
-       {
-               mi = this.mins;
-               ma = this.maxs;
-       }
-       mi += this.origin;
-       ma += this.origin;
+               vector mi, ma;
+               if(this.solid == SOLID_BSP)
+               {
+                       // TODO set the absolute bbox
+                       mi = this.mins;
+                       ma = this.maxs;
+               }
+               else
+               {
+                       mi = this.mins;
+                       ma = this.maxs;
+               }
+               mi += this.origin;
+               ma += this.origin;
 
-       if(this.flags & FL_ITEM)
-       {
-               mi -= '15 15 1';
-               ma += '15 15 1';
+               if(this.flags & FL_ITEM)
+               {
+                       mi -= '15 15 1';
+                       ma += '15 15 1';
+               }
+               else
+               {
+                       mi -= '1 1 1';
+                       ma += '1 1 1';
+               }
+
+               this.absmin = mi;
+               this.absmax = ma;
        }
        else
        {
-               mi -= '1 1 1';
-               ma += '1 1 1';
+               setorigin(this, this.origin); // calls SV_LinkEdict
+       #ifdef CSQC
+               // NOTE: CSQC's version of setorigin doesn't expand
+               this.absmin -= '1 1 1';
+               this.absmax += '1 1 1';
+       #endif
        }
 
-       this.absmin = mi;
-       this.absmax = ma;
-
        if(touch_triggers)
                _Movetype_LinkEdict_TouchAreaGrid(this);
 }
@@ -519,6 +532,8 @@ void _Movetype_Physics_Frame(entity this, float movedt)
                case MOVETYPE_FLY:
                case MOVETYPE_FLY_WORLDONLY:
                        _Movetype_Physics_Toss(this, movedt);
+                       if(wasfreed(this))
+                               return;
                        _Movetype_LinkEdict(this, true);
                        break;
                case MOVETYPE_PHYSICS:
index 7d3cab007b508fa6dafceb84a14585d0fd68f327..2f4ebb1ff002c9c37278901d70a4838bb0e043e1 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;
@@ -781,7 +792,7 @@ void PM_jetpack(entity this, float maxspd_mod, float dt)
 
 #ifdef SVQC
                if (!(ITEMS_STAT(this) & IT_UNLIMITED_WEAPON_AMMO))
-                       this.ammo_fuel -= PHYS_JETPACK_FUEL(this) * dt * fvel * f;
+                       TakeResource(this, RESOURCE_FUEL, PHYS_JETPACK_FUEL(this) * dt * fvel * f);
 
                ITEMS_STAT(this) |= IT_USING_JETPACK;
 
index 0ebea585f80e61071cedd24e4c8e2d22abdec445..da48fa698c2086e34049c7fc1ffeb0f9599d5a87 100644 (file)
 .float lastflags;
 .float lastground;
 .float wasFlying;
-#ifdef SVQC
-.float spectatorspeed = _STAT(SPECTATORSPEED);
-#elif defined(CSQC)
-.float spectatorspeed;
-#endif
 
 .int buttons_old;
 .vector movement_old;
@@ -106,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)
@@ -125,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
 
@@ -245,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
 
@@ -260,9 +248,6 @@ STATIC_INIT(PHYS_INPUT_BUTTON_DODGE)
 
        void PM_UpdateButtons(entity this, entity store);
 
-       .float stat_sv_airspeedlimit_nonqw = _STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW);
-       .float stat_sv_maxspeed = _STAT(MOVEVARS_MAXSPEED);
-
        /** Not real stats */
        .string jumpspeedcap_min;
        .string jumpspeedcap_max;
@@ -300,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 a562292b40a5c5bcd7f00d779f647c2a3bb87357..8e33c649b3bf5e68e09b5050252f53f48002e8b7 100644 (file)
@@ -5,6 +5,10 @@
 /// \author Lyberta
 /// \copyright GNU GPLv2 or any later version.
 
+/// \brief Unconditional maximum amount of resources the entity can have.
+const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
+const int RESOURCE_LIMIT_NONE = -1;
+
 /// \brief Describes the available resource types.
 enum
 {
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 ea936185b95ee2b1227a58be5664a7e2ecfda30c..37813ef716c0bd5f393bc45a1f2fad39036e7b0b 100644 (file)
@@ -31,7 +31,6 @@ void PlayerScore_Attach(entity this);
 void ClientData_Attach(entity this);
 void accuracy_init(entity this);
 void entcs_attach(entity this);
-void playerdemo_init(entity this);
 void anticheat_init(entity this);
 void W_HitPlotOpen(entity this);
 void bot_clientconnect(entity this);
@@ -51,7 +50,6 @@ void ClientState_attach(entity this)
        ClientData_Attach(this);
        accuracy_init(this);
        entcs_attach(this);
-       playerdemo_init(this);
        anticheat_init(this);
        W_HitPlotOpen(this);
 
@@ -61,7 +59,6 @@ void ClientState_attach(entity this)
 void bot_clientdisconnect(entity this);
 void W_HitPlotClose(entity this);
 void anticheat_report_to_eventlog(entity this);
-void playerdemo_shutdown(entity this);
 void entcs_detach(entity this);
 void accuracy_free(entity this);
 void ClientData_Detach(entity this);
@@ -81,6 +78,5 @@ void ClientState_detach(entity this)
     bot_clientdisconnect(this);
 
     anticheat_report_to_eventlog(this);
-    playerdemo_shutdown(this);
     entcs_detach(this);
 }
index daa1d3c8b7bd205640288198c94a0eb7f010dede..9b8f04041780fd55f707331540c74ab99b0e8e88 100644 (file)
@@ -73,7 +73,6 @@ REGISTER_STAT(GAMESTARTTIME, float, game_starttime)
 REGISTER_STAT(STRENGTH_FINISHED, float)
 REGISTER_STAT(INVINCIBLE_FINISHED, float)
 /** arc heat in [0,1] */
-REGISTER_STAT(ARC_HEAT, float)
 REGISTER_STAT(PRESSED_KEYS, int)
 /** this stat could later contain some other bits of info, like, more server-side particle config */
 REGISTER_STAT(ALLOW_OLDVORTEXBEAM, bool, autocvar_g_allow_oldvortexbeam)
@@ -82,18 +81,12 @@ REGISTER_STAT(NB_METERSTART, float)
 /** compressShotOrigin */
 REGISTER_STAT(SHOTORG, int)
 REGISTER_STAT(LEADLIMIT, float, autocvar_leadlimit)
-REGISTER_STAT(WEAPON_CLIPLOAD, int)
-REGISTER_STAT(WEAPON_CLIPSIZE, int)
 
-REGISTER_STAT(VORTEX_CHARGE, float)
 REGISTER_STAT(LAST_PICKUP, float)
 REGISTER_STAT(HUD, int)
-REGISTER_STAT(VORTEX_CHARGEPOOL, float)
 REGISTER_STAT(HIT_TIME, float)
 REGISTER_STAT(DAMAGE_DEALT_TOTAL, int)
 REGISTER_STAT(TYPEHIT_TIME, float)
-REGISTER_STAT(LAYED_MINES, int)
-REGISTER_STAT(HAGAR_LOAD, int)
 REGISTER_STAT(SUPERWEAPONS_FINISHED, float)
 REGISTER_STAT(VEHICLESTAT_HEALTH, int)
 REGISTER_STAT(VEHICLESTAT_SHIELD, int)
@@ -127,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;
@@ -306,6 +306,13 @@ REGISTER_STAT(SLICK_APPLYGRAVITY, bool, autocvar_sv_slick_applygravity)
 float warmup_limit;
 #endif
 
+#ifdef SVQC
+bool autocvar_g_shootfromcenter;
+bool autocvar_g_shootfromeye;
+#endif
+REGISTER_STAT(SHOOTFROMEYE, bool, autocvar_g_shootfromeye)
+REGISTER_STAT(SHOOTFROMCENTER, bool, autocvar_g_shootfromcenter)
+
 REGISTER_STAT(MOVEVARS_AIRACCEL_QW_STRETCHFACTOR, float)
 REGISTER_STAT(MOVEVARS_AIRCONTROL_PENALTY, float)
 REGISTER_STAT(MOVEVARS_AIRSPEEDLIMIT_NONQW, float)
index e13df065a477b5f0f95a7370c484c5968a444ba4..140b619c5ec09cae3f8c62fcf1e87bb6c4b61c2b 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)
@@ -158,9 +162,7 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
 
     if(sf & ISF_LOCATION)
     {
-        this.origin_x = ReadCoord();
-        this.origin_y = ReadCoord();
-        this.origin_z = ReadCoord();
+        this.origin = ReadVector();
         setorigin(this, this.origin);
         this.oldorigin = this.origin;
     }
@@ -213,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!
 
@@ -225,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);
@@ -267,9 +277,7 @@ NET_HANDLE(ENT_CLIENT_ITEM, bool isnew)
         this.pushable = true;
         //this.angles = '0 0 0';
         set_movetype(this, MOVETYPE_TOSS);
-        this.velocity_x = ReadCoord();
-        this.velocity_y = ReadCoord();
-        this.velocity_z = ReadCoord();
+        this.velocity = ReadVector();
         setorigin(this, this.oldorigin);
 
         if(!this.move_time)
@@ -311,9 +319,7 @@ bool ItemSend(entity this, entity to, int sf)
        //WriteByte(MSG_ENTITY, this.cnt);
        if(sf & ISF_LOCATION)
        {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
+               WriteVector(MSG_ENTITY, this.origin);
        }
 
        if(sf & ISF_ANGLES)
@@ -356,9 +362,7 @@ bool ItemSend(entity this, entity to, int sf)
 
        if(sf & ISF_DROP)
        {
-               WriteCoord(MSG_ENTITY, this.velocity.x);
-               WriteCoord(MSG_ENTITY, this.velocity.y);
-               WriteCoord(MSG_ENTITY, this.velocity.z);
+               WriteVector(MSG_ENTITY, this.velocity);
        }
 
        return true;
@@ -392,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);
@@ -448,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)
@@ -508,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);
@@ -593,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);
@@ -613,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);
@@ -626,6 +603,7 @@ AUTOCVAR(g_pickup_respawntime_scaling_reciprocal, float, 0.0, "Multiply respawn
 AUTOCVAR(g_pickup_respawntime_scaling_offset, float, 0.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening");
 AUTOCVAR(g_pickup_respawntime_scaling_linear, float, 1.0, "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `linear` can be used to simply scale the respawn time linearly");
 
+/// Adjust respawn time according to the number of players.
 float adjust_respawntime(float normal_respawntime) {
        float r = autocvar_g_pickup_respawntime_scaling_reciprocal;
        float o = autocvar_g_pickup_respawntime_scaling_offset;
@@ -660,17 +638,49 @@ void Item_ScheduleRespawn(entity e)
                //LOG_INFOF("item %s will respawn in %f", e.classname, adjusted_respawntime);
 
                // range: adjusted_respawntime - respawntimejitter .. adjusted_respawntime + respawntimejitter
-               float actual_time = adjusted_respawntime + crandom() * e.respawntimejitter;
-               Item_ScheduleRespawnIn(e, actual_time);
+               float respawn_in = adjusted_respawntime + crandom() * e.respawntimejitter;
+               Item_ScheduleRespawnIn(e, respawn_in);
        }
        else // if respawntime is -1, this item does not respawn
                Item_Show(e, -1);
 }
 
+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");
+
 void Item_ScheduleInitialRespawn(entity e)
 {
        Item_Show(e, 0);
-       Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : ITEM_RESPAWNTIME_INITIAL(e)));
+
+       float spawn_in;
+       if (autocvar_g_pickup_respawntime_initial_random == 0)
+       {
+               // range: respawntime .. respawntime + respawntimejitter
+               spawn_in = e.respawntime + random() * e.respawntimejitter;
+       }
+       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 + rnd * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
+       }
+
+       Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : spawn_in));
 }
 
 void GiveRandomWeapons(entity receiver, int num_weapons, string weapon_names,
@@ -691,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;
@@ -702,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;
@@ -732,14 +742,14 @@ float Item_GiveAmmoTo(entity item, entity player, int resource_type, float ammom
                {
                        return false;
                }
-               GiveResourceWithLimit(player, resource_type, amount, ammomax);
+               GiveOrTakeResourceWithLimit(player, resource_type, amount, ammomax);
                return true;
        }
        if (g_weapon_stay != 2)
        {
                return false;
        }
-       GiveResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
+       GiveOrTakeResourceWithLimit(player, resource_type, amount, min(amount, ammomax));
        return true;
 }
 
@@ -764,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);
                        }
                }
@@ -780,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))
                {
@@ -814,7 +824,8 @@ float Item_GiveTo(entity item, entity player)
        {
                pickedup = true;
                player.items |= its;
-               Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
+               // TODO: we probably want to show a message in the console, but not this one!
+               //Send_Notification(NOTIF_ONE, player, MSG_INFO, INFO_ITEM_WEAPON_GOT, item.netname);
        }
 
        if (item.strength_finished)
@@ -915,7 +926,7 @@ void Item_Touch(entity this, entity toucher)
 
 LABEL(pickup)
 
-       toucher.last_pickup = time;
+       STAT(LAST_PICKUP, toucher) = time;
 
        Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
        _sound (toucher, (this.itemdef.instanceOfPowerup ? CH_TRIGGER_SINGLE : CH_TRIGGER), (this.item_pickupsound ? this.item_pickupsound : Sound_fixpath(this.item_pickupsound_ent)), VOL_BASE, ATTEN_NORM);
@@ -971,7 +982,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);
        }
@@ -1030,7 +1041,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)
@@ -1041,7 +1052,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;
@@ -1060,12 +1071,12 @@ float ammo_pickupevalfunc(entity player, entity item)
        if(item.itemdef.instanceOfWeaponPickup)
        {
                entity ammo = NULL;
-               if(item.ammo_shells)       { need_shells  = true; ammo = ITEM_Shells;      }
-               else if(item.ammo_nails)   { need_nails   = true; ammo = ITEM_Bullets;     }
-               else if(item.ammo_rockets) { need_rockets = true; ammo = ITEM_Rockets;     }
-               else if(item.ammo_cells)   { need_cells   = true; ammo = ITEM_Cells;       }
-               else if(item.ammo_plasma)  { need_plasma  = true; ammo = ITEM_Plasma;      }
-               else if(item.ammo_fuel)    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
+               if(GetResourceAmount(item, RESOURCE_SHELLS))       { need_shells  = true; ammo = ITEM_Shells;      }
+               else if(GetResourceAmount(item, RESOURCE_BULLETS))   { need_nails   = true; ammo = ITEM_Bullets;     }
+               else if(GetResourceAmount(item, RESOURCE_ROCKETS)) { need_rockets = true; ammo = ITEM_Rockets;     }
+               else if(GetResourceAmount(item, RESOURCE_CELLS))   { need_cells   = true; ammo = ITEM_Cells;       }
+               else if(GetResourceAmount(item, RESOURCE_PLASMA))  { need_plasma  = true; ammo = ITEM_Plasma;      }
+               else if(GetResourceAmount(item, RESOURCE_FUEL))    { need_fuel    = true; ammo = ITEM_JetpackFuel; }
 
                if(!ammo)
                        return 0;
@@ -1075,7 +1086,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)
@@ -1093,23 +1104,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) && GetResourceAmount(item, RESOURCE_SHELLS) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
+               c = GetResourceAmount(item, RESOURCE_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) && GetResourceAmount(item, RESOURCE_BULLETS) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
+               c = GetResourceAmount(item, RESOURCE_BULLETS) / 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) && GetResourceAmount(item, RESOURCE_ROCKETS) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
+               c = GetResourceAmount(item, RESOURCE_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) && GetResourceAmount(item, RESOURCE_CELLS) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
+               c = GetResourceAmount(item, RESOURCE_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) && GetResourceAmount(item, RESOURCE_PLASMA) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
+               c = GetResourceAmount(item, RESOURCE_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) && GetResourceAmount(item, RESOURCE_FUEL) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
+               c = GetResourceAmount(item, RESOURCE_FUEL) / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
 
        rating *= min(c, 2);
        if(wpn)
@@ -1122,8 +1133,8 @@ float healtharmor_pickupevalfunc(entity player, entity item)
        float c = 0;
        float rating = item.bot_pickupbasevalue;
 
-       float itemarmor = item.armorvalue;
-       float itemhealth = item.health;
+       float itemarmor = GetResourceAmount(item, RESOURCE_ARMOR);
+       float itemhealth = GetResourceAmount(item, RESOURCE_HEALTH);
 
        if(item.item_group)
        {
@@ -1131,17 +1142,17 @@ float healtharmor_pickupevalfunc(entity player, entity item)
                itemhealth *= min(4, item.item_group_count);
        }
 
-       if (itemarmor && (player.armorvalue < item.max_armorvalue))
-               c = itemarmor / max(1, player.armorvalue * 2/3 + player.health * 1/3);
+       if (itemarmor && (GetResourceAmount(player, RESOURCE_ARMOR) < item.max_armorvalue))
+               c = itemarmor / max(1, GetResourceAmount(player, RESOURCE_ARMOR) * 2/3 + GetResourceAmount(player, RESOURCE_HEALTH) * 1/3);
 
-       if (itemhealth && (player.health < item.max_health))
-               c = itemhealth / max(1, player.health);
+       if (itemhealth && (GetResourceAmount(player, RESOURCE_HEALTH) < item.max_health))
+               c = itemhealth / max(1, GetResourceAmount(player, RESOURCE_HEALTH));
 
        rating *= min(2, c);
        return rating;
 }
 
-void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void Item_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(ITEM_DAMAGE_NEEDKILL(deathtype))
                RemoveItem(this);
@@ -1168,7 +1179,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
        {
@@ -1191,7 +1202,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);
@@ -1324,7 +1335,7 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
                if(def.instanceOfPowerup)
                        this.ItemStatus |= ITS_ANIMATE1;
 
-               if(this.armorvalue || this.health)
+               if(GetResourceAmount(this, RESOURCE_ARMOR) || GetResourceAmount(this, RESOURCE_HEALTH))
                        this.ItemStatus |= ITS_ANIMATE2;
        }
 
@@ -1492,7 +1503,7 @@ spawnfunc(target_items)
                                        s = Buff_UndeprecateName(argv(j));
                                        if(s == it.m_name)
                                        {
-                                               this.buffs |= (it.m_itemid);
+                                               STAT(BUFFS, this) |= (it.m_itemid);
                                                break;
                                        }
                                });
@@ -1500,7 +1511,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;
@@ -1544,16 +1555,16 @@ spawnfunc(target_items)
                this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, this.superweapons_finished * boolean(this.items & IT_SUPERWEAPON), "superweapons");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_Jetpack.m_itemid), "jetpack");
                this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, boolean(this.items & ITEM_JetpackRegen.m_itemid), "fuel_regen");
-               if(this.ammo_shells != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_shells), "shells");
-               if(this.ammo_nails != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_nails), "nails");
-               if(this.ammo_rockets != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_rockets), "rockets");
-               if(this.ammo_cells != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_cells), "cells");
-               if(this.ammo_plasma != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_plasma), "plasma");
-               if(this.ammo_fuel != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.ammo_fuel), "fuel");
-               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, !!(this.buffs & (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));
+               if(GetResourceAmount(this, RESOURCE_SHELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_SHELLS)), "shells");
+               if(GetResourceAmount(this, RESOURCE_BULLETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_BULLETS)), "nails");
+               if(GetResourceAmount(this, RESOURCE_ROCKETS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ROCKETS)), "rockets");
+               if(GetResourceAmount(this, RESOURCE_CELLS) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_CELLS)), "cells");
+               if(GetResourceAmount(this, RESOURCE_PLASMA) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_PLASMA)), "plasma");
+               if(GetResourceAmount(this, RESOURCE_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_FUEL)), "fuel");
+               if(GetResourceAmount(this, RESOURCE_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_HEALTH)), "health");
+               if(GetResourceAmount(this, RESOURCE_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResourceAmount(this, RESOURCE_ARMOR)), "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, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
        }
        this.netname = strzone(this.netname);
        //print(this.netname, "\n");
@@ -1572,59 +1583,59 @@ 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);
 }
 
 bool GiveBuff(entity e, Buff thebuff, int op, int val)
 {
-       bool had_buff = (e.buffs & thebuff.m_itemid);
+       bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
        switch(op)
        {
                case OP_SET:
                        if(val > 0)
-                               e.buffs |= thebuff.m_itemid;
+                               STAT(BUFFS, e) |= thebuff.m_itemid;
                        else
-                               e.buffs &= ~thebuff.m_itemid;
+                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
                        break;
                case OP_MIN:
                case OP_PLUS:
                        if(val > 0)
-                               e.buffs |= thebuff.m_itemid;
+                               STAT(BUFFS, e) |= thebuff.m_itemid;
                        break;
                case OP_MAX:
                        if(val <= 0)
-                               e.buffs &= ~thebuff.m_itemid;
+                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
                        break;
                case OP_MINUS:
                        if(val > 0)
-                               e.buffs &= ~thebuff.m_itemid;
+                               STAT(BUFFS, e) &= ~thebuff.m_itemid;
                        break;
        }
-       bool have_buff = (e.buffs & thebuff.m_itemid);
+       bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
        return (had_buff != have_buff);
 }
 
@@ -1651,6 +1662,31 @@ void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .floa
        else if(v0 > v1)
                e.(regenfield) = max(e.(regenfield), time + regentime);
 }
+bool GiveResourceValue(entity e, int resource_type, int op, int val)
+{
+       int v0 = GetResourceAmount(e, resource_type);
+       switch (op)
+       {
+               case OP_SET:
+                       SetResourceAmount(e, resource_type, val);
+                       break;
+               case OP_MIN:
+                       SetResourceAmount(e, resource_type, max(v0, val)); // min 100 cells = at least 100 cells
+                       break;
+               case OP_MAX:
+                       SetResourceAmount(e, resource_type, min(v0, val));
+                       break;
+               case OP_PLUS:
+                       SetResourceAmount(e, resource_type, v0 + val);
+                       break;
+               case OP_MINUS:
+                       SetResourceAmount(e, resource_type, v0 - val);
+                       break;
+       }
+       int v1 = GetResourceAmount(e, resource_type);
+       return v0 != v1;
+}
+
 float GiveItems(entity e, float beginarg, float endarg)
 {
        float got, i, val, op;
@@ -1683,14 +1719,14 @@ float GiveItems(entity e, float beginarg, float endarg)
        PREGIVE(e, strength_finished);
        PREGIVE(e, invincible_finished);
        PREGIVE(e, superweapons_finished);
-       PREGIVE(e, ammo_nails);
-       PREGIVE(e, ammo_cells);
-       PREGIVE(e, ammo_plasma);
-       PREGIVE(e, ammo_shells);
-       PREGIVE(e, ammo_rockets);
-       PREGIVE(e, ammo_fuel);
-       PREGIVE(e, armorvalue);
-       PREGIVE(e, health);
+       PREGIVE_RESOURCE(e, RESOURCE_BULLETS);
+       PREGIVE_RESOURCE(e, RESOURCE_CELLS);
+       PREGIVE_RESOURCE(e, RESOURCE_PLASMA);
+       PREGIVE_RESOURCE(e, RESOURCE_SHELLS);
+       PREGIVE_RESOURCE(e, RESOURCE_ROCKETS);
+       PREGIVE_RESOURCE(e, RESOURCE_FUEL);
+       PREGIVE_RESOURCE(e, RESOURCE_ARMOR);
+       PREGIVE_RESOURCE(e, RESOURCE_HEALTH);
 
        for(i = beginarg; i < endarg; ++i)
        {
@@ -1727,19 +1763,19 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
                        case "all":
                                got += GiveBit(e, items, ITEM_Jetpack.m_itemid, op, val);
-                               got += GiveValue(e, health, op, val);
-                               got += GiveValue(e, armorvalue, op, val);
+                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
                        case "allweapons":
                                FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
                        //case "allbuffs": // all buffs makes a player god, do not want!
                                //FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
                        case "allammo":
-                               got += GiveValue(e, ammo_cells, op, val);
-                               got += GiveValue(e, ammo_plasma, op, val);
-                               got += GiveValue(e, ammo_shells, op, val);
-                               got += GiveValue(e, ammo_nails, op, val);
-                               got += GiveValue(e, ammo_rockets, op, val);
-                               got += GiveValue(e, ammo_fuel, op, val);
+                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
+                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
+                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
                                break;
                        case "unlimited_ammo":
                                got += GiveBit(e, items, IT_UNLIMITED_AMMO, op, val);
@@ -1766,29 +1802,29 @@ float GiveItems(entity e, float beginarg, float endarg)
                                got += GiveValue(e, superweapons_finished, op, val);
                                break;
                        case "cells":
-                               got += GiveValue(e, ammo_cells, op, val);
+                               got += GiveResourceValue(e, RESOURCE_CELLS, op, val);
                                break;
                        case "plasma":
-                               got += GiveValue(e, ammo_plasma, op, val);
+                               got += GiveResourceValue(e, RESOURCE_PLASMA, op, val);
                                break;
                        case "shells":
-                               got += GiveValue(e, ammo_shells, op, val);
+                               got += GiveResourceValue(e, RESOURCE_SHELLS, op, val);
                                break;
                        case "nails":
                        case "bullets":
-                               got += GiveValue(e, ammo_nails, op, val);
+                               got += GiveResourceValue(e, RESOURCE_BULLETS, op, val);
                                break;
                        case "rockets":
-                               got += GiveValue(e, ammo_rockets, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ROCKETS, op, val);
                                break;
                        case "health":
-                               got += GiveValue(e, health, op, val);
+                               got += GiveResourceValue(e, RESOURCE_HEALTH, op, val);
                                break;
                        case "armor":
-                               got += GiveValue(e, armorvalue, op, val);
+                               got += GiveResourceValue(e, RESOURCE_ARMOR, op, val);
                                break;
                        case "fuel":
-                               got += GiveValue(e, ammo_fuel, op, val);
+                               got += GiveResourceValue(e, RESOURCE_FUEL, op, val);
                                break;
                        default:
                                FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
@@ -1813,23 +1849,23 @@ 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);
        POSTGIVE_VALUE(e, invincible_finished, 1, SND_Shield, SND_POWEROFF);
        //POSTGIVE_VALUE(e, superweapons_finished, 1, SND_Null, SND_Null);
-       POSTGIVE_VALUE(e, ammo_nails, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_cells, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_plasma, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_shells, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE(e, ammo_rockets, 0, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE_ROT(e, ammo_fuel, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
-       POSTGIVE_VALUE_ROT(e, armorvalue, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
-       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);
+       POSTGIVE_RESOURCE(e, RESOURCE_BULLETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_CELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_PLASMA, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_SHELLS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE(e, RESOURCE_ROCKETS, 0, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_FUEL, 1, pauserotfuel_finished, autocvar_g_balance_pause_fuel_rot, pauseregen_finished, autocvar_g_balance_pause_fuel_regen, SND_ITEMPICKUP, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_ARMOR, 1, pauserotarmor_finished, autocvar_g_balance_pause_armor_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_ARMOR25, SND_Null);
+       POSTGIVE_RESOURCE_ROT(e, RESOURCE_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)
@@ -1849,7 +1885,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 d2f44c61daa8e6544f44f47f4f92a61c54907218..9fdb0b0925798580c57106a7eb598c24e3a5ad41 100644 (file)
@@ -57,9 +57,6 @@ bool have_pickup_item(entity this);
 
 const float ITEM_RESPAWN_TICKS = 10;
 
-#define ITEM_RESPAWNTIME_INITIAL(i) (ITEM_RESPAWN_TICKS + random() * ((i).respawntime + (i).respawntimejitter - ITEM_RESPAWN_TICKS))
-       // range: 10 .. respawntime + respawntimejitter
-
 .float max_armorvalue;
 .float pickup_anyway;
 
@@ -127,10 +124,15 @@ 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 PREGIVE_RESOURCE(e,f) float save_##f = GetResourceAmount((e), (f))
+#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_RESOURCE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, GetResourceAmount((e), (f)), t, snd_incr, snd_decr)
+#define POSTGIVE_RESOURCE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e),save_##f,GetResourceAmount((e),(f)),rotfield,rottime,regenfield,regentime);GiveSound((e),save_##f,GetResourceAmount((e),(f)),t,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 84e5581..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, 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, 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, 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 ddd62ae..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, 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 6adbcc6..0000000
+++ /dev/null
@@ -1,208 +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);
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
-
-               WriteCoord(MSG_ENTITY, this.mins_x);
-               WriteCoord(MSG_ENTITY, this.mins_y);
-               WriteCoord(MSG_ENTITY, this.mins_z);
-               WriteCoord(MSG_ENTITY, this.maxs_x);
-               WriteCoord(MSG_ENTITY, this.maxs_y);
-               WriteCoord(MSG_ENTITY, this.maxs_z);
-
-               WriteCoord(MSG_ENTITY, this.movedir_x);
-               WriteCoord(MSG_ENTITY, this.movedir_y);
-               WriteCoord(MSG_ENTITY, this.movedir_z);
-
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               setorigin(this, this.origin);
-
-               this.mins_x = ReadCoord();
-               this.mins_y = ReadCoord();
-               this.mins_z = ReadCoord();
-               this.maxs_x = ReadCoord();
-               this.maxs_y = ReadCoord();
-               this.maxs_z = ReadCoord();
-               setsize(this, this.mins, this.maxs);
-
-               this.movedir_x = ReadCoord();
-               this.movedir_y = ReadCoord();
-               this.movedir_z = ReadCoord();
-
-               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 bb15503..0000000
+++ /dev/null
@@ -1,859 +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, 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, 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, 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, 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, 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, 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, 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);
-
-               WriteCoord(MSG_ENTITY, this.pos1_x);
-               WriteCoord(MSG_ENTITY, this.pos1_y);
-               WriteCoord(MSG_ENTITY, this.pos1_z);
-               WriteCoord(MSG_ENTITY, this.pos2_x);
-               WriteCoord(MSG_ENTITY, this.pos2_y);
-               WriteCoord(MSG_ENTITY, this.pos2_z);
-
-               WriteCoord(MSG_ENTITY, this.size_x);
-               WriteCoord(MSG_ENTITY, this.size_y);
-               WriteCoord(MSG_ENTITY, this.size_z);
-
-               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)
-       {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
-
-               WriteCoord(MSG_ENTITY, this.pos1_x);
-               WriteCoord(MSG_ENTITY, this.pos1_y);
-               WriteCoord(MSG_ENTITY, this.pos1_z);
-               WriteCoord(MSG_ENTITY, this.pos2_x);
-               WriteCoord(MSG_ENTITY, this.pos2_y);
-               WriteCoord(MSG_ENTITY, this.pos2_z);
-       }
-
-       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);
-
-               vector v;
-
-               v.x = ReadCoord();
-               v.y = ReadCoord();
-               v.z = ReadCoord();
-               this.pos1 = v;
-
-               v.x = ReadCoord();
-               v.y = ReadCoord();
-               v.z = ReadCoord();
-               this.pos2 = v;
-
-               v.x = ReadCoord();
-               v.y = ReadCoord();
-               v.z = ReadCoord();
-               this.size = v;
-
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               setorigin(this, this.origin);
-
-               this.pos1_x = ReadCoord();
-               this.pos1_y = ReadCoord();
-               this.pos1_z = ReadCoord();
-               this.pos2_x = ReadCoord();
-               this.pos2_y = ReadCoord();
-               this.pos2_z = ReadCoord();
-       }
-       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 6f2d101..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, 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 36b4eef..0000000
+++ /dev/null
@@ -1,188 +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);
-
-               WriteCoord(MSG_ENTITY, this.pos1_x);
-               WriteCoord(MSG_ENTITY, this.pos1_y);
-               WriteCoord(MSG_ENTITY, this.pos1_z);
-               WriteCoord(MSG_ENTITY, this.pos2_x);
-               WriteCoord(MSG_ENTITY, this.pos2_y);
-               WriteCoord(MSG_ENTITY, this.pos2_z);
-
-               WriteCoord(MSG_ENTITY, this.size_x);
-               WriteCoord(MSG_ENTITY, this.size_y);
-               WriteCoord(MSG_ENTITY, this.size_z);
-
-               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_x = ReadCoord();
-               this.pos1_y = ReadCoord();
-               this.pos1_z = ReadCoord();
-               this.pos2_x = ReadCoord();
-               this.pos2_y = ReadCoord();
-               this.pos2_z = ReadCoord();
-
-               this.size_x = ReadCoord();
-               this.size_y = ReadCoord();
-               this.size_z = ReadCoord();
-
-               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 a0773f2..0000000
+++ /dev/null
@@ -1,385 +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)
-       {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
-       }
-       if(fl & 1)
-       {
-               if(this.model != "null")
-               {
-                       WriteShort(MSG_ENTITY, this.modelindex);
-                       if(fl & 0x80)
-                       {
-                               WriteCoord(MSG_ENTITY, this.mins_x);
-                               WriteCoord(MSG_ENTITY, this.mins_y);
-                               WriteCoord(MSG_ENTITY, this.mins_z);
-                               WriteCoord(MSG_ENTITY, this.maxs_x);
-                               WriteCoord(MSG_ENTITY, this.maxs_y);
-                               WriteCoord(MSG_ENTITY, this.maxs_z);
-                       }
-               }
-               else
-               {
-                       WriteShort(MSG_ENTITY, 0);
-                       if(fl & 0x80)
-                       {
-                               WriteCoord(MSG_ENTITY, this.maxs_x);
-                               WriteCoord(MSG_ENTITY, this.maxs_y);
-                               WriteCoord(MSG_ENTITY, this.maxs_z);
-                       }
-               }
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-       }
-       if(f & 1)
-       {
-               this.modelindex = ReadShort();
-               if(f & 0x80)
-               {
-                       if(this.modelindex)
-                       {
-                               this.mins_x = ReadCoord();
-                               this.mins_y = ReadCoord();
-                               this.mins_z = ReadCoord();
-                               this.maxs_x = ReadCoord();
-                               this.maxs_y = ReadCoord();
-                               this.maxs_z = ReadCoord();
-                       }
-                       else
-                       {
-                               this.mins    = '0 0 0';
-                               this.maxs_x = ReadCoord();
-                               this.maxs_y = ReadCoord();
-                               this.maxs_z = ReadCoord();
-                       }
-               }
-               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 c8b4e29..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-#include "rainsnow.qh"
-REGISTER_NET_LINKED(ENT_CLIENT_RAINSNOW)
-
-#ifdef SVQC
-bool rainsnow_SendEntity(entity this, entity to, float sf)
-{
-       WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
-       WriteByte(MSG_ENTITY, this.state);
-       WriteCoord(MSG_ENTITY, this.origin_x + this.mins_x);
-       WriteCoord(MSG_ENTITY, this.origin_y + this.mins_y);
-       WriteCoord(MSG_ENTITY, this.origin_z + this.mins_z);
-       WriteCoord(MSG_ENTITY, this.maxs_x - this.mins_x);
-       WriteCoord(MSG_ENTITY, this.maxs_y - this.mins_y);
-       WriteCoord(MSG_ENTITY, this.maxs_z - this.mins_z);
-       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_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
-       this.maxs_x = ReadCoord();
-       this.maxs_y = ReadCoord();
-       this.maxs_z = ReadCoord();
-       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 c5a6e3d..0000000
+++ /dev/null
@@ -1,367 +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);
-
-               WriteCoord(MSG_ENTITY, this.pos1_x);
-               WriteCoord(MSG_ENTITY, this.pos1_y);
-               WriteCoord(MSG_ENTITY, this.pos1_z);
-               WriteCoord(MSG_ENTITY, this.pos2_x);
-               WriteCoord(MSG_ENTITY, this.pos2_y);
-               WriteCoord(MSG_ENTITY, this.pos2_z);
-
-               WriteCoord(MSG_ENTITY, this.size_x);
-               WriteCoord(MSG_ENTITY, this.size_y);
-               WriteCoord(MSG_ENTITY, this.size_z);
-
-               WriteCoord(MSG_ENTITY, this.view_ofs_x);
-               WriteCoord(MSG_ENTITY, this.view_ofs_y);
-               WriteCoord(MSG_ENTITY, this.view_ofs_z);
-
-               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_x = ReadCoord();
-               this.pos1_y = ReadCoord();
-               this.pos1_z = ReadCoord();
-               this.pos2_x = ReadCoord();
-               this.pos2_y = ReadCoord();
-               this.pos2_z = ReadCoord();
-
-               this.size_x = ReadCoord();
-               this.size_y = ReadCoord();
-               this.size_z = ReadCoord();
-
-               this.view_ofs_x = ReadCoord();
-               this.view_ofs_y = ReadCoord();
-               this.view_ofs_z = ReadCoord();
-
-               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 dcc4471..0000000
+++ /dev/null
@@ -1,90 +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);
-
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
-
-       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_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
-       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 2059a81..0000000
+++ /dev/null
@@ -1,383 +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, 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)
-       {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
-       }
-       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)
-               {
-                       WriteCoord(MSG_ENTITY, this.enemy.origin_x);
-                       WriteCoord(MSG_ENTITY, this.enemy.origin_y);
-                       WriteCoord(MSG_ENTITY, this.enemy.origin_z);
-               }
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-               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_x = ReadCoord();
-                       this.velocity_y = ReadCoord();
-                       this.velocity_z = ReadCoord();
-               }
-               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 3f52038..0000000
+++ /dev/null
@@ -1,98 +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);
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
-
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-
-               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 09e7330..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, 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, 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, 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, blocker.origin, '0 0 0');
-                       // Gib dead/dying stuff
-                       if(IS_DEAD(blocker))
-                               Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, 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 34c02ba..0000000
+++ /dev/null
@@ -1,10 +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/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 c59ee79..0000000
+++ /dev/null
@@ -1,10 +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/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 4558b71..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#include "include.qh"
-
-#include "changelevel.qc"
-#include "kill.qc"
-#include "levelwarp.qc"
-#include "location.qc"
-#include "music.qc"
-#include "spawn.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 a821ac1..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, 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 1f8cb00..0000000
+++ /dev/null
@@ -1,335 +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)
-       {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
-       }
-       if(sf & 1)
-       {
-               if(this.model != "null")
-               {
-                       WriteShort(MSG_ENTITY, this.modelindex);
-                       WriteCoord(MSG_ENTITY, this.mins.x);
-                       WriteCoord(MSG_ENTITY, this.mins.y);
-                       WriteCoord(MSG_ENTITY, this.mins.z);
-                       WriteCoord(MSG_ENTITY, this.maxs.x);
-                       WriteCoord(MSG_ENTITY, this.maxs.y);
-                       WriteCoord(MSG_ENTITY, this.maxs.z);
-               }
-               else
-               {
-                       WriteShort(MSG_ENTITY, 0);
-                       WriteCoord(MSG_ENTITY, this.maxs.x);
-                       WriteCoord(MSG_ENTITY, this.maxs.y);
-                       WriteCoord(MSG_ENTITY, this.maxs.z);
-               }
-               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_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-       }
-       if(f & 1)
-       {
-               this.modelindex = ReadShort();
-               if(this.modelindex)
-               {
-                       this.mins_x = ReadCoord();
-                       this.mins_y = ReadCoord();
-                       this.mins_z = ReadCoord();
-                       this.maxs_x = ReadCoord();
-                       this.maxs_y = ReadCoord();
-                       this.maxs_z = ReadCoord();
-               }
-               else
-               {
-                       this.mins    = '0 0 0';
-                       this.maxs_x = ReadCoord();
-                       this.maxs_y = ReadCoord();
-                       this.maxs_z = ReadCoord();
-               }
-
-               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/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 5aedf30..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, head.origin, '0 0 0');
-                       }
-               }
-               else // dead bodies and monsters gib themselves instead of telefragging
-                       Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, 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 d0ba4eb..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, 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, 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 9e40cfd..0000000
+++ /dev/null
@@ -1,644 +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);
-
-       WriteCoord(MSG_ENTITY, this.movedir_x);
-       WriteCoord(MSG_ENTITY, this.movedir_y);
-       WriteCoord(MSG_ENTITY, this.movedir_z);
-
-       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);
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
-
-       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_x = ReadCoord();
-       this.movedir_y = ReadCoord();
-       this.movedir_z = 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, 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_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
-
-       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 2f32e50..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, 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 a82034e..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#include "relay.qh"
-#ifdef SVQC
-/*QUAKED spawnfunc_trigger_relay (.5 .5 .5) (-8 -8 -8) (8 8 8)
-This fixed size trigger cannot be touched, it can only be fired by other events.  It can contain killtargets, targets, delays, and messages.
-*/
-spawnfunc(trigger_relay)
-{
-       this.use = SUB_UseTargets;
-       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 c3c2c74..0000000
+++ /dev/null
@@ -1,89 +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)
-{
-       this.stat_secrets_total = secrets_total;
-       this.stat_secrets_found = 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 e483316..0000000
+++ /dev/null
@@ -1,22 +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;
-
-
-.float stat_secrets_total = _STAT(SECRETS_TOTAL);
-.float stat_secrets_found = _STAT(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 71c5247..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, 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 41394ac..0000000
+++ /dev/null
@@ -1,218 +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(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);
-
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
-
-       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);
-
-       WriteCoord(MSG_ENTITY, this.origin_x);
-       WriteCoord(MSG_ENTITY, this.origin_y);
-       WriteCoord(MSG_ENTITY, this.origin_z);
-
-       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_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
-
-       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_x = ReadCoord();
-       this.origin_y = ReadCoord();
-       this.origin_z = ReadCoord();
-       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 f6cb013..0000000
+++ /dev/null
@@ -1,295 +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);
-       WriteByte(MSG_ENTITY, f);
-
-       if(withtarget)
-       {
-               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);
-               WriteString(MSG_ENTITY, this.killtarget);
-       }
-
-       if(f & 4)
-       {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
-       }
-
-       WriteShort(MSG_ENTITY, this.modelindex);
-       WriteCoord(MSG_ENTITY, this.mins.x);
-       WriteCoord(MSG_ENTITY, this.mins.y);
-       WriteCoord(MSG_ENTITY, this.mins.z);
-       WriteCoord(MSG_ENTITY, this.maxs.x);
-       WriteCoord(MSG_ENTITY, this.maxs.y);
-       WriteCoord(MSG_ENTITY, this.maxs.z);
-       WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
-
-       WriteCoord(MSG_ENTITY, this.movedir_x);
-       WriteCoord(MSG_ENTITY, this.movedir_y);
-       WriteCoord(MSG_ENTITY, this.movedir_z);
-
-       WriteCoord(MSG_ENTITY, this.angles_x);
-       WriteCoord(MSG_ENTITY, this.angles_y);
-       WriteCoord(MSG_ENTITY, this.angles_z);
-}
-
-#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); }
-               this.target = strzone(ReadString());
-               if(this.target2) { strunzone(this.target2); }
-               this.target2 = strzone(ReadString());
-               if(this.target3) { strunzone(this.target3); }
-               this.target3 = strzone(ReadString());
-               if(this.target4) { strunzone(this.target4); }
-               this.target4 = strzone(ReadString());
-               if(this.targetname) { strunzone(this.targetname); }
-               this.targetname = strzone(ReadString());
-               if(this.killtarget) { strunzone(this.killtarget); }
-               this.killtarget = strzone(ReadString());
-       }
-
-       if(f & 4)
-       {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
-       }
-       else
-               this.origin = '0 0 0';
-       setorigin(this, this.origin);
-
-       this.modelindex = ReadShort();
-       this.mins_x = ReadCoord();
-       this.mins_y = ReadCoord();
-       this.mins_z = ReadCoord();
-       this.maxs_x = ReadCoord();
-       this.maxs_y = ReadCoord();
-       this.maxs_z = ReadCoord();
-       this.scale = ReadByte() / 16;
-       setsize(this, this.mins, this.maxs);
-
-       this.movedir_x = ReadCoord();
-       this.movedir_y = ReadCoord();
-       this.movedir_z = ReadCoord();
-
-       this.angles_x = ReadCoord();
-       this.angles_y = ReadCoord();
-       this.angles_z = ReadCoord();
-}
-
-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 d75e4a925ce0bf30c781a40f825cdc5b4ffa82f0..ac68003a6cde83c1a6b652959af1f349240654e1 100644 (file)
@@ -37,7 +37,7 @@ void turret_draw(entity this)
 
        this.tur_head.angles += dt * this.tur_head.avelocity;
 
-       if (this.health < 127)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) < 127)
        {
                dt = random();
 
@@ -45,11 +45,11 @@ void turret_draw(entity this)
                        te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
        }
 
-       if(this.health < 85)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 85)
        if(dt < 0.01)
                pointparticles(EFFECT_SMOKE_LARGE, (this.origin + (randomvec() * 80)), '0 0 0', 1);
 
-       if(this.health < 32)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 32)
        if(dt < 0.015)
                pointparticles(EFFECT_SMOKE_SMALL, (this.origin + (randomvec() * 80)), '0 0 0', 1);
 
@@ -115,11 +115,7 @@ void turret_draw2d(entity this)
                LOG_INFOF("WARNING: sprite of name %s has no color, using pink so you notice it", spriteimage);
        }
 
-       txt = this.netname;
-       if(autocvar_g_waypointsprite_spam && waypointsprite_count >= autocvar_g_waypointsprite_spam)
-               txt = _("Spam");
-       else
-               txt = spritelookuptext(this, spriteimage);
+       txt = spritelookuptext(this, spriteimage);
 
        if(time - floor(time) > 0.5 && t == this.team)
        {
@@ -180,11 +176,11 @@ void turret_draw2d(entity this)
        }
 
        o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
-       o = drawspritetext(o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
+       o = drawsprite_TextOrIcon(true, o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
        drawhealthbar(
                        o,
                        0,
-                       this.health / 255,
+                       GetResourceAmount(this, RESOURCE_HEALTH) / 255,
                        '0 0 0',
                        '0 0 0',
                        0.5 * SPRITE_HEALTHBAR_WIDTH * t,
@@ -225,7 +221,7 @@ void turret_construct(entity this, bool isnew)
        set_movetype(this.tur_head, MOVETYPE_NOCLIP);
        set_movetype(this, MOVETYPE_NOCLIP);
        this.tur_head.angles                    = this.angles;
-       this.health                                             = 255;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 255);
        this.solid                                              = SOLID_BBOX;
        this.tur_head.solid                             = SOLID_NOT;
        set_movetype(this, MOVETYPE_NOCLIP);
@@ -365,9 +361,7 @@ NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
        {
                this.m_id = ReadByte();
 
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
 
                this.angles_x = ReadAngle();
@@ -401,14 +395,10 @@ NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
 
        if(sf & TNSF_MOVE)
        {
-               this.origin_x = ReadShort();
-               this.origin_y = ReadShort();
-               this.origin_z = ReadShort();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
 
-               this.velocity_x = ReadShort();
-               this.velocity_y = ReadShort();
-               this.velocity_z = ReadShort();
+               this.velocity = ReadVector();
 
                this.angles_y = ReadShort();
 
@@ -432,13 +422,15 @@ NET_HANDLE(ENT_CLIENT_TURRET, bool isnew)
                }
 
                _tmp = ReadByte();
-               if(_tmp == 0 && this.health != 0)
+               float myhp = GetResourceAmount(this, RESOURCE_HEALTH);
+               if(_tmp == 0 && myhp != 0)
                        turret_die(this);
-               else if(this.health && this.health != _tmp)
+               else if(myhp && myhp > _tmp)
                        this.helpme = servertime + 10;
+               else if(myhp && myhp < _tmp)
+                       this.helpme = 0; // we're being healed, don't spam help me waypoints
 
-               this.health = _tmp;
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
        }
-       //this.enemy.health = this.health / 255;
        return true;
 }
index cb69bf0ff12ba7f2ec9c312e0af33002af6b9393..b68aca16feddd93b6ea01b555b49aa6b17d2c53a 100644 (file)
@@ -182,9 +182,10 @@ void turret_die(entity this)
        this.tur_head.solid      = this.solid;
 
        this.event_damage                 = func_null;
+       this.event_heal = func_null;
        this.takedamage                  = DAMAGE_NO;
 
-       this.health                      = 0;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0);
 
 // Go boom
        //RadiusDamage (this,this, min(this.ammo,50),min(this.ammo,50) * 0.25,250,NULL,min(this.ammo,50)*5,DEATH_TURRET,NULL);
@@ -212,7 +213,7 @@ void turret_die(entity this)
        }
 }
 
-void turret_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
+void turret_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector vforce)
 {
        // Enough already!
        if(this.deadflag == DEAD_DEAD)
@@ -230,7 +231,7 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
                        return;
        }
 
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
        // thorw head slightly off aim when hit?
        if (this.damage_flags & TFL_DMG_HEADSHAKE)
@@ -244,10 +245,12 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        if (this.turret_flags & TUR_FLAG_MOVE)
                this.velocity = this.velocity + vforce;
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.event_damage                 = func_null;
                this.tur_head.event_damage = func_null;
+               this.event_heal = func_null;
+               this.tur_head.event_heal = func_null;
                this.takedamage                  = DAMAGE_NO;
                this.nextthink = time;
                setthink(this, turret_die);
@@ -256,6 +259,17 @@ void turret_damage(entity this, entity inflictor, entity attacker, float damage,
        this.SendFlags  |= TNSF_STATUS;
 }
 
+bool turret_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       targ.SendFlags |= TNSF_STATUS;
+       return true;
+}
+
 void turret_think(entity this);
 void turret_respawn(entity this)
 {
@@ -268,10 +282,11 @@ void turret_respawn(entity this)
        this.solid                                      = SOLID_BBOX;
        this.takedamage                         = DAMAGE_AIM;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.avelocity                          = '0 0 0';
        this.tur_head.avelocity         = this.avelocity;
        this.tur_head.angles            = this.idle_aim;
-       this.health                                     = this.max_health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, this.max_health);
        this.enemy                                      = NULL;
        this.volly_counter                      = this.shot_volly;
        this.ammo                                       = this.ammo_max;
@@ -313,9 +328,7 @@ bool turret_send(entity this, entity to, float sf)
        {
                WriteByte(MSG_ENTITY, this.m_id);
 
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
+               WriteVector(MSG_ENTITY, this.origin);
 
                WriteAngle(MSG_ENTITY, this.angles_x);
                WriteAngle(MSG_ENTITY, this.angles_y);
@@ -335,13 +348,9 @@ bool turret_send(entity this, entity to, float sf)
 
        if(sf & TNSF_MOVE)
        {
-               WriteShort(MSG_ENTITY, rint(this.origin_x));
-               WriteShort(MSG_ENTITY, rint(this.origin_y));
-               WriteShort(MSG_ENTITY, rint(this.origin_z));
+               WriteVector(MSG_ENTITY, this.origin);
 
-               WriteShort(MSG_ENTITY, rint(this.velocity_x));
-               WriteShort(MSG_ENTITY, rint(this.velocity_y));
-               WriteShort(MSG_ENTITY, rint(this.velocity_z));
+               WriteVector(MSG_ENTITY, this.velocity);
 
                WriteShort(MSG_ENTITY, rint(this.angles_y));
        }
@@ -356,10 +365,10 @@ bool turret_send(entity this, entity to, float sf)
        {
                WriteByte(MSG_ENTITY, this.team);
 
-               if(this.health <= 0)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                        WriteByte(MSG_ENTITY, 0);
                else
-                       WriteByte(MSG_ENTITY, ceil((this.health / this.max_health) * 255));
+                       WriteByte(MSG_ENTITY, ceil((GetResourceAmount(this, RESOURCE_HEALTH) / this.max_health) * 255));
        }
 
        return true;
@@ -390,7 +399,7 @@ void load_unit_settings(entity ent, bool is_reload)
                ent.tur_head.angles = '0 0 0';
        }
 
-       ent.health       = cvar(strcat(sbase,"_health")) * ent.turret_scale_health;
+       SetResourceAmountExplicit(ent, RESOURCE_HEALTH, cvar(strcat(sbase,"_health")) * ent.turret_scale_health);
        ent.respawntime = cvar(strcat(sbase,"_respawntime")) * ent.turret_scale_respawn;
 
        ent.shot_dmg             = cvar(strcat(sbase,"_shot_dmg")) * ent.turret_scale_damage;
@@ -439,11 +448,11 @@ void turret_projectile_explode(entity this)
        this.event_damage = func_null;
 #ifdef TURRET_DEBUG
        float d;
-       d = RadiusDamage (this, this.owner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
+       d = RadiusDamage (this, this.owner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, DMG_NOWEP, NULL);
        this.owner.tur_debug_dmg_t_h = this.owner.tur_debug_dmg_t_h + d;
        this.owner.tur_debug_dmg_t_f = this.owner.tur_debug_dmg_t_f + this.owner.shot_dmg;
 #else
-       RadiusDamage (this, this.realowner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
+       RadiusDamage (this, this.realowner, this.owner.shot_dmg, 0, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, DMG_NOWEP, NULL);
 #endif
        delete(this);
 }
@@ -454,12 +463,12 @@ void turret_projectile_touch(entity this, entity toucher)
        turret_projectile_explode(this);
 }
 
-void turret_projectile_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector vforce)
+void turret_projectile_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector vforce)
 {
        this.velocity  += vforce;
-       this.health     -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        //this.realowner = attacker; // Dont change realowner, it does not make much sense for turrets
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, this.owner, turret_projectile_explode);
 }
 
@@ -489,7 +498,7 @@ entity turret_projectile(entity actor, Sound _snd, float _size, float _health, f
        PROJECTILE_MAKETRIGGER(proj);
        if(_health)
        {
-               proj.health              = _health;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
                proj.takedamage  = DAMAGE_YES;
                proj.event_damage  = turret_projectile_damage;
        }
@@ -726,7 +735,7 @@ float turret_validate_target(entity e_turret, entity e_target, float validate_fl
                if (e_target.vehicle_health <= 0)
                        return -6;
        }
-       else if (e_target.health <= 0)
+       else if (GetResourceAmount(e_target, RESOURCE_HEALTH) <= 0)
                return -6;
        else if(STAT(FROZEN, e_target) > 0)
                return -6;
@@ -1245,6 +1254,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");
@@ -1292,7 +1307,7 @@ bool turret_initialize(entity this, Turret tur)
 
        if(!this.team || !teamplay)             { this.team = FLOAT_MAX; }
        if(!this.ticrate)                               { this.ticrate = ((this.turret_flags & TUR_FLAG_SUPPORT) ? 0.2 : 0.1); }
-       if(!this.health)                                { this.health = 1000; }
+       if(!GetResourceAmount(this, RESOURCE_HEALTH)) { SetResourceAmountExplicit(this, RESOURCE_HEALTH, 1000); }
        if(!this.shot_refire)                   { this.shot_refire = 1; }
        if(!this.tur_shotorg)                   { this.tur_shotorg = '50 0 50'; }
        if(!this.turret_flags)                  { this.turret_flags = TUR_FLAG_SPLASH | TUR_FLAG_MEDPROJ | TUR_FLAG_PLAYER; }
@@ -1349,7 +1364,7 @@ bool turret_initialize(entity this, Turret tur)
        this.effects                            = EF_NODRAW;
        this.netname                            = tur.turret_name;
        this.ticrate                            = bound(sys_frametime, this.ticrate, 60);
-       this.max_health                         = this.health;
+       this.max_health                         = GetResourceAmount(this, RESOURCE_HEALTH);
        this.target_validate_flags      = this.target_select_flags;
        this.ammo                                       = this.ammo_max;
        this.ammo_recharge                 *= this.ticrate;
@@ -1360,6 +1375,7 @@ bool turret_initialize(entity this, Turret tur)
        this.idle_aim                           = '0 0 0';
        this.turret_firecheckfunc       = turret_firecheck;
        this.event_damage                       = turret_damage;
+       this.event_heal                         = turret_heal;
        this.use                                        = turret_use;
        this.bot_attack                         = true;
        this.nextthink                          = time + 1;
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..c0a0b177ee2d179afb99aeb774203521daf5eeeb 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);
 
@@ -229,17 +228,17 @@ void ewheel_draw(entity this)
     setorigin(this, this.origin + this.velocity * dt);
     this.tur_head.angles += dt * this.tur_head.avelocity;
 
-    if (this.health < 127)
+    if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
     if(random() < 0.05)
         te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 }
 
-        METHOD(EWheel, tr_setup, void(EWheel this, entity it))
-        {
-            it.gravity         = 1;
-            set_movetype(it, MOVETYPE_BOUNCE);
-            it.move_time               = time;
-            it.draw                    = ewheel_draw;
-        }
+METHOD(EWheel, tr_setup, void(EWheel this, entity it))
+{
+    it.gravity         = 1;
+    set_movetype(it, MOVETYPE_BOUNCE);
+    it.move_time               = time;
+    it.draw                    = ewheel_draw;
+}
 
 #endif // CSQC
index fc22c3086c861505e57b49baff564297a74a1b26..4a0fe87c43255cc8b9eb918c5db76255878a593b 100644 (file)
@@ -10,7 +10,7 @@ METHOD(EWheelAttack, wr_think, void(entity thiswep, entity actor, .entity weapon
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_EWheelAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_EWheelAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_EWHEEL.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 974a32ca138e50d280fc8dc9d594a6b330a1b692..cbf7cb30fcf69f63b90b2120ea41424826635d03 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(EWheelAttack, PortoLaunch)
-/* flags     */ ATTRIB(EWheelAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(EWheelAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(EWheelAttack, impulse, int, 5);
 /* refname   */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel");
 /* wepname   */ ATTRIB(EWheelAttack, m_name, string, _("eWheel"));
index 10d53aa08f527e64dd53ce05d92a0329d54d8465..d9d7a3f1423e0c5d724b9a977b6236b2bb87d4dc 100644 (file)
@@ -10,7 +10,7 @@ METHOD(FlacAttack, wr_think, void(entity thiswep, entity actor, .entity weaponen
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_FlacAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_FlacAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_FLAC.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
@@ -41,11 +41,11 @@ void turret_flac_projectile_think_explode(entity this)
         setorigin(this, this.enemy.origin + randomvec() * this.owner.shot_radius);
 
 #ifdef TURRET_DEBUG
-    float d = RadiusDamage (this, this.owner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
+    float d = RadiusDamage (this, this.owner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, DMG_NOWEP, NULL);
     this.owner.tur_dbg_dmg_t_h = this.owner.tur_dbg_dmg_t_h + d;
     this.owner.tur_dbg_dmg_t_f = this.owner.tur_dbg_dmg_t_f + this.owner.shot_dmg;
 #else
-    RadiusDamage (this, this.realowner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, NULL);
+    RadiusDamage (this, this.realowner, this.owner.shot_dmg, this.owner.shot_dmg, this.owner.shot_radius, this, NULL, this.owner.shot_force, this.totalfrags, DMG_NOWEP, NULL);
 #endif
     delete(this);
 }
index 7857f2f3893cb67dbf9c74687fe27da866f6450b..13965bf513a911239d173ac78b1537225145aef5 100644 (file)
@@ -1,5 +1,7 @@
 #pragma once
 
+// TODO: WEP_TYPE_OTHER?
+
 CLASS(FlacAttack, PortoLaunch)
 /* flags     */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(FlacAttack, impulse, int, 5);
index a1065dec1b12033916dc30437a2a9a92c9be62bd..1c12a33c65559181d455df5cb2f90381bb1008bf 100644 (file)
@@ -13,7 +13,7 @@ METHOD(HellionAttack, wr_think, void(entity thiswep, entity actor, .entity weapo
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HellionAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HellionAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_HELLION.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 88ac336725c5a7bbc9b6602bae16dca9c0a2baac..69c67b800b7e7d432968e40981019f1d6d392f2d 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(HellionAttack, PortoLaunch)
-/* flags     */ ATTRIB(HellionAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(HellionAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(HellionAttack, impulse, int, 9);
 /* refname   */ ATTRIB(HellionAttack, netname, string, "turret_hellion");
 /* wepname   */ ATTRIB(HellionAttack, m_name, string, _("Hellion"));
index 9a243adaa73c6903cad83ea22e1eb9155bb84d44..b68bfb77307a5f3ed243779deb9b3b717eacfad9 100644 (file)
@@ -18,7 +18,7 @@ METHOD(HunterKillerAttack, wr_think, void(entity thiswep, entity actor, .entity
        if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
                if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HunterKillerAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_HunterKillerAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_HK.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
@@ -58,7 +58,7 @@ void turret_hk_missile_think(entity this)
     //if (this.cnt < time)
     // turret_hk_missile_explode();
 
-    if (IS_DEAD(this.enemy))
+    if (IS_DEAD(this.enemy) || IS_SPEC(this.enemy) || IS_OBSERVER(this.enemy))
         this.enemy = NULL;
 
     // Pick the closest valid target.
@@ -251,7 +251,7 @@ bool hk_is_valid_target(entity this, entity proj, entity targ)
         return false;
 
     // Cant touch this
-    if ((targ.takedamage == DAMAGE_NO) || (targ.health < 0))
+    if ((targ.takedamage == DAMAGE_NO) || (GetResourceAmount(targ, RESOURCE_HEALTH) < 0))
         return false;
 
     // player
index 87e0c88c20f5884dd34eecf7055c21c43277f662..7d44cfff91e8fb317773645f13f5c2d390b65804 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(HunterKillerAttack, PortoLaunch)
-/* flags     */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(HunterKillerAttack, impulse, int, 9);
 /* refname   */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk");
 /* wepname   */ ATTRIB(HunterKillerAttack, m_name, string, _("Hunter-Killer"));
index 83ed8cfda51d4608874c1145fe53dadcb689a645..b3c5c5197d3cf02f4c1d7b7814a314c15b20eaa7 100644 (file)
@@ -11,7 +11,7 @@ METHOD(MachineGunTurretAttack, wr_think, void(entity thiswep, entity actor, .ent
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MachineGunTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_MACHINEGUN.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 30163bc93c339ee8875c0c36b5ea3a12e20b9b5a..ab8169e6cb15000bb77bca0508b1ef576988c928 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(MachineGunTurretAttack, PortoLaunch)
-/* flags     */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MachineGunTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun");
 /* wepname   */ ATTRIB(MachineGunTurretAttack, m_name, string, _("Machinegun"));
index ccf309aaf7c31ef8015b788b17d3a112551f49f6..75f2e8b4aa6959d195e4735175bce8aa0f1c65ec 100644 (file)
@@ -9,7 +9,7 @@ METHOD(MLRSTurretAttack, wr_think, void(entity thiswep, entity actor, .entity we
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(machinegun, sustained_refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MLRSTurretAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_MLRSTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_MLRS.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index c583842cd97b33b54bc498ce239ffd91c04dace2..ccb74771a6ad8121b7aa4627cb66362167b24cd4 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(MLRSTurretAttack, PortoLaunch)
-/* flags     */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(MLRSTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs");
 /* wepname   */ ATTRIB(MLRSTurretAttack, m_name, string, _("MLRS"));
index 3fb34fb14c2b9b1d97f7c0a6ad3008ba3e6011af..0a3627631139a250552448dbf48f54870ae9a332 100644 (file)
@@ -12,7 +12,7 @@ METHOD(PhaserTurretAttack, wr_think, void(entity thiswep, entity actor, .entity
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PhaserTurretAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PhaserTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_PHASER.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 326a90e977a288b2aa1ace5636ff333424684d21..ea45977d52e5a7921b3766ec7fc297635e2ae364 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(PhaserTurretAttack, PortoLaunch)
-/* flags     */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(PhaserTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser");
 /* wepname   */ ATTRIB(PhaserTurretAttack, m_name, string, _("Phaser"));
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 7de7406e2da1fe195f38bf1b06caf70cbcfb54aa..de53de98407a8c75fad8dcdc699d6cf9c5e0ba11 100644 (file)
@@ -8,7 +8,7 @@ METHOD(PlasmaAttack, wr_think, void(entity thiswep, entity actor, .entity weapon
        if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
                if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PlasmaAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_PlasmaAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_PLASMA.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 5c733846fe2a12077b69ffe17aaac7d1df4d663c..3c11fdc0030bda7649d73e8ddd903d07940d420a 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(PlasmaAttack, PortoLaunch)
-/* flags     */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(PlasmaAttack, impulse, int, 5);
 /* refname   */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma");
 /* wepname   */ ATTRIB(PlasmaAttack, m_name, string, _("Plasma"));
index 88ca4db9702f491d237edd4adade82a526b0c9af..b62201eb983e3523118b39eb1b71e3fde321f10b 100644 (file)
@@ -10,7 +10,7 @@ METHOD(TeslaCoilTurretAttack, wr_think, void(entity thiswep, entity actor, .enti
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_TeslaCoilTurretAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_TeslaCoilTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_TESLA.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
@@ -73,7 +73,7 @@ entity toast(entity actor, entity from, float range, float damage)
     if (etarget)
     {
         te_csqc_lightningarc(from.origin, etarget.origin);
-        Damage(etarget, actor, actor, damage, DEATH_TURRET_TESLA.m_id, etarget.origin, '0 0 0');
+        Damage(etarget, actor, actor, damage, DEATH_TURRET_TESLA.m_id, DMG_NOWEP, etarget.origin, '0 0 0');
         etarget.railgunhit = true;
         IL_PUSH(g_railgunhit, etarget);
     }
index 7e3879bc01bfdb89dea8d5d577a5426d4f2c3420..a7398526604e3ed5c6a77d129050481b6ff09b24 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(TeslaCoilTurretAttack, PortoLaunch)
-/* flags     */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9);
 /* refname   */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla");
 /* wepname   */ ATTRIB(TeslaCoilTurretAttack, m_name, string, _("Tesla Coil"));
index 415d5dfeef16fd315cd5c08d7dc269be2c199bd9..6aa0865e69d1e4fac73d93ab9177f72278071985 100644 (file)
@@ -62,7 +62,7 @@ void walker_melee_do_dmg(entity this)
     {
         if (turret_validate_target(this, e, this.target_validate_flags))
             if (e != this && e.owner != this)
-                Damage(e, this, this, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE.m_id, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force));
+                Damage(e, this, this, (autocvar_g_turrets_unit_walker_melee_damage), DEATH_TURRET_WALK_MELEE.m_id, DMG_NOWEP, '0 0 0', v_forward * (autocvar_g_turrets_unit_walker_melee_force));
 
         e = e.chain;
     }
@@ -75,7 +75,7 @@ void walker_setnoanim(entity this)
 }
 void walker_rocket_explode(entity this)
 {
-    RadiusDamage (this, this.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), this, NULL, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET.m_id, NULL);
+    RadiusDamage (this, this.owner, (autocvar_g_turrets_unit_walker_rocket_damage), 0, (autocvar_g_turrets_unit_walker_rocket_radius), this, NULL, (autocvar_g_turrets_unit_walker_rocket_force), DEATH_TURRET_WALK_ROCKET.m_id, DMG_NOWEP, NULL);
     delete(this);
 }
 
@@ -84,12 +84,12 @@ void walker_rocket_touch(entity this, entity toucher)
     walker_rocket_explode(this);
 }
 
-void walker_rocket_damage(entity this, entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector vforce)
+void walker_rocket_damage(entity this, entity inflictor, entity attacker, float damage, float deathtype, .entity weaponentity, vector hitloc, vector vforce)
 {
-    this.health = this.health - damage;
+    TakeResource(this, RESOURCE_HEALTH, damage);
     this.velocity = this.velocity + vforce;
 
-    if (this.health <= 0)
+    if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
         W_PrepareExplosionByDamage(this, this.owner, walker_rocket_explode);
 }
 
@@ -218,7 +218,7 @@ void walker_fire_rocket(entity this, vector org)
     rocket.bot_dodgerating     = 50;
     rocket.takedamage           = DAMAGE_YES;
     rocket.damageforcescale   = 2;
-    rocket.health                       = 25;
+    SetResourceAmountExplicit(rocket, RESOURCE_HEALTH, 25);
     rocket.tur_shotorg         = randomvec() * 512;
     rocket.cnt                         = time + 1;
     rocket.enemy                         = this.enemy;
@@ -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)
     {
@@ -627,17 +629,17 @@ void walker_draw(entity this)
     setorigin(this, this.origin + this.velocity * dt);
     this.tur_head.angles += dt * this.tur_head.avelocity;
 
-    if (this.health < 127)
+    if(GetResourceAmount(this, RESOURCE_HEALTH) < 127)
     if(random() < 0.15)
         te_spark(this.origin + '0 0 40', randomvec() * 256 + '0 0 256', 16);
 }
 
-        METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
-        {
-            it.gravity         = 1;
-            set_movetype(it, MOVETYPE_BOUNCE);
-            it.move_time               = time;
-            it.draw                    = walker_draw;
-        }
+METHOD(WalkerTurret, tr_setup, void(WalkerTurret this, entity it))
+{
+    it.gravity         = 1;
+    set_movetype(it, MOVETYPE_BOUNCE);
+    it.move_time               = time;
+    it.draw                    = walker_draw;
+}
 
 #endif // CSQC
index c1e433aea7df12a6c1fa2db9a2b8d1511e8be802..121f15c62823b6abf891e7d225e92505ed9e4d7a 100644 (file)
@@ -9,7 +9,7 @@ METHOD(WalkerTurretAttack, wr_think, void(entity thiswep, entity actor, .entity
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(electro, refire))) {
         if (isPlayer) {
             turret_initparams(actor);
-            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0);
+            W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_WalkerTurretAttack_FIRE, CH_WEAPON_B, 0, DEATH_TURRET_WALK_GUN.m_id);
             actor.tur_shotdir_updated = w_shotdir;
             actor.tur_shotorg = w_shotorg;
             actor.tur_head = actor;
index 4e2078514431d0cd156a30760e06d64894e30257..7c4fc0bed03560a379a8969b7fca284e5a99d032 100644 (file)
@@ -1,7 +1,7 @@
 #pragma once
 
 CLASS(WalkerTurretAttack, PortoLaunch)
-/* flags     */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(WalkerTurretAttack, impulse, int, 5);
 /* refname   */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker");
 /* wepname   */ ATTRIB(WalkerTurretAttack, m_name, string, _("Walker"));
index d4cbb4fb1da280665f62c00f00dc3b340f251909..5201f4751c9ee14df84cec520e313c959cc5b7c7 100644 (file)
@@ -85,7 +85,7 @@ void FireImoBeam(entity this, vector start, vector end, vector smin, vector smax
                // apply the damage
                if (ent.takedamage)
                {
-                       Damage (ent, this, this, f_dmg, deathtype, hitloc, force);
+                       Damage (ent, this, this, f_dmg, deathtype, DMG_NOWEP, hitloc, force);
                        ent.velocity = ent.velocity * f_velfactor;
                        //ent.alpha = 0.25 + random() * 0.75;
                }
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 b2f87821eea414ca4b6eb764663571d4d1826c4c..51ac4bee45f3e035b19fc9895abfbce066e639e6 100644 (file)
@@ -70,9 +70,7 @@ NET_HANDLE(ENT_CLIENT_AUXILIARYXHAIR, bool isnew)
 
        if(sf & 2)
        {
-               axh.origin_x = ReadCoord();
-               axh.origin_y = ReadCoord();
-               axh.origin_z = ReadCoord();
+               axh.origin = ReadVector();
        }
 
        if(sf & 4)
index 1fbd80210475debd33e63fc5823ca4dd114214bb..214109c97b5fcbb8a45e4f73ddc46972b065f6c5 100644 (file)
@@ -9,9 +9,7 @@ bool SendAuxiliaryXhair(entity this, entity to, int sf)
 
        if(sf & 2)
        {
-               WriteCoord(MSG_ENTITY, this.origin_x);
-               WriteCoord(MSG_ENTITY, this.origin_y);
-               WriteCoord(MSG_ENTITY, this.origin_z);
+               WriteVector(MSG_ENTITY, this.origin);
        }
 
        if(sf & 4)
@@ -26,8 +24,8 @@ bool SendAuxiliaryXhair(entity this, entity to, int sf)
 
 bool AuxiliaryXhair_customize(entity this, entity client)
 {
-       //entity e = WaypointSprite_getviewentity(client);
-       entity axh = client.(AuxiliaryXhair[this.cnt]);
+       entity e = WaypointSprite_getviewentity(client);
+       entity axh = e.(AuxiliaryXhair[this.cnt]);
        return axh.owner == this.owner; // cheaply check if the client's axh owner is the same as our real owner
 }
 
@@ -201,15 +199,15 @@ vector vehicles_force_fromtag_maglev(entity this, string tag_name, float spring_
 }
 
 // projectile handling
-void vehicles_projectile_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void vehicles_projectile_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        // Ignore damage from oterh projectiles from my owner (dont mess up volly's)
        if(inflictor.owner == this.owner)
                return;
 
-       this.health -= damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.velocity += force;
-       if(this.health < 1)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 1)
        {
                this.takedamage = DAMAGE_NO;
                this.event_damage = func_null;
@@ -232,7 +230,7 @@ void vehicles_projectile_explode(entity this, entity toucher)
        PROJECTILE_TOUCH(this, toucher);
 
        this.event_damage = func_null;
-       RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, toucher);
+       RadiusDamage (this, this.realowner, this.shot_dmg, 0, this.shot_radius, this, NULL, this.shot_force, this.totalfrags, DMG_NOWEP, toucher);
 
        delete(this);
 }
@@ -284,7 +282,7 @@ entity vehicles_projectile(entity this, string _mzlfx, Sound _mzlsound,
        {
                proj.takedamage    = DAMAGE_AIM;
                proj.event_damage        = vehicles_projectile_damage;
-               proj.health                = _health;
+               SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
        }
        else
                proj.flags |= FL_NOTARGET;
@@ -369,7 +367,7 @@ bool vehicle_addplayerslot( entity _owner,
        _slot.PlayerPhysplug = _framefunc;
        _slot.vehicle_exit = _exitfunc;
        _slot.vehicle_enter = _enterfunc;
-       _slot.hud = _hud;
+       STAT(HUD, _slot) = _hud;
        _slot.vehicle_flags = VHF_PLAYERSLOT;
        _slot.vehicle_viewport = spawn();
        _slot.vehicle_hudmodel = spawn();
@@ -522,6 +520,7 @@ void vehicles_showwp(entity this)
        else
                rgb = '1 1 1';
        entity wp = WaypointSprite_Spawn(WP_Vehicle, 0, 0, ent, '0 0 64', NULL, 0, ent, waypointsprite_attached, true, RADARICON_Vehicle);
+       wp.wp_extra = ent.wp00.vehicleid;
        wp.colormod = rgb;
        if(ent.waypointsprite_attached)
        {
@@ -639,7 +638,7 @@ void vehicles_frame(entity this, entity actor)
        vehicles_painframe(this);
 }
 
-void vehicles_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void vehicles_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        this.dmg_time = time;
 
@@ -728,6 +727,20 @@ void vehicles_damage(entity this, entity inflictor, entity attacker, float damag
        }
 }
 
+bool vehicles_heal(entity targ, entity inflictor, float amount, float limit)
+{
+       float true_limit = ((limit != RESOURCE_LIMIT_NONE) ? limit : targ.max_health);
+       //if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= true_limit)
+       if(targ.vehicle_health <= 0 || targ.vehicle_health >= true_limit)
+               return false;
+
+       targ.vehicle_health = min(targ.vehicle_health + amount, true_limit);
+       //GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, true_limit);
+       //if(targ.owner)
+               //targ.owner.vehicle_health = (targ.vehicle_health / targ.max_health) * 100;
+       return true;
+}
+
 bool vehicles_crushable(entity e)
 {
        if(IS_PLAYER(e) && time >= e.vehicle_enter_delay)
@@ -752,7 +765,7 @@ void vehicles_impact(entity this, float _minspeed, float _speedfac, float _maxpa
                if(_minspeed < wc)
                {
                        float take = min(_speedfac * wc, _maxpain);
-                       Damage (this, NULL, NULL, take, DEATH_FALL.m_id, this.origin, '0 0 0');
+                       Damage (this, NULL, NULL, take, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        this.play_time = time + 0.25;
 
                        //dprint("wc: ", ftos(wc), "\n");
@@ -798,7 +811,6 @@ void vehicles_exit(entity vehic, bool eject)
 
        vehicles_exit_running = true;
 
-       // TODO: this was in an IS_CLIENT check, make sure it isn't actually needed!
        if(vehic.vehicle_flags & VHF_PLAYERSLOT)
        {
                vehic.vehicle_exit(vehic, eject);
@@ -826,13 +838,13 @@ void vehicles_exit(entity vehic, bool eject)
                player.solid                    = SOLID_SLIDEBOX;
                set_movetype(player, MOVETYPE_WALK);
                player.effects             &= ~EF_NODRAW;
-               player.teleportable     = TELEPORT_NORMAL;
+               player.teleportable             = TELEPORT_NORMAL;
                player.alpha                    = 1;
                player.PlayerPhysplug   = func_null;
                player.vehicle                  = NULL;
-               player.view_ofs         = STAT(PL_VIEW_OFS, player);
-               player.event_damage     = PlayerDamage;
-               player.hud                              = HUD_NORMAL;
+               player.view_ofs                 = STAT(PL_VIEW_OFS, player);
+               player.event_damage             = PlayerDamage;
+               STAT(HUD, player)               = HUD_NORMAL;
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++ slot)
                {
                        .entity weaponentity = weaponentities[slot];
@@ -900,7 +912,7 @@ void vehicles_touch(entity this, entity toucher)
                if(vehicles_crushable(toucher))
                {
                        if(vdist(this.velocity, >=, 30))
-                               Damage(toucher, this, this.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, '0 0 0', normalize(toucher.origin - this.origin) * autocvar_g_vehicles_crush_force);
+                               Damage(toucher, this, this.owner, autocvar_g_vehicles_crush_dmg, DEATH_VH_CRUSH.m_id, DMG_NOWEP, '0 0 0', normalize(toucher.origin - this.origin) * autocvar_g_vehicles_crush_force);
 
                        return; // Dont do selfdamage when hitting "soft targets".
                }
@@ -1006,6 +1018,7 @@ void vehicles_enter(entity pl, entity veh)
        setsize(pl, STAT(PL_MIN, pl), STAT(PL_MAX, pl));
 
        veh.event_damage        = vehicles_damage;
+       veh.event_heal          = vehicles_heal;
        veh.nextthink           = 0;
        pl.items &= ~IT_USING_JETPACK;
        pl.angles                       = veh.angles;
@@ -1026,7 +1039,7 @@ void vehicles_enter(entity pl, entity veh)
                veh.(weaponentity) = new(temp_wepent);
                veh.(weaponentity).m_switchweapon = pl.(weaponentity).m_switchweapon;
        }
-       pl.hud = veh.vehicleid;
+       STAT(HUD, pl) = veh.vehicleid;
        pl.PlayerPhysplug = veh.PlayerPhysplug;
 
        pl.vehicle_ammo1 = veh.vehicle_ammo1;
@@ -1087,7 +1100,7 @@ void vehicles_think(entity this)
        this.nextthink = time + autocvar_g_vehicles_thinkrate;
 
        if(this.owner)
-               this.owner.vehicle_weapon2mode = this.vehicle_weapon2mode;
+               STAT(VEHICLESTAT_W2MODE, this.owner) = STAT(VEHICLESTAT_W2MODE, this);
 
        Vehicle info = Vehicles_from(this.vehicleid);
        info.vr_think(info, this);
@@ -1119,6 +1132,7 @@ void vehicles_spawn(entity this)
        this.owner                              = NULL;
        settouch(this, vehicles_touch);
        this.event_damage               = vehicles_damage;
+       this.event_heal                 = vehicles_heal;
        this.reset                              = vehicles_reset;
        this.iscreature                 = true;
        this.teleportable               = false; // no teleporting for vehicles, too buggy
@@ -1231,6 +1245,7 @@ bool vehicle_initialize(entity this, Vehicle info, bool nodrop)
        this.vehicleid                          = info.vehicleid;
        this.PlayerPhysplug                     = info.PlayerPhysplug;
        this.event_damage                       = func_null;
+       this.event_heal                         = func_null;
        settouch(this, vehicles_touch);
        setthink(this, vehicles_spawn);
        this.nextthink                          = time;
index 22e2e4859dd170c94f3bf03c571822bb9c496052..0cc9da56ea11a57779850fc85f1bdd53ca0864e1 100644 (file)
@@ -45,14 +45,14 @@ float autocvar_g_vehicles_weapon_damagerate = 2;
 .entity gunner1;
 .entity gunner2;
 
-.float vehicle_health = _STAT(VEHICLESTAT_HEALTH);  /// If ent is player this is 0..100 indicating precentage of health left on vehicle. If ent is vehile, this is the real health value.
-.float vehicle_energy = _STAT(VEHICLESTAT_ENERGY);  /// If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehile, this is the real energy value.
-.float vehicle_shield = _STAT(VEHICLESTAT_SHIELD);  /// If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehile, this is the real shield value.
+.float vehicle_health = _STAT(VEHICLESTAT_HEALTH);  /// If ent is player this is 0..100 indicating precentage of health left on vehicle. If ent is vehicle, this is the real health value.
+.float vehicle_energy = _STAT(VEHICLESTAT_ENERGY);  /// If ent is player this is 0..100 indicating precentage of energy left on vehicle. If ent is vehicle, this is the real energy value.
+.float vehicle_shield = _STAT(VEHICLESTAT_SHIELD);  /// If ent is player this is 0..100 indicating precentage of shield left on vehicle. If ent is vehicle, this is the real shield value.
 
-.float vehicle_ammo1 = _STAT(VEHICLESTAT_AMMO1);   /// If ent is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already stored in vehicle_energy. If ent is vehile, this is the real ammo1 value.
-.float vehicle_reload1 = _STAT(VEHICLESTAT_RELOAD1); /// If ent is player this is 0..100 indicating percentage of primary reload status. If ent is vehile, this is the real reload1 value.
-.float vehicle_ammo2 = _STAT(VEHICLESTAT_AMMO2);   /// If ent is player this is 0..100 indicating percentage of secondary ammo left. If ent is vehile, this is the real ammo2 value.
-.float vehicle_reload2 = _STAT(VEHICLESTAT_RELOAD2); /// If ent is player this is 0..100 indicating percentage of secondary reload status. If ent is vehile, this is the real reload2 value.
+.float vehicle_ammo1 = _STAT(VEHICLESTAT_AMMO1);   /// If ent is player this is 0..100 indicating percentage of primary ammo left UNLESS value is already stored in vehicle_energy. If ent is vehicle, this is the real ammo1 value.
+.float vehicle_reload1 = _STAT(VEHICLESTAT_RELOAD1); /// If ent is player this is 0..100 indicating percentage of primary reload status. If ent is vehicle, this is the real reload1 value.
+.float vehicle_ammo2 = _STAT(VEHICLESTAT_AMMO2);   /// If ent is player this is 0..100 indicating percentage of secondary ammo left. If ent is vehicle, this is the real ammo2 value.
+.float vehicle_reload2 = _STAT(VEHICLESTAT_RELOAD2); /// If ent is player this is 0..100 indicating percentage of secondary reload status. If ent is vehicle, this is the real reload2 value.
 
 .float sound_nexttime;
 const float VOL_VEHICLEENGINE = 1;
@@ -64,7 +64,6 @@ const float SVC_UPDATEENTITY  = 128; // Net.Protocol 0x80
 const float VHSF_NORMAL = 0;
 const float VHSF_FACTORY = 2;
 
-.int hud = _STAT(HUD);
 .float dmg_time;
 
 .float play_time;
@@ -80,16 +79,14 @@ const int MAX_AXH = 4;
 .float  lock_strength;
 .float  lock_time;
 .float  lock_soundtime;
-const float    DAMAGE_TARGETDRONE = 10;
 
 // vehicle functions
 .void(int _spawnflag) vehicle_spawn;  /// Vehicles custom fucntion to be efecuted when vehicle (re)spawns
 .bool(entity this, int _imp) vehicles_impulse;
-.int vehicle_weapon2mode = _STAT(VEHICLESTAT_W2MODE);
 .void(entity this, int exit_flags) vehicle_exit;
 .bool(entity this, entity player) vehicle_enter;
 const int VHEF_NORMAL = 0;  /// User pressed exit key
-const int VHEF_EJECT  = 1;  /// User pressed exit key 3 times fast (not implemented) or vehile is dying
+const int VHEF_EJECT  = 1;  /// User pressed exit key 3 times fast (not implemented) or vehicle is dying
 const int VHEF_RELEASE = 2;  /// Release ownership, client possibly allready dissconnected / went spec / changed team / used "kill" (not implemented)
 
 float  force_fromtag_power;
@@ -109,6 +106,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 018e1a17db9cf3ee0277d7097ec8188bcb7ce2f0..c340d947035617492da6d224bbede286baf8e7be 100644 (file)
@@ -233,7 +233,7 @@ void bumblebee_gunner_exit(entity this, int _exitflag)
        player.PlayerPhysplug = func_null;
        player.view_ofs       = STAT(PL_VIEW_OFS, player);
        player.event_damage   = PlayerDamage;
-       player.hud            = HUD_NORMAL;
+       STAT(HUD, player)     = HUD_NORMAL;
        player.teleportable       = TELEPORT_NORMAL;
        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
@@ -298,7 +298,7 @@ bool bumblebee_gunner_enter(entity this, entity player)
        set_movetype(player, MOVETYPE_NOCLIP);
        player.event_damage     = func_null;
        player.view_ofs                 = '0 0 0';
-       player.hud                              = gunner.hud;
+       STAT(HUD, player)               = STAT(HUD, gunner);
        player.teleportable     = false;
        player.PlayerPhysplug   = gunner.PlayerPhysplug;
        player.vehicle_ammo1    = vehic.vehicle_ammo1;
@@ -332,7 +332,7 @@ bool bumblebee_gunner_enter(entity this, entity player)
                WriteAngle(MSG_ONE,     0); // roll
        }
 
-       CSQCVehicleSetup(player, player.hud);
+       CSQCVehicleSetup(player, STAT(HUD, player));
 
        MUTATOR_CALLHOOK(VehicleEnter, player, gunner);
 
@@ -538,42 +538,33 @@ bool bumblebee_pilot_frame(entity this, float dt)
                {
                        if(autocvar_g_vehicle_bumblebee_raygun)
                        {
-                               Damage(trace_ent, vehic, this, autocvar_g_vehicle_bumblebee_raygun_dps * PHYS_INPUT_FRAMETIME, DEATH_GENERIC.m_id, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * PHYS_INPUT_FRAMETIME);
+                               Damage(trace_ent, vehic, this, autocvar_g_vehicle_bumblebee_raygun_dps * PHYS_INPUT_FRAMETIME, DEATH_GENERIC.m_id, DMG_NOWEP, trace_endpos, v_forward * autocvar_g_vehicle_bumblebee_raygun_fps * PHYS_INPUT_FRAMETIME);
                                vehic.vehicle_energy -= autocvar_g_vehicle_bumblebee_raygun_aps * PHYS_INPUT_FRAMETIME;
                        }
                        else
                        {
                                if(!IS_DEAD(trace_ent))
+                               {
                                        if((teamplay && trace_ent.team == this.team) || !teamplay)
                                        {
+                                               if(autocvar_g_vehicle_bumblebee_healgun_hps)
+                                               {
+                                                       float hplimit = ((IS_PLAYER(trace_ent)) ? autocvar_g_vehicle_bumblebee_healgun_hmax : RESOURCE_LIMIT_NONE);
+                                                       Heal(trace_ent, this, autocvar_g_vehicle_bumblebee_healgun_hps * dt, hplimit);
+                                               }
 
                                                if(IS_VEHICLE(trace_ent))
                                                {
                                                        if(autocvar_g_vehicle_bumblebee_healgun_sps && trace_ent.vehicle_health <= trace_ent.max_health)
                                                                trace_ent.vehicle_shield = min(trace_ent.vehicle_shield + autocvar_g_vehicle_bumblebee_healgun_sps * dt, trace_ent.tur_head.max_health);
-
-                                                       if(autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.vehicle_health = min(trace_ent.vehicle_health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
                                                }
                                                else if(IS_CLIENT(trace_ent))
                                                {
-                                                       if(trace_ent.health <= autocvar_g_vehicle_bumblebee_healgun_hmax && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-
-                                                       if(trace_ent.armorvalue <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
-                                                               trace_ent.armorvalue = min(trace_ent.armorvalue + autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
-
-                                                       trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, autocvar_g_vehicle_bumblebee_healgun_hmax);
-                                               }
-                                               else if(IS_TURRET(trace_ent))
-                                               {
-                                                       if(trace_ent.health  <= trace_ent.max_health && autocvar_g_vehicle_bumblebee_healgun_hps)
-                                                               trace_ent.health = min(trace_ent.health + autocvar_g_vehicle_bumblebee_healgun_hps * dt, trace_ent.max_health);
-                                                       //else ..hmmm what? ammo?
-
-                                                       trace_ent.SendFlags |= TNSF_STATUS;
+                                                       if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= autocvar_g_vehicle_bumblebee_healgun_amax && autocvar_g_vehicle_bumblebee_healgun_aps)
+                                                               GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, autocvar_g_vehicle_bumblebee_healgun_aps * dt, autocvar_g_vehicle_bumblebee_healgun_amax);
                                                }
                                        }
+                               }
                        }
                }
 
@@ -676,7 +667,7 @@ void bumblebee_blowup(entity this)
                                 autocvar_g_vehicle_bumblebee_blowup_edgedamage,
                                 autocvar_g_vehicle_bumblebee_blowup_radius, this, NULL,
                                 autocvar_g_vehicle_bumblebee_blowup_forceintensity,
-                                DEATH_VH_BUMB_DEATH.m_id, NULL);
+                                DEATH_VH_BUMB_DEATH.m_id, DMG_NOWEP, NULL);
 
        sound(this, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
        Send_Effect(EFFECT_EXPLOSION_BIG, (this.origin + '0 0 100') + (randomvec() * 80), '0 0 0', 1);
@@ -803,7 +794,7 @@ METHOD(Bumblebee, vr_death, void(Bumblebee thisveh, entity instance))
 
     Send_Effect(EFFECT_EXPLOSION_MEDIUM, findbetterlocation(instance.origin, 16), '0 0 0', 1);
 
-    instance.health                    = 0;
+    SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage      = func_null;
     instance.solid                     = SOLID_NOT;
     instance.takedamage                = DAMAGE_NO;
index fa05c6a6f12dbd46343c941148c46b4c14db0366..5f4068a7d281ff3269d4cef825fbb3d333ed5765 100644 (file)
@@ -27,16 +27,12 @@ bool bumble_raygun_send(entity this, entity to, float sf)
 
     if(sf & BRG_START)
     {
-        WriteCoord(MSG_ENTITY, this.hook_start_x);
-        WriteCoord(MSG_ENTITY, this.hook_start_y);
-        WriteCoord(MSG_ENTITY, this.hook_start_z);
+        WriteVector(MSG_ENTITY, this.hook_start);
     }
 
     if(sf & BRG_END)
     {
-        WriteCoord(MSG_ENTITY, this.hook_end_x);
-        WriteCoord(MSG_ENTITY, this.hook_end_y);
-        WriteCoord(MSG_ENTITY, this.hook_end_z);
+        WriteVector(MSG_ENTITY, this.hook_end);
     }
 
     return true;
@@ -75,17 +71,13 @@ NET_HANDLE(ENT_CLIENT_BUMBLE_RAYGUN, bool isnew)
 
     if(sf & BRG_START)
     {
-        this.origin_x = ReadCoord();
-        this.origin_y = ReadCoord();
-        this.origin_z = ReadCoord();
+        this.origin = ReadVector();
         setorigin(this, this.origin);
     }
 
     if(sf & BRG_END)
     {
-        this.bumble_origin_x = ReadCoord();
-        this.bumble_origin_y = ReadCoord();
-        this.bumble_origin_z = ReadCoord();
+        this.bumble_origin = ReadVector();
     }
     return true;
 }
index 8dbfae4677221eb70a7d63feb206b3f9724f3f4a..18e13bcbbe68d3f23bc558dad7b0e0f9427c4d2b 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)
@@ -462,7 +461,7 @@ void racer_blowup(entity this)
                                        autocvar_g_vehicle_racer_blowup_edgedamage,
                                        autocvar_g_vehicle_racer_blowup_radius, NULL, NULL,
                                        autocvar_g_vehicle_racer_blowup_forceintensity,
-                                       DEATH_VH_WAKI_DEATH.m_id, NULL);
+                                       DEATH_VH_WAKI_DEATH.m_id, DMG_NOWEP, NULL);
 
        this.nextthink  = time + autocvar_g_vehicle_racer_respawntime;
        setthink(this, vehicles_spawn);
@@ -567,7 +566,7 @@ METHOD(Racer, vr_death, void(Racer thisveh, entity instance))
 {
 #ifdef SVQC
     setSendEntity(instance, func_null); // stop networking this racer (for now)
-    instance.health                    = 0;
+    SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage      = func_null;
     instance.solid                     = SOLID_CORPSE;
     instance.takedamage                = DAMAGE_NO;
index 02015eb8daba23c239bee5794c9734b206b2decc..0e7222eb2403d847db29476e04fead2a60ad3829 100644 (file)
@@ -14,7 +14,7 @@ METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weapone
             veh.vehicle_energy -= autocvar_g_vehicle_racer_cannon_cost;
             veh.wait = time;
         }
-        if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+        if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0, DEATH_VH_WAKI_GUN.m_id);
         vector org = w_shotorg;
         vector dir = w_shotdir;
         entity bolt = vehicles_projectile(veh, EFFECT_RACER_MUZZLEFLASH.eent_eff_name, SND_LASERGUN_FIRE,
@@ -26,7 +26,7 @@ METHOD(RacerAttack, wr_think, void(entity thiswep, entity actor, .entity weapone
     }
     if (fire & 2)
     if (!isPlayer || weapon_prepareattack(thiswep, actor, weaponentity, false, 0.2)) {
-        if (isPlayer) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+        if (isPlayer) W_SetupShot_Dir(actor, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0, DEATH_VH_WAKI_ROCKET.m_id);
         racer_fire_rocket(player, w_shotorg, w_shotdir, NULL);
         weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, 0, w_ready);
     }
index 3bd712011622ab35700b19e42d398825eef05e1f..7e4505ca3e0e7e6342cb08bbe76297e62b61d103 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/weapons/_all.qh>
 
 CLASS(RacerAttack, PortoLaunch)
-/* flags     */ ATTRIB(RacerAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(RacerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RacerAttack, impulse, int, 3);
 /* refname   */ ATTRIB(RacerAttack, netname, string, "racercannon");
 /* wepname   */ ATTRIB(RacerAttack, m_name, string, _("Racer cannon"));
index d7ef38abcad18d731ee7337e5f7a17bcc9f4c7f4..f44dcc578464e7a2e485c5da437a286bd721bc87 100644 (file)
@@ -254,7 +254,7 @@ bool raptor_frame(entity this, float dt)
        setorigin(this, vehic.origin + '0 0 32');
        this.oldorigin = this.origin; // negate fall damage
 
-       this.vehicle_weapon2mode = vehic.vehicle_weapon2mode;
+       STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
 
        vector vf, ad;
        // Target lock & predict
@@ -376,7 +376,7 @@ bool raptor_frame(entity this, float dt)
 
        Weapon wep2a = WEP_RAPTOR_BOMB;
        if(!forbidWeaponUse(this))
-       if(vehic.vehicle_weapon2mode == RSM_BOMB)
+       if(STAT(VEHICLESTAT_W2MODE, vehic) == RSM_BOMB)
        {
                if(time > vehic.lip + autocvar_g_vehicle_raptor_bombs_refire)
                if(PHYS_INPUT_BUTTON_ATCK2(this))
@@ -465,7 +465,7 @@ bool raptor_takeoff(entity this, float dt)
        else
                this.PlayerPhysplug = raptor_frame;
 
-       this.vehicle_weapon2mode = vehic.vehicle_weapon2mode;
+       STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
 
        if(vehic.vehicle_flags  & VHF_SHIELDREGEN)
                vehicles_regen(vehic, vehic.dmg_time, vehicle_shield, autocvar_g_vehicle_raptor_shield, autocvar_g_vehicle_raptor_shield_regen_pause, autocvar_g_vehicle_raptor_shield_regen, dt, true);
@@ -493,7 +493,7 @@ void raptor_blowup(entity this, entity toucher)
 {
        this.deadflag   = DEAD_DEAD;
        this.vehicle_exit(this, VHEF_NORMAL);
-       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_RAPT_DEATH.m_id, NULL);
+       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_RAPT_DEATH.m_id, DMG_NOWEP, NULL);
 
        this.alpha                = -1;
        set_movetype(this, MOVETYPE_NONE);
@@ -539,20 +539,20 @@ bool raptor_impulse(entity this, int _imp)
        switch(_imp)
        {
                case IMP_weapon_group_1.impulse:
-                       this.vehicle.vehicle_weapon2mode = RSM_BOMB;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_BOMB;
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_group_2.impulse:
-                       this.vehicle.vehicle_weapon2mode = RSM_FLARE;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_FLARE;
                        CSQCVehicleSetup(this, 0);
                        return true;
 
                case IMP_weapon_next_byid.impulse:
                case IMP_weapon_next_bypriority.impulse:
                case IMP_weapon_next_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode += 1;
-                       if(this.vehicle.vehicle_weapon2mode > RSM_LAST)
-                               this.vehicle.vehicle_weapon2mode = RSM_FIRST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) += 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) > RSM_LAST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_FIRST;
 
                        CSQCVehicleSetup(this, 0);
                        return true;
@@ -560,9 +560,9 @@ bool raptor_impulse(entity this, int _imp)
                case IMP_weapon_prev_byid.impulse:
                case IMP_weapon_prev_bypriority.impulse:
                case IMP_weapon_prev_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode -= 1;
-                       if(this.vehicle.vehicle_weapon2mode < RSM_FIRST)
-                               this.vehicle.vehicle_weapon2mode = RSM_LAST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) -= 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) < RSM_FIRST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = RSM_LAST;
 
                        CSQCVehicleSetup(this, 0);
                        return true;
@@ -590,7 +590,7 @@ METHOD(Raptor, vr_impact, void(Raptor thisveh, entity instance))
 }
 METHOD(Raptor, vr_enter, void(Raptor thisveh, entity instance))
 {
-    instance.vehicle_weapon2mode = RSM_BOMB;
+    STAT(VEHICLESTAT_W2MODE, instance) = RSM_BOMB;
     instance.owner.PlayerPhysplug = raptor_takeoff;
     set_movetype(instance, MOVETYPE_BOUNCEMISSILE);
     instance.solid               = SOLID_SLIDEBOX;
@@ -609,7 +609,7 @@ METHOD(Raptor, vr_enter, void(Raptor thisveh, entity instance))
 }
 METHOD(Raptor, vr_death, void(Raptor thisveh, entity instance))
 {
-    instance.health                            = 0;
+       SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage              = func_null;
     instance.solid                             = SOLID_CORPSE;
     instance.takedamage                        = DAMAGE_NO;
index 514d67c0e6cd5b31c0ea805c39d0200c26fd2c2b..53475d6cfd382e6efe95ae50ae09642b6fe04a89 100644 (file)
@@ -10,7 +10,7 @@ METHOD(RaptorCannon, wr_think, void(entity thiswep, entity actor, .entity weapon
     float t = autocvar_g_vehicle_raptor_cannon_refire * (1 + veh.misc_bulletcounter == 4);
     if (fire & 1)
     if (weapon_prepareattack(thiswep, player, weaponentity, false, t)) {
-        if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0);
+        if (isPlayer) W_SetupShot_Dir(player, weaponentity, v_forward, false, 0, SND_Null, CH_WEAPON_B, 0, DEATH_VH_RAPT_CANNON.m_id);
         vector org = w_shotorg;
         vector dir = w_shotdir;
         if (veh) {
@@ -50,7 +50,7 @@ METHOD(RaptorBomb, wr_think, void(entity thiswep, entity actor, .entity weaponen
 }
 
 void raptor_flare_think(entity this);
-void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
 void raptor_flare_touch(entity this, entity toucher);
 
 METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire)) {
@@ -74,7 +74,7 @@ METHOD(RaptorFlare, wr_think, void(entity thiswep, entity actor, .entity weapone
             _flare.solid = SOLID_CORPSE;
             _flare.takedamage = DAMAGE_YES;
             _flare.event_damage = raptor_flare_damage;
-            _flare.health = 20;
+            SetResourceAmountExplicit(_flare, RESOURCE_HEALTH, 20);
             _flare.tur_impacttime = time + autocvar_g_vehicle_raptor_flare_lifetime;
             settouch(_flare, raptor_flare_touch);
         }
@@ -88,7 +88,7 @@ void raptor_bomblet_boom(entity this)
     RadiusDamage (this, this.realowner, autocvar_g_vehicle_raptor_bomblet_damage,
                                     autocvar_g_vehicle_raptor_bomblet_edgedamage,
                                     autocvar_g_vehicle_raptor_bomblet_radius, NULL, NULL,
-                                    autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB.m_id, NULL);
+                                    autocvar_g_vehicle_raptor_bomblet_force, DEATH_VH_RAPT_BOMB.m_id, DMG_NOWEP, NULL);
     delete(this);
 }
 
@@ -189,10 +189,10 @@ void raptor_flare_touch(entity this, entity toucher)
     delete(this);
 }
 
-void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void raptor_flare_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-    this.health -= damage;
-    if(this.health <= 0)
+    TakeResource(this, RESOURCE_HEALTH, damage);
+    if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
         delete(this);
 }
 
index a7908d50d340829f44d903c59749aadd134e85f8..c7ffff79700ddb02e03dffc5dcacd20406a20024 100644 (file)
@@ -3,7 +3,7 @@
 #include <common/weapons/_all.qh>
 
 CLASS(RaptorCannon, PortoLaunch)
-/* flags     */ ATTRIB(RaptorCannon, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(RaptorCannon, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RaptorCannon, impulse, int, 3);
 /* refname   */ ATTRIB(RaptorCannon, netname, string, "raptorcannon");
 /* wepname   */ ATTRIB(RaptorCannon, m_name, string, _("Raptor cannon"));
@@ -11,7 +11,7 @@ ENDCLASS(RaptorCannon)
 REGISTER_WEAPON(RAPTOR, NEW(RaptorCannon));
 
 CLASS(RaptorBomb, PortoLaunch)
-/* flags     */ ATTRIB(RaptorBomb, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags     */ ATTRIB(RaptorBomb, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
 /* impulse   */ ATTRIB(RaptorBomb, impulse, int, 3);
 /* refname   */ ATTRIB(RaptorBomb, netname, string, "raptorbomb");
 /* wepname   */ ATTRIB(RaptorBomb, m_name, string, _("Raptor bomb"));
index 8d782f927ff7de9a3010efcc4d6a24cf9c2b6ecf..5a69976effc905965c50480e25440094babb9c81 100644 (file)
@@ -63,7 +63,7 @@ bool spiderbot_frame(entity this, float dt)
                .entity weaponentity = weaponentities[slot];
                this.(weaponentity).m_switchweapon = WEP_Null;
        }
-       this.vehicle_weapon2mode = vehic.vehicle_weapon2mode;
+       STAT(VEHICLESTAT_W2MODE, this) = STAT(VEHICLESTAT_W2MODE, vehic);
 
 
 #if 1 // 0 to enable per-gun impact aux crosshairs
@@ -449,7 +449,7 @@ void spiderbot_blowup(entity this)
        SUB_SetFade(g1, time, min(this.respawntime, 10));
        SUB_SetFade(g2, time, min(this.respawntime, 10));
 
-       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_SPID_DEATH.m_id, NULL);
+       RadiusDamage (this, this.enemy, 250, 15, 250, NULL, NULL, 250, DEATH_VH_SPID_DEATH.m_id, DMG_NOWEP, NULL);
 
        this.alpha = this.tur_head.alpha = this.gun1.alpha = this.gun2.alpha = -1;
        set_movetype(this, MOVETYPE_NONE);
@@ -464,37 +464,37 @@ bool spiderbot_impulse(entity this, int _imp)
        switch(_imp)
        {
                case IMP_weapon_group_1.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_VOLLY;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_VOLLY;
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_group_2.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_GUIDE;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_GUIDE;
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_group_3.impulse:
-                       this.vehicle.vehicle_weapon2mode = SBRM_ARTILLERY;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_ARTILLERY;
                        CSQCVehicleSetup(this, 0);
                        return true;
 
                case IMP_weapon_next_byid.impulse:
                case IMP_weapon_next_bypriority.impulse:
                case IMP_weapon_next_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode += 1;
-                       if(this.vehicle.vehicle_weapon2mode > SBRM_LAST)
-                               this.vehicle.vehicle_weapon2mode = SBRM_FIRST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) += 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) > SBRM_LAST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_FIRST;
 
-                       //centerprint(this, strcat("Rocket mode is ", ftos(this.vehicle.vehicle_weapon2mode)));
+                       //centerprint(this, strcat("Rocket mode is ", ftos(STAT(VEHICLESTAT_W2MODE, this.vehicle))));
                        CSQCVehicleSetup(this, 0);
                        return true;
                case IMP_weapon_last.impulse:
                case IMP_weapon_prev_byid.impulse:
                case IMP_weapon_prev_bypriority.impulse:
                case IMP_weapon_prev_bygroup.impulse:
-                       this.vehicle.vehicle_weapon2mode -= 1;
-                       if(this.vehicle.vehicle_weapon2mode < SBRM_FIRST)
-                               this.vehicle.vehicle_weapon2mode = SBRM_LAST;
+                       STAT(VEHICLESTAT_W2MODE, this.vehicle) -= 1;
+                       if(STAT(VEHICLESTAT_W2MODE, this.vehicle) < SBRM_FIRST)
+                               STAT(VEHICLESTAT_W2MODE, this.vehicle) = SBRM_LAST;
 
-                       //centerprint(this, strcat("Rocket mode is ", ftos(this.vehicle.vehicle_weapon2mode)));
+                       //centerprint(this, strcat("Rocket mode is ", ftos(STAT(VEHICLESTAT_W2MODE, this.vehicle))));
                        CSQCVehicleSetup(this, 0);
                        return true;
 
@@ -521,7 +521,7 @@ METHOD(Spiderbot, vr_impact, void(Spiderbot thisveh, entity instance))
 }
 METHOD(Spiderbot, vr_enter, void(Spiderbot thisveh, entity instance))
 {
-    instance.vehicle_weapon2mode = SBRM_GUIDE;
+    STAT(VEHICLESTAT_W2MODE, instance) = SBRM_GUIDE;
     set_movetype(instance, MOVETYPE_WALK);
     CSQCVehicleSetup(instance.owner, 0);
     instance.owner.vehicle_health = (instance.vehicle_health / autocvar_g_vehicle_spiderbot_health) * 100;
@@ -540,7 +540,7 @@ METHOD(Spiderbot, vr_think, void(Spiderbot thisveh, entity instance))
 }
 METHOD(Spiderbot, vr_death, void(Spiderbot thisveh, entity instance))
 {
-    instance.health                            = 0;
+       SetResourceAmountExplicit(instance, RESOURCE_HEALTH, 0);
     instance.event_damage              = func_null;
     instance.takedamage                        = DAMAGE_NO;
     settouch(instance, func_null);
index 7887781ed7a74f3b5c3850dfad0cfdd64a48e398..a18d0321356f0bb4311abbf12997a9f2681296fa 100644 (file)
@@ -141,7 +141,7 @@ void spiderbot_rocket_do(entity this)
 
     if (this.wait != -10)
     {
-        if (PHYS_INPUT_BUTTON_ATCK2(this.owner) && this.vehicle_weapon2mode == SBRM_GUIDE)
+        if (PHYS_INPUT_BUTTON_ATCK2(this.owner) && STAT(VEHICLESTAT_W2MODE, this) == SBRM_GUIDE)
         {
             if (this.wait == 1)
             if (this.tur_head.frame == 9 || this.tur_head.frame == 1)
@@ -180,7 +180,7 @@ void spiderbot_rocket_do(entity this)
 
     v = gettaginfo(this.tur_head,gettagindex(this.tur_head,"tag_fire"));
 
-    switch(this.vehicle_weapon2mode)
+    switch(STAT(VEHICLESTAT_W2MODE, this))
     {
         case SBRM_VOLLY:
             rocket = vehicles_projectile(this, EFFECT_SPIDERBOT_ROCKETLAUNCH.eent_eff_name, SND_ROCKET_FIRE,
@@ -240,7 +240,7 @@ void spiderbot_rocket_do(entity this)
     if (this.tur_head.frame == 9)
         this.attack_finished_single[0] = autocvar_g_vehicle_spiderbot_rocket_reload;
     else
-        this.attack_finished_single[0] = ((this.vehicle_weapon2mode ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
+        this.attack_finished_single[0] = ((STAT(VEHICLESTAT_W2MODE, this) ==  SBRM_VOLLY) ? autocvar_g_vehicle_spiderbot_rocket_refire2 : autocvar_g_vehicle_spiderbot_rocket_refire);
 
     this.gun2.cnt = time + this.attack_finished_single[0];
 }
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 e430ec2e78c252dea99cfc5c8fdfcc1a874bce8a..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)
@@ -293,24 +294,21 @@ vector shotorg_adjustfromclient(vector vecs, float y_is_right, float algn)
 
 vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn)
 {
-#ifdef SVQC
        string s;
-#endif
        if (visual)
        {
                vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
        }
-#ifdef SVQC
-       else if (autocvar_g_shootfromeye)
+       else if (STAT(SHOOTFROMEYE))
        {
                vecs.y = vecs.z = 0;
        }
-       else if (autocvar_g_shootfromcenter)
+       else if (STAT(SHOOTFROMCENTER))
        {
                vecs.y = 0;
                vecs.z -= 2;
        }
-       else if ((s = autocvar_g_shootfromfixedorigin) != "")
+       else if ((s = G_SHOOTFROMFIXEDORIGIN) != "")
        {
                vector v = stov(s);
                if (y_is_right) v.y = -v.y;
@@ -318,7 +316,6 @@ vector shotorg_adjust_values(vector vecs, bool y_is_right, bool visual, int algn
                vecs.y = v.y;
                vecs.z = v.z;
        }
-#endif
        else  // just do the same as top
        {
                vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
@@ -531,7 +528,7 @@ void CL_WeaponEntity_SetModel(entity this, string name, bool _anim)
        // make them match perfectly
 #ifdef SVQC
     // null during init
-    if (this.owner) this.owner.stat_shotorg = compressed_shotorg;
+    if (this.owner) STAT(SHOTORG, this.owner) = compressed_shotorg;
        this.movedir = decompressShotOrigin(compressed_shotorg);
 #else
        this.movedir = decompressShotOrigin(compressed_shotorg);
@@ -554,10 +551,7 @@ REGISTER_NET_TEMP(wframe)
 #ifdef CSQC
 NET_HANDLE(wframe, bool isNew)
 {
-       vector a;
-       a.x = ReadCoord();
-    a.y = ReadCoord();
-    a.z = ReadCoord();
+       vector a = ReadVector();
     int slot = ReadByte();
        bool restartanim = ReadByte();
        entity wepent = viewmodels[slot];
@@ -590,9 +584,7 @@ void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim)
        int channel = MSG_ONE;
        msg_entity = actor;
        WriteHeader(channel, wframe);
-       WriteCoord(channel, a.x);
-       WriteCoord(channel, a.y);
-       WriteCoord(channel, a.z);
+       WriteVector(channel, a);
        WriteByte(channel, weaponslot(weaponentity.weaponentity_fld));
        WriteByte(channel, restartanim);
        WriteByte(channel, weaponentity.state);
index beaa6cb48a3773e2555b4817177696242b7b7e43..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)
@@ -359,6 +358,17 @@ ENUMCLASS_END(WFRAME)
 
 .WFRAME wframe;
 
+#ifdef SVQC
+    #define G_SHOOTFROMFIXEDORIGIN autocvar_g_shootfromfixedorigin
+#elif defined(CSQC)
+    string autocvar_cl_shootfromfixedorigin;
+    #define G_SHOOTFROMFIXEDORIGIN autocvar_cl_shootfromfixedorigin
+#endif
+
 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 b5f542928f3fc4d869999c8b379a414143eb2a8e..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 */
@@ -108,6 +106,8 @@ CLASS(Weapon, Object)
         // no weapon specific image for this weapon
         return false;
     }
+    /** (CLIENT) check whether the weapon should zoom (special handling) */
+    METHOD(Weapon, wr_zoomdir, bool(Weapon this)) {return false;}
     /** (CLIENT) weapon specific view model */
     METHOD(Weapon, wr_viewmodel, string(Weapon this, entity wep)) { return string_null; }
     /** (CLIENT) weapon specific glow */
@@ -183,21 +183,20 @@ int max_shot_distance = 32768; // determined by world mins/maxs when map loads
 #endif
 
 // weapon flags
-const int WEP_TYPE_OTHER          =  0x00; // not for damaging people
-const int WEP_TYPE_SPLASH         =  0x01; // splash damage
-const int WEP_TYPE_HITSCAN        =  0x02; // hitscan
-const int WEP_TYPEMASK            =  0x0F;
-const int WEP_FLAG_CANCLIMB       =  0x10; // can be used for movement
-const int WEP_FLAG_NORMAL         =  0x20; // in "most weapons" set
-const int WEP_FLAG_HIDDEN         =  0x40; // hides from menu
-const int WEP_FLAG_RELOADABLE     =  0x80; // can has reload
-const int WEP_FLAG_SUPERWEAPON    = 0x100; // powerup timer
-const int WEP_FLAG_MUTATORBLOCKED = 0x200; // hides from impulse 99 etc. (mutators are allowed to clear this flag)
-const int WEP_TYPE_MELEE_PRI      = 0x400; // primary attack is melee swing (for animation)
-const int WEP_TYPE_MELEE_SEC      = 0x800; // secondary attack is melee swing (for animation)
-const int WEP_FLAG_DUALWIELD      = 0x1000; // weapon can be dual wielded
-const int WEP_FLAG_NODUAL         = 0x2000; // weapon doesn't work well with dual wielding (fireball etc just explode on fire), doesn't currently prevent anything
-const int WEP_FLAG_PENETRATEWALLS = 0x4000; // weapon has high calibur bullets that can penetrate thick walls (WEAPONTODO)
+const int WEP_TYPE_OTHER          =  BIT(0); // not for damaging people
+const int WEP_TYPE_SPLASH         =  BIT(1); // splash damage
+const int WEP_TYPE_HITSCAN        =  BIT(2); // hitscan
+const int WEP_FLAG_CANCLIMB       =  BIT(3); // can be used for movement
+const int WEP_FLAG_NORMAL         =  BIT(4); // in "most weapons" set
+const int WEP_FLAG_HIDDEN         =  BIT(5); // hides from menu
+const int WEP_FLAG_RELOADABLE     =  BIT(6); // can has reload
+const int WEP_FLAG_SUPERWEAPON    =  BIT(7); // powerup timer
+const int WEP_FLAG_MUTATORBLOCKED =  BIT(8); // hides from impulse 99 etc. (mutators are allowed to clear this flag)
+const int WEP_TYPE_MELEE_PRI      =  BIT(9); // primary attack is melee swing (for animation)
+const int WEP_TYPE_MELEE_SEC      =  BIT(10); // secondary attack is melee swing (for animation)
+const int WEP_FLAG_DUALWIELD      =  BIT(11); // weapon can be dual wielded
+const int WEP_FLAG_NODUAL         =  BIT(12); // weapon doesn't work well with dual wielding (fireball etc just explode on fire), doesn't currently prevent anything
+const int WEP_FLAG_PENETRATEWALLS =  BIT(13); // weapon has high calibur bullets that can penetrate thick walls (WEAPONTODO)
 
 // variables:
 string weaponorder_byid;
@@ -210,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 23e3dbcb2bc8d235e2921f45ab8803570bd0ea35..e78e10a3641d772427a9c053170db903a70e2fb0 100644 (file)
@@ -1,6 +1,8 @@
 #include "arc.qh"
 
 #ifdef SVQC
+#include <common/gamemodes/gamemode/onslaught/sv_onslaught.qh>
+#include <common/gamemodes/gamemode/onslaught/sv_generator.qh>
 
 bool W_Arc_Beam_Send(entity this, entity to, int sf)
 {
@@ -30,21 +32,17 @@ bool W_Arc_Beam_Send(entity this, entity to, int sf)
        }
        if(sf & ARC_SF_START) // starting location
        {
-               WriteCoord(MSG_ENTITY, this.beam_start.x);
-               WriteCoord(MSG_ENTITY, this.beam_start.y);
-               WriteCoord(MSG_ENTITY, this.beam_start.z);
+               WriteVector(MSG_ENTITY, this.beam_start);
        }
        if(sf & ARC_SF_WANTDIR) // want/aim direction
        {
-               WriteCoord(MSG_ENTITY, this.beam_wantdir.x);
-               WriteCoord(MSG_ENTITY, this.beam_wantdir.y);
-               WriteCoord(MSG_ENTITY, this.beam_wantdir.z);
+               WriteVector(MSG_ENTITY, this.beam_wantdir);
        }
        if(sf & ARC_SF_BEAMDIR) // beam direction
        {
-               WriteCoord(MSG_ENTITY, this.beam_dir.x);
-               WriteCoord(MSG_ENTITY, this.beam_dir.y);
-               WriteCoord(MSG_ENTITY, this.beam_dir.z);
+               WriteAngle(MSG_ENTITY, this.beam_dir.x);
+               WriteAngle(MSG_ENTITY, this.beam_dir.y);
+               WriteAngle(MSG_ENTITY, this.beam_dir.z);
        }
        if(sf & ARC_SF_BEAMTYPE) // beam type
        {
@@ -87,14 +85,14 @@ float Arc_GetHeat_Percent(entity player, .entity weaponentity)
 }
 void Arc_Player_SetHeat(entity player, .entity weaponentity)
 {
-       player.arc_heat_percent = Arc_GetHeat_Percent(player, weaponentity);
+       player.(weaponentity).arc_heat_percent = Arc_GetHeat_Percent(player, weaponentity);
        //dprint("Heat: ",ftos(player.arc_heat_percent*100),"%\n");
 }
 
 void W_Arc_Bolt_Explode(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
-       RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR(arc, bolt_damage), WEP_CVAR(arc, bolt_edgedamage), WEP_CVAR(arc, bolt_radius), NULL, NULL, WEP_CVAR(arc, bolt_force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -104,18 +102,18 @@ void W_Arc_Bolt_Explode_use(entity this, entity actor, entity trigger)
        W_Arc_Bolt_Explode(this, trigger);
 }
 
-void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Arc_Bolt_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1))
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, getthink(this));
 }
 
@@ -131,7 +129,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(arc, bolt_ammo), weaponentity);
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage));
+       W_SetupShot(actor, weaponentity, false, 2, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR(arc, bolt_damage), WEP_ARC.m_id | HITTYPE_SECONDARY);
 
        Send_Effect(EFFECT_ARC_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -142,7 +140,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        missile.bot_dodgerating = WEP_CVAR(arc, bolt_damage);
 
        missile.takedamage = DAMAGE_YES;
-       missile.health = WEP_CVAR(arc, bolt_health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(arc, bolt_health));
        missile.damageforcescale = WEP_CVAR(arc, bolt_damageforcescale);
        missile.event_damage = W_Arc_Bolt_Damage;
        missile.damagedbycontents = true;
@@ -154,6 +152,7 @@ void W_Arc_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        missile.nextthink = time + WEP_CVAR(arc, bolt_lifetime);
        PROJECTILE_MAKETRIGGER(missile);
        missile.projectiledeathtype = WEP_ARC.m_id | HITTYPE_SECONDARY;
+       missile.weaponentity_fld = weaponentity;
        setorigin(missile, w_shotorg);
        setsize(missile, '0 0 0', '0 0 0');
 
@@ -192,11 +191,9 @@ void W_Arc_Beam_Think(entity this)
        if(
                !IS_PLAYER(own)
                ||
-               (!thiswep.wr_checkammo1(thiswep, own, weaponentity) && !(own.items & IT_UNLIMITED_WEAPON_AMMO))
-               ||
                IS_DEAD(own)
                ||
-               forbidWeaponUse(own)
+               !weapon_prepareattack_check(thiswep, own, weaponentity, this.beam_bursting, -1)
                ||
                own.(weaponentity).m_switchweapon != WEP_ARC
                ||
@@ -274,7 +271,8 @@ void W_Arc_Beam_Think(entity this)
                SND_Null,
                0,
                WEP_CVAR(arc, beam_damage) * coefficient,
-               WEP_CVAR(arc, beam_range)
+               WEP_CVAR(arc, beam_range),
+               WEP_ARC.m_id
        );
 
        // After teleport, "lock" the beam until the teleport is confirmed.
@@ -410,7 +408,7 @@ void W_Arc_Beam_Think(entity this)
                beam_endpos = WarpZone_TransformOrigin(WarpZone_trace_transform, beam_endpos);
                new_dir = WarpZone_TransformVelocity(WarpZone_trace_transform, new_dir);
 
-               float is_player = (
+               bool is_player = (
                        IS_PLAYER(trace_ent)
                        ||
                        trace_ent.classname == "body"
@@ -418,65 +416,42 @@ void W_Arc_Beam_Think(entity this)
                        IS_MONSTER(trace_ent)
                );
 
-               if(trace_ent && trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
+               if(trace_ent)
                {
-                       // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
-                       // NO. trace_endpos should be just fine. If not,
-                       // that's an engine bug that needs proper debugging.
-                       vector hitorigin = trace_endpos;
-
-                       float falloff = ExponentialFalloff(
-                               WEP_CVAR(arc, beam_falloff_mindist),
-                               WEP_CVAR(arc, beam_falloff_maxdist),
-                               WEP_CVAR(arc, beam_falloff_halflifedist),
-                               vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
-                       );
-
-                       if(is_player && SAME_TEAM(own, trace_ent))
+                       if(SAME_TEAM(own, trace_ent))
                        {
-                               float roothealth, rootarmor;
-                               if(burst)
-                               {
-                                       roothealth = WEP_CVAR(arc, burst_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, burst_healing_aps);
-                               }
-                               else
+                               float roothealth = ((burst) ? WEP_CVAR(arc, burst_healing_hps) : WEP_CVAR(arc, beam_healing_hps));
+                               float rootarmor = ((burst) ? WEP_CVAR(arc, burst_healing_aps) : WEP_CVAR(arc, beam_healing_aps));
+                               float hplimit = ((IS_PLAYER(trace_ent)) ? WEP_CVAR(arc, beam_healing_hmax) : RESOURCE_LIMIT_NONE);
+                               Heal(trace_ent, own, (roothealth * coefficient), hplimit);
+                               if(IS_PLAYER(trace_ent) && rootarmor)
                                {
-                                       roothealth = WEP_CVAR(arc, beam_healing_hps);
-                                       rootarmor = WEP_CVAR(arc, beam_healing_aps);
+                                       if(GetResourceAmount(trace_ent, RESOURCE_ARMOR) <= WEP_CVAR(arc, beam_healing_amax))
+                                       {
+                                               GiveResourceWithLimit(trace_ent, RESOURCE_ARMOR, (rootarmor * coefficient), WEP_CVAR(arc, beam_healing_amax));
+                                               trace_ent.pauserotarmor_finished = max(
+                                                       trace_ent.pauserotarmor_finished,
+                                                       time + autocvar_g_balance_pause_armor_rot
+                                               );
+                                       }
                                }
-
-                               if(trace_ent.health <= WEP_CVAR(arc, beam_healing_hmax) && roothealth)
-                               {
-                                       trace_ent.health = min(
-                                               trace_ent.health + (roothealth * coefficient),
-                                               WEP_CVAR(arc, beam_healing_hmax)
-                                       );
-                               }
-                               if(trace_ent.armorvalue <= WEP_CVAR(arc, beam_healing_amax) && rootarmor)
-                               {
-                                       trace_ent.armorvalue = min(
-                                               trace_ent.armorvalue + (rootarmor * coefficient),
-                                               WEP_CVAR(arc, beam_healing_amax)
-                                       );
-                               }
-
-                               // stop rot, set visual effect
                                if(roothealth || rootarmor)
-                               {
-                                       trace_ent.pauserothealth_finished = max(
-                                               trace_ent.pauserothealth_finished,
-                                               time + autocvar_g_balance_pause_health_rot
-                                       );
-                                       trace_ent.pauserotarmor_finished = max(
-                                               trace_ent.pauserotarmor_finished,
-                                               time + autocvar_g_balance_pause_armor_rot
-                                       );
                                        new_beam_type = ARC_BT_HEAL;
-                               }
                        }
-                       else
+                       else if(trace_ent.takedamage && (is_player || WEP_CVAR(arc, beam_nonplayerdamage)))
                        {
+                               // calculate our own hit origin as trace_endpos tends to jump around annoyingly (to player origin?)
+                               // NO. trace_endpos should be just fine. If not,
+                               // that's an engine bug that needs proper debugging.
+                               vector hitorigin = trace_endpos;
+
+                               float falloff = ExponentialFalloff(
+                                       WEP_CVAR(arc, beam_falloff_mindist),
+                                       WEP_CVAR(arc, beam_falloff_maxdist),
+                                       WEP_CVAR(arc, beam_falloff_halflifedist),
+                                       vlen(WarpZone_UnTransformOrigin(WarpZone_trace_transform, hitorigin) - w_shotorg)
+                               );
+
                                float rootdamage;
                                if(is_player)
                                {
@@ -504,6 +479,7 @@ void W_Arc_Beam_Think(entity this)
                                        own,
                                        rootdamage * coefficient * falloff,
                                        WEP_ARC.m_id,
+                                       weaponentity,
                                        hitorigin,
                                        WEP_CVAR(arc, beam_force) * new_dir * coefficient * falloff
                                );
@@ -560,12 +536,12 @@ void W_Arc_Beam(float burst, entity actor, .entity weaponentity)
 void Arc_Smoke(entity actor, .entity weaponentity)
 {
        makevectors(actor.v_angle);
-       W_SetupShot_Range(actor,weaponentity,true,0,SND_Null,0,0,0);
+       W_SetupShot_Range(actor,weaponentity,true,0,SND_Null,0,0,0,WEP_ARC.m_id); // TODO: probably doesn't need deathtype, since this is just a prefire effect
 
        vector smoke_origin = w_shotorg + actor.velocity*frametime;
        if ( actor.arc_overheat > time )
        {
-               if ( random() < actor.arc_heat_percent )
+               if ( random() < actor.(weaponentity).arc_heat_percent )
                        Send_Effect(EFFECT_ARC_SMOKE, smoke_origin, '0 0 0', 1 );
                if ( PHYS_INPUT_BUTTON_ATCK(actor) || PHYS_INPUT_BUTTON_ATCK2(actor) )
                {
@@ -657,7 +633,7 @@ METHOD(Arc, wr_think, void(entity thiswep, entity actor, .entity weaponentity, i
     }
     else if(fire & 2)
     {
-        if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(arc, bolt_refire)))
+        if(weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR(arc, bolt_refire)))
         {
             W_Arc_Attack_Bolt(thiswep, actor, weaponentity);
             weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(arc, bolt_refire), w_ready);
@@ -753,6 +729,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))
 {
@@ -803,32 +782,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:
@@ -885,17 +869,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,
@@ -912,9 +909,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;
 
@@ -1120,7 +1124,7 @@ void Draw_ArcBeam(entity this)
                        )
                );
        }
-       if(this.beam_muzzleeffect)
+       if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
        {
                pointparticles(
                        this.beam_muzzleeffect,
@@ -1161,11 +1165,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;
@@ -1224,9 +1230,7 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
 
        if(sf & ARC_SF_START) // starting location
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
        }
        else if(this.beam_usevieworigin) // infer the location from player location
        {
@@ -1246,16 +1250,14 @@ NET_HANDLE(ENT_CLIENT_ARC_BEAM, bool isnew)
 
        if(sf & ARC_SF_WANTDIR) // want/aim direction
        {
-               this.v_angle_x = ReadCoord();
-               this.v_angle_y = ReadCoord();
-               this.v_angle_z = ReadCoord();
+               this.v_angle = ReadVector();
        }
 
        if(sf & ARC_SF_BEAMDIR) // beam direction
        {
-               this.angles_x = ReadCoord();
-               this.angles_y = ReadCoord();
-               this.angles_z = ReadCoord();
+               this.angles_x = ReadAngle();
+               this.angles_y = ReadAngle();
+               this.angles_z = ReadAngle();
        }
 
        if(sf & ARC_SF_BEAMTYPE) // beam type
@@ -1276,17 +1278,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;
-                               if(this.beam_muzzleeffect)
+                               this.beam_image = "particles/lgbeam";
+                               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;
                        }
@@ -1301,18 +1304,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;
                        }
@@ -1327,18 +1330,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;
                        }
@@ -1353,18 +1356,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;
                        }
@@ -1379,18 +1382,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;
                        }
@@ -1405,18 +1408,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;
                        }
@@ -1431,18 +1434,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;
                        }
@@ -1457,18 +1460,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;
                        }
@@ -1485,18 +1488,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 4ec2d4edc98a1a59053f8a7ac8346c9f5a7bd52e..187e5840257149e270f929961f13a7ed2412a7ea 100644 (file)
@@ -112,7 +112,7 @@ const int ARC_SF_LOCALMASK =   ARC_SF_START | ARC_SF_WANTDIR | ARC_SF_BEAMDIR;
 .float beam_heat; // (beam) amount of heat produced
 .float arc_overheat; // (dropped arc/player) time during which it's too hot
 .float arc_cooldown; // (dropped arc/player) cooling speed
-.float arc_heat_percent = _STAT(ARC_HEAT);
+.float arc_heat_percent;
 .float arc_smoke_sound;
 #endif
 #ifdef CSQC
index 2189c1db209d1d1d68b57949bdd8a5103183bb17..e3d713d470b5808f2f12a35b02cdaf6c53bb5755 100644 (file)
@@ -18,6 +18,7 @@ void W_Blaster_Touch(entity this, entity toucher)
                NULL,
                this.blaster_force,
                this.projectiledeathtype,
+               this.weaponentity_fld,
                toucher
        );
 
@@ -48,7 +49,7 @@ void W_Blaster_Attack(
 {
        vector s_forward = v_forward * cos(atk_shotangle * DEG2RAD) + v_up * sin(atk_shotangle * DEG2RAD);
 
-       W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, atk_damage);
+       W_SetupShot_Dir(actor, weaponentity, s_forward, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, atk_damage, atk_deathtype);
        Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
        entity missile = new(blasterbolt);
@@ -88,6 +89,7 @@ void W_Blaster_Attack(
        IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
        missile.projectiledeathtype = atk_deathtype;
+       missile.weaponentity_fld = weaponentity;
        setthink(missile, W_Blaster_Think);
        missile.nextthink = time + atk_delay;
 
@@ -193,6 +195,17 @@ METHOD(Blaster, wr_killmessage, Notification(entity thiswep))
     return WEAPON_BLASTER_MURDER;
 }
 
+METHOD(OffhandBlaster, offhand_think, void(OffhandBlaster this, entity actor, bool key_pressed))
+{
+       if (!key_pressed || (time < actor.jump_interval))
+       {
+               return;
+       }
+       actor.jump_interval = time + WEP_CVAR_SEC(blaster, refire) * W_WeaponRateFactor(actor);
+       .entity weaponentity = weaponentities[1];
+       BLASTER_SECONDARY_ATTACK(blaster, actor, weaponentity);
+}
+
 #endif
 #ifdef CSQC
 
index 0a0e7c17d2f57c21cdbee6d3735f0576c566377e..7efbdf7a52cc661899ce42c973c72c11df5959df 100644 (file)
@@ -48,6 +48,10 @@ REGISTER_WEAPON(BLASTER, blaster, NEW(Blaster));
 SPAWNFUNC_WEAPON(weapon_blaster, WEP_BLASTER)
 SPAWNFUNC_WEAPON(weapon_laser, WEP_BLASTER)
 
+CLASS(OffhandBlaster, OffhandWeapon)
+ENDCLASS(OffhandBlaster)
+OffhandBlaster OFFHAND_BLASTER; STATIC_INIT(OFFHAND_BLASTER) { OFFHAND_BLASTER = NEW(OffhandBlaster); }
+
 #ifdef SVQC
 .float blaster_damage;
 .float blaster_edgedamage;
@@ -55,4 +59,22 @@ SPAWNFUNC_WEAPON(weapon_laser, WEP_BLASTER)
 .float blaster_force;
 .float blaster_lifetime;
 
+// Will be demacroed after WEP_CVAR macros are also demacroed.
+#define BLASTER_SECONDARY_ATTACK(weapon_name, actor, weaponentity) \
+       makevectors(actor.v_angle); \
+       W_Blaster_Attack( \
+               actor, \
+               weaponentity, \
+               WEP_BLASTER.m_id | HITTYPE_SECONDARY, \
+               WEP_CVAR_SEC(weapon_name, shotangle), \
+               WEP_CVAR_SEC(weapon_name, damage), \
+               WEP_CVAR_SEC(weapon_name, edgedamage), \
+               WEP_CVAR_SEC(weapon_name, radius), \
+               WEP_CVAR_SEC(weapon_name, force), \
+               WEP_CVAR_SEC(weapon_name, speed), \
+               WEP_CVAR_SEC(weapon_name, spread), \
+               WEP_CVAR_SEC(weapon_name, delay), \
+               WEP_CVAR_SEC(weapon_name, lifetime) \
+       );
+
 #endif
index 246452fe62ff9cce932ec72a698033ef5d8839de..5a41666bdb74ba1a58b4a09eae9adf341e2a7d8a 100644 (file)
@@ -66,7 +66,7 @@ void W_Crylink_LinkExplode(entity e, entity e2, entity directhitentity)
        float isprimary = !(e.projectiledeathtype & HITTYPE_SECONDARY);
 
        RadiusDamage(e, e.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * a, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * a, WEP_CVAR_BOTH(crylink, isprimary, radius),
-                               NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, directhitentity);
+                               NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * a, e.projectiledeathtype, e.weaponentity_fld, directhitentity);
 
        W_Crylink_LinkExplode(e.queuenext, e2, directhitentity);
 
@@ -196,6 +196,7 @@ void W_Crylink_LinkJoinEffect_Think(entity this)
                                        NULL,
                                        WEP_CVAR_BOTH(crylink, isprimary, joinexplode_force) * n,
                                        e.projectiledeathtype,
+                                       e.weaponentity_fld,
                                        NULL
                                );
                                Send_Effect(EFFECT_CRYLINK_JOINEXPLODE, this.origin, '0 0 0', n);
@@ -246,7 +247,8 @@ 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), NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, toucher);
+       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)))))
        {
@@ -295,7 +297,7 @@ void W_Crylink_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        if(WEP_CVAR_PRI(crylink, joinexplode))
                maxdmg += WEP_CVAR_PRI(crylink, joinexplode_damage);
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, maxdmg);
+       W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, maxdmg, WEP_CRYLINK.m_id);
        forward = v_forward;
        right = v_right;
        up = v_up;
@@ -407,7 +409,7 @@ void W_Crylink_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        if(WEP_CVAR_SEC(crylink, joinexplode))
                maxdmg += WEP_CVAR_SEC(crylink, joinexplode_damage);
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE2, CH_WEAPON_A, maxdmg);
+       W_SetupShot(actor, weaponentity, false, 2, SND_CRYLINK_FIRE2, CH_WEAPON_A, maxdmg, WEP_CRYLINK.m_id | HITTYPE_SECONDARY);
        forward = v_forward;
        right = v_right;
        up = v_up;
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 46db8358cef76b423c43e5b218e391d6ff876a9a..ab97e3d7f0b6c5c16ba538092b3ece2bd2aeb4df 100644 (file)
@@ -38,6 +38,7 @@ void W_Devastator_Explode(entity this, entity directhitentity)
                NULL,
                WEP_CVAR(devastator, force),
                this.projectiledeathtype,
+               this.weaponentity_fld,
                directhitentity
        );
 
@@ -112,6 +113,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity)
                                                head,
                                                (WEP_CVAR(devastator, remote_jump_force) ? WEP_CVAR(devastator, remote_jump_force) : 0),
                                                this.projectiledeathtype | HITTYPE_BOUNCE,
+                                               this.weaponentity_fld,
                                                NULL
                                        );
                                        break;
@@ -131,6 +133,7 @@ void W_Devastator_DoRemoteExplode(entity this, .entity weaponentity)
                NULL,
                WEP_CVAR(devastator, remote_force),
                this.projectiledeathtype | HITTYPE_BOUNCE,
+               this.weaponentity_fld,
                NULL
        );
 
@@ -232,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
@@ -276,26 +287,26 @@ void W_Devastator_Touch(entity this, entity toucher)
        W_Devastator_Explode(this, toucher);
 }
 
-void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Devastator_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, W_Devastator_Explode_think);
 }
 
-void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
+void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(devastator, ammo), weaponentity);
 
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR(devastator, damage), WEP_DEVASTATOR.m_id);
        Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
        entity missile = WarpZone_RefSys_SpawnSameRefSys(actor);
@@ -313,7 +324,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        missile.takedamage = DAMAGE_YES;
        missile.damageforcescale = WEP_CVAR(devastator, damageforcescale);
-       missile.health = WEP_CVAR(devastator, health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(devastator, health));
        missile.event_damage = W_Devastator_Damage;
        missile.damagedbycontents = true;
        IL_PUSH(g_damagedbycontents, missile);
@@ -331,6 +342,7 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        setthink(missile, W_Devastator_Think);
        missile.nextthink = time;
        missile.cnt = time + WEP_CVAR(devastator, lifetime);
+       missile.rl_detonate_later = (fire & 2); // allow instant detonation
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
        IL_PUSH(g_bot_dodge, missile);
@@ -347,6 +359,11 @@ void W_Devastator_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        // common properties
        MUTATOR_CALLHOOK(EditProjectile, actor, missile);
+
+       if (time >= missile.nextthink)
+       {
+               getthink(missile)(missile);
+       }
 }
 
 METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
@@ -420,7 +437,7 @@ METHOD(Devastator, wr_aim, void(entity thiswep, entity actor, .entity weaponenti
         // but don't fire a new shot at the same time!
         if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
             PHYS_INPUT_BUTTON_ATCK2(actor) = true;
-        if((skill > 6.5) && (selfdamage > actor.health))
+        if((skill > 6.5) && (selfdamage > GetResourceAmount(actor, RESOURCE_HEALTH)))
             PHYS_INPUT_BUTTON_ATCK2(actor) = false;
         //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true)
         //     dprint(ftos(desirabledamage),"\n");
@@ -438,7 +455,7 @@ METHOD(Devastator, wr_think, void(entity thiswep, entity actor, .entity weaponen
             if(actor.(weaponentity).rl_release || WEP_CVAR(devastator, guidestop))
             if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR(devastator, refire)))
             {
-                W_Devastator_Attack(thiswep, actor, weaponentity);
+                W_Devastator_Attack(thiswep, actor, weaponentity, fire);
                 weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(devastator, animtime), w_ready);
                 actor.(weaponentity).rl_release = 0;
             }
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 05f306174dae307cd024d8518f77a20b39c30155..89738289f2b84b0205020e9ae0b4f33eeca05afb 100644 (file)
@@ -65,6 +65,7 @@ void W_Electro_ExplodeCombo(entity this)
                NULL,
                WEP_CVAR(electro, combo_force),
                WEP_ELECTRO.m_id | HITTYPE_BOUNCE, // use THIS type for a combo because primary can't bounce
+               this.weaponentity_fld,
                NULL
        );
 
@@ -95,6 +96,7 @@ void W_Electro_Explode(entity this, entity directhitentity)
                        NULL,
                        WEP_CVAR_SEC(electro, force),
                        this.projectiledeathtype,
+                       this.weaponentity_fld,
                        directhitentity
                );
        }
@@ -111,6 +113,7 @@ void W_Electro_Explode(entity this, entity directhitentity)
                        NULL,
                        WEP_CVAR_PRI(electro, force),
                        this.projectiledeathtype,
+                       this.weaponentity_fld,
                        directhitentity
                );
        }
@@ -201,7 +204,8 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
                2,
                SND_ELECTRO_FIRE,
                CH_WEAPON_A,
-               WEP_CVAR_PRI(electro, damage)
+               WEP_CVAR_PRI(electro, damage),
+               WEP_ELECTRO.m_id
        );
 
        Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
@@ -216,6 +220,7 @@ void W_Electro_Attack_Bolt(Weapon thiswep, entity actor, .entity weaponentity)
        proj.ltime = time + WEP_CVAR_PRI(electro, lifetime);
        PROJECTILE_MAKETRIGGER(proj);
        proj.projectiledeathtype = WEP_ELECTRO.m_id;
+       proj.weaponentity_fld = weaponentity;
        setorigin(proj, w_shotorg);
 
        // if (IS_CSQC)
@@ -253,7 +258,7 @@ void W_Electro_Orb_Stick(entity this, entity to)
 
        newproj.takedamage = this.takedamage;
        newproj.damageforcescale = this.damageforcescale;
-       newproj.health = this.health;
+       SetResourceAmountExplicit(newproj, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
        newproj.event_damage = this.event_damage;
        newproj.spawnshieldtime = this.spawnshieldtime;
        newproj.damagedbycontents = true;
@@ -261,6 +266,7 @@ void W_Electro_Orb_Stick(entity this, entity to)
 
        set_movetype(newproj, MOVETYPE_NONE); // lock the orb in place
        newproj.projectiledeathtype = this.projectiledeathtype;
+       newproj.weaponentity_fld = this.weaponentity_fld;
 
        settouch(newproj, func_null);
        setthink(newproj, getthink(this));
@@ -292,9 +298,9 @@ void W_Electro_Orb_Touch(entity this, entity toucher)
        }
 }
 
-void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        // note: combos are usually triggered by W_Electro_TriggerCombo, not damage
@@ -303,8 +309,8 @@ void W_Electro_Orb_Damage(entity this, entity inflictor, entity attacker, float
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_combo ? 1 : -1)))
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
-       if(this.health <= 0)
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.takedamage = DAMAGE_NO;
                this.nextthink = time;
@@ -347,7 +353,8 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
                2,
                SND_ELECTRO_FIRE2,
                CH_WEAPON_A,
-               WEP_CVAR_SEC(electro, damage)
+               WEP_CVAR_SEC(electro, damage),
+               WEP_ELECTRO.m_id | HITTYPE_SECONDARY
        );
 
        w_shotdir = v_forward; // no TrueAim for grenades please
@@ -363,6 +370,7 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
        proj.nextthink = time + WEP_CVAR_SEC(electro, lifetime);
        PROJECTILE_MAKETRIGGER(proj);
        proj.projectiledeathtype = WEP_ELECTRO.m_id | HITTYPE_SECONDARY;
+       proj.weaponentity_fld = weaponentity;
        setorigin(proj, w_shotorg);
 
        //proj.glow_size = 50;
@@ -373,7 +381,7 @@ void W_Electro_Attack_Orb(Weapon thiswep, entity actor, .entity weaponentity)
        setsize(proj, '-4 -4 -4', '4 4 4');
        proj.takedamage = DAMAGE_YES;
        proj.damageforcescale = WEP_CVAR_SEC(electro, damageforcescale);
-       proj.health = WEP_CVAR_SEC(electro, health);
+       SetResourceAmountExplicit(proj, RESOURCE_HEALTH, WEP_CVAR_SEC(electro, health));
        proj.event_damage = W_Electro_Orb_Damage;
        proj.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, proj);
index 3f6830f33c271516446592883fed8ff4e08a6c06..84113b7020f210352d85360cfc5f6b0d6d488d61 100644 (file)
@@ -14,9 +14,9 @@ void W_Fireball_Explode(entity this, entity directhitentity)
        this.takedamage = DAMAGE_NO;
 
        // 1. dist damage
-       d = (this.realowner.health + this.realowner.armorvalue);
-       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(fireball, damage), WEP_CVAR_PRI(fireball, edgedamage), WEP_CVAR_PRI(fireball, radius), NULL, NULL, WEP_CVAR_PRI(fireball, force), this.projectiledeathtype, directhitentity);
-       if(this.realowner.health + this.realowner.armorvalue >= d)
+       d = (GetResourceAmount(this.realowner, RESOURCE_HEALTH) + GetResourceAmount(this.realowner, RESOURCE_ARMOR));
+       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(fireball, damage), WEP_CVAR_PRI(fireball, edgedamage), WEP_CVAR_PRI(fireball, radius), NULL, NULL, WEP_CVAR_PRI(fireball, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+       if(GetResourceAmount(this.realowner, RESOURCE_HEALTH) + GetResourceAmount(this.realowner, RESOURCE_ARMOR) >= d)
        if(!this.cnt)
        {
                modeleffect_spawn("models/sphere/sphere.md3", 0, 0, this.origin, '0 0 0', '0 0 0', '0 0 0', 0, WEP_CVAR_PRI(fireball, bfgradius), 0.2, 0.05, 0.25);
@@ -44,7 +44,7 @@ void W_Fireball_Explode(entity this, entity directhitentity)
                        if(accuracy_isgooddamage(this.realowner, e))
                                accuracy_add(this.realowner, WEP_FIREBALL.m_id, 0, WEP_CVAR_PRI(fireball, bfgdamage) * points);
 
-                       Damage(e, this, this.realowner, WEP_CVAR_PRI(fireball, bfgdamage) * points, this.projectiledeathtype | HITTYPE_BOUNCE | HITTYPE_SPLASH, e.origin + e.view_ofs, WEP_CVAR_PRI(fireball, bfgforce) * dir);
+                       Damage(e, this, this.realowner, WEP_CVAR_PRI(fireball, bfgdamage) * points, this.projectiledeathtype | HITTYPE_BOUNCE | HITTYPE_SPLASH, this.weaponentity_fld, e.origin + e.view_ofs, WEP_CVAR_PRI(fireball, bfgforce) * dir);
                        Send_Effect(EFFECT_FIREBALL_BFGDAMAGE, e.origin, -1 * dir, 1);
                }
        }
@@ -117,16 +117,16 @@ void W_Fireball_Think(entity this)
        this.nextthink = time + 0.1;
 }
 
-void W_Fireball_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Fireball_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_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)
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                this.cnt = 1;
                W_PrepareExplosionByDamage(this, attacker, W_Fireball_Explode_think);
@@ -135,7 +135,7 @@ void W_Fireball_Damage(entity this, entity inflictor, entity attacker, float dam
 
 void W_Fireball_Attack1(entity actor, .entity weaponentity)
 {
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 2, SND_FIREBALL_FIRE2, CH_WEAPON_A, WEP_CVAR_PRI(fireball, damage) + WEP_CVAR_PRI(fireball, bfgdamage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 2, SND_FIREBALL_FIRE2, CH_WEAPON_A, WEP_CVAR_PRI(fireball, damage) + WEP_CVAR_PRI(fireball, bfgdamage), WEP_FIREBALL.m_id);
 
        Send_Effect(EFFECT_FIREBALL_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -147,13 +147,14 @@ void W_Fireball_Attack1(entity actor, .entity weaponentity)
        proj.use = W_Fireball_Explode_use;
        setthink(proj, W_Fireball_Think);
        proj.nextthink = time;
-       proj.health = WEP_CVAR_PRI(fireball, health);
+       SetResourceAmountExplicit(proj, RESOURCE_HEALTH, WEP_CVAR_PRI(fireball, health));
        proj.team = actor.team;
        proj.event_damage = W_Fireball_Damage;
        proj.takedamage = DAMAGE_YES;
        proj.damageforcescale = WEP_CVAR_PRI(fireball, damageforcescale);
        PROJECTILE_MAKETRIGGER(proj);
        proj.projectiledeathtype = WEP_FIREBALL.m_id;
+       proj.weaponentity_fld = weaponentity;
        setorigin(proj, w_shotorg);
 
        set_movetype(proj, MOVETYPE_FLY);
@@ -173,7 +174,7 @@ void W_Fireball_Attack1(entity actor, .entity weaponentity)
 
 void W_Fireball_AttackEffect(entity actor, .entity weaponentity, float i, vector f_diff)
 {
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 0, SND_Null, 0, 0);
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-16 -16 -16', '16 16 16', false, 0, SND_Null, 0, 0, WEP_FIREBALL.m_id); // TODO: probably doesn't need deathtype, just a prefire effect
        w_shotorg += f_diff.x * v_up + f_diff.y * v_right;
        Send_Effect(EFFECT_FIREBALL_PRE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 }
@@ -270,7 +271,7 @@ void W_Fireball_Attack2(entity actor, .entity weaponentity)
                        f_diff = '+1.25 +3.75 0';
                        break;
        }
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 2, SND_FIREBALL_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(fireball, damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 2, SND_FIREBALL_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(fireball, damage), WEP_FIREBALL.m_id | HITTYPE_SECONDARY);
        traceline(w_shotorg, w_shotorg + f_diff_x * v_up + f_diff_y * v_right, MOVE_NORMAL, actor);
        w_shotorg = trace_endpos;
 
index ff2e74539ce83faf9acb719b3faf4c26cd376bc7..03855e316e7c1c9f4be758095ad057c06fa5c835 100644 (file)
@@ -7,7 +7,7 @@
 void W_Hagar_Explode(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
-       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), NULL, NULL, WEP_CVAR_PRI(hagar, force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(hagar, damage), WEP_CVAR_PRI(hagar, edgedamage), WEP_CVAR_PRI(hagar, radius), NULL, NULL, WEP_CVAR_PRI(hagar, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -20,7 +20,7 @@ void W_Hagar_Explode_use(entity this, entity actor, entity trigger)
 void W_Hagar_Explode2(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
-       RadiusDamage(this, this.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), NULL, NULL, WEP_CVAR_SEC(hagar, force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR_SEC(hagar, damage), WEP_CVAR_SEC(hagar, edgedamage), WEP_CVAR_SEC(hagar, radius), NULL, NULL, WEP_CVAR_SEC(hagar, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -30,9 +30,9 @@ void W_Hagar_Explode2_use(entity this, entity actor, entity trigger)
        W_Hagar_Explode2(this, trigger);
 }
 
-void W_Hagar_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Hagar_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        float is_linkexplode = ( ((inflictor.owner != NULL) ? (inflictor.owner == this.owner) : true)
@@ -47,10 +47,10 @@ void W_Hagar_Damage(entity this, entity inflictor, entity attacker, float damage
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, is_linkexplode))
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, getthink(this));
 }
 
@@ -81,7 +81,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(hagar, ammo), weaponentity);
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hagar, damage));
+       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hagar, damage), WEP_HAGAR.m_id);
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -91,7 +91,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.bot_dodgerating = WEP_CVAR_PRI(hagar, damage);
 
        missile.takedamage = DAMAGE_YES;
-       missile.health = WEP_CVAR_PRI(hagar, health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR_PRI(hagar, health));
        missile.damageforcescale = WEP_CVAR_PRI(hagar, damageforcescale);
        missile.event_damage = W_Hagar_Damage;
        missile.damagedbycontents = true;
@@ -103,6 +103,7 @@ void W_Hagar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        missile.nextthink = time + WEP_CVAR_PRI(hagar, lifetime);
        PROJECTILE_MAKETRIGGER(missile);
        missile.projectiledeathtype = WEP_HAGAR.m_id;
+       missile.weaponentity_fld = weaponentity;
        setorigin(missile, w_shotorg);
        setsize(missile, '0 0 0', '0 0 0');
 
@@ -126,7 +127,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo), weaponentity);
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
+       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage), WEP_HAGAR.m_id | HITTYPE_SECONDARY);
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -136,7 +137,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
 
        missile.takedamage = DAMAGE_YES;
-       missile.health = WEP_CVAR_SEC(hagar, health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR_SEC(hagar, health));
        missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
        missile.event_damage = W_Hagar_Damage;
        missile.damagedbycontents = true;
@@ -149,6 +150,7 @@ void W_Hagar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        missile.nextthink = time + WEP_CVAR_SEC(hagar, lifetime_min) + random() * WEP_CVAR_SEC(hagar, lifetime_rand);
        PROJECTILE_MAKETRIGGER(missile);
        missile.projectiledeathtype = WEP_HAGAR.m_id | HITTYPE_SECONDARY;
+       missile.weaponentity_fld = weaponentity;
        setorigin(missile, w_shotorg);
        setsize(missile, '0 0 0', '0 0 0');
 
@@ -181,14 +183,14 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
 
        weapon_prepareattack_do(actor, weaponentity, true, WEP_CVAR_SEC(hagar, refire));
 
-       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage));
+       shots = actor.(weaponentity).hagar_load;
+       W_SetupShot(actor, weaponentity, false, 2, SND_HAGAR_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hagar, damage) * shots, WEP_HAGAR.m_id | HITTYPE_SECONDARY);
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
        forward = v_forward;
        right = v_right;
        up = v_up;
 
-       shots = actor.(weaponentity).hagar_load;
        missile = NULL;
        for(counter = 0; counter < shots; ++counter)
        {
@@ -198,7 +200,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
                missile.bot_dodgerating = WEP_CVAR_SEC(hagar, damage);
 
                missile.takedamage = DAMAGE_YES;
-               missile.health = WEP_CVAR_SEC(hagar, health);
+               SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR_SEC(hagar, health));
                missile.damageforcescale = WEP_CVAR_SEC(hagar, damageforcescale);
                missile.event_damage = W_Hagar_Damage;
                missile.damagedbycontents = true;
@@ -210,6 +212,7 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
                missile.nextthink = time + WEP_CVAR_SEC(hagar, lifetime_min) + random() * WEP_CVAR_SEC(hagar, lifetime_rand);
                PROJECTILE_MAKETRIGGER(missile);
                missile.projectiledeathtype = WEP_HAGAR.m_id | HITTYPE_SECONDARY;
+               missile.weaponentity_fld = weaponentity;
                setorigin(missile, w_shotorg);
                setsize(missile, '0 0 0', '0 0 0');
                set_movetype(missile, MOVETYPE_FLY);
@@ -247,17 +250,12 @@ void W_Hagar_Attack2_Load_Release(entity actor, .entity weaponentity)
        weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(hagar, load_animtime), w_ready);
        actor.(weaponentity).hagar_loadstep = time + WEP_CVAR_SEC(hagar, refire) * W_WeaponRateFactor(actor);
        actor.(weaponentity).hagar_load = 0;
-
-       if(weaponslot(weaponentity) == 0)
-               actor.hagar_load = 0;
 }
 
 void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
 {
        // loadable hagar secondary attack, must always run each frame
-       if(round_handler_IsActive() && !round_handler_IsRoundStarted())
-               return;
-       if(time < game_starttime)
+       if(time < game_starttime || time < actor.race_penalty || timeout_status == TIMEOUT_ACTIVE)
                return;
 
        bool loaded = actor.(weaponentity).hagar_load >= WEP_CVAR_SEC(hagar, load_max);
@@ -283,8 +281,6 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
                                actor.(weaponentity).state = WS_READY;
                                W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hagar, ammo) * actor.(weaponentity).hagar_load * -1, weaponentity); // give back ammo
                                actor.(weaponentity).hagar_load = 0;
-                               if(weaponslot(weaponentity) == 0)
-                                       actor.hagar_load = 0;
                                sound(actor, CH_WEAPON_A, SND_HAGAR_BEEP, VOL_BASE, ATTN_NORM);
 
                                // pause until we can load rockets again, once we re-press the alt fire button
@@ -365,7 +361,7 @@ void W_Hagar_Attack2_Load(Weapon thiswep, entity actor, .entity weaponentity)
 
 void W_Hagar_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
-       if(!(fire & 1) || actor.(weaponentity).hagar_load || actor.(weaponentity).hagar_loadblock || actor.(weaponentity).m_switchweapon != WEP_HAGAR)
+       if(!(fire & 1) || actor.(weaponentity).hagar_load || actor.(weaponentity).hagar_loadblock || actor.(weaponentity).m_switchweapon != WEP_HAGAR || !weapon_prepareattack_check(thiswep, actor, weaponentity, false, -1))
        {
                w_ready(thiswep, actor, weaponentity, fire);
                return;
@@ -404,8 +400,6 @@ METHOD(Hagar, wr_think, void(entity thiswep, entity actor, .entity weaponentity,
 {
     float loadable_secondary;
     loadable_secondary = (WEP_CVAR_SEC(hagar, load) && WEP_CVAR(hagar, secondary));
-    if(weaponslot(weaponentity) == 0)
-       actor.hagar_load = actor.(weaponentity).hagar_load;
 
     if(loadable_secondary)
         W_Hagar_Attack2_Load(thiswep, actor, weaponentity); // must always run each frame
@@ -437,7 +431,6 @@ METHOD(Hagar, wr_gonethink, void(entity thiswep, entity actor, .entity weaponent
 }
 METHOD(Hagar, wr_setup, void(entity thiswep, entity actor, .entity weaponentity))
 {
-       actor.hagar_load = 0;
     actor.(weaponentity).hagar_loadblock = false;
     if(actor.(weaponentity).hagar_load)
     {
@@ -459,7 +452,6 @@ METHOD(Hagar, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponen
 }
 METHOD(Hagar, wr_resetplayer, void(entity thiswep, entity actor))
 {
-    actor.hagar_load = 0;
     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
     {
        .entity weaponentity = weaponentities[slot];
index ae6c9a66372f4637ec28cfacb5890a82987f0e33..8f501653869caad8908a2723ad435dbfd70ff243 100644 (file)
@@ -12,7 +12,8 @@ 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), NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, toucher);
+       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);
 }
@@ -29,7 +30,7 @@ void W_HLAC_Attack(Weapon thiswep, entity actor, .entity weaponentity)
     if(actor.crouch)
         spread = spread * WEP_CVAR_PRI(hlac, spread_crouchmod);
 
-       W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hlac, damage));
+       W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(hlac, damage), WEP_HLAC.m_id);
        Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
        if(!autocvar_g_norecoil)
        {
@@ -61,6 +62,7 @@ void W_HLAC_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        IL_PUSH(g_projectiles, missile);
        IL_PUSH(g_bot_dodge, missile);
        missile.projectiledeathtype = WEP_HLAC.m_id;
+       missile.weaponentity_fld = weaponentity;
 
        CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
 
@@ -78,7 +80,7 @@ void W_HLAC_Attack2(entity actor, .entity weaponentity)
     if(actor.crouch)
         spread = spread * WEP_CVAR_SEC(hlac, spread_crouchmod);
 
-       W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage));
+       W_SetupShot(actor, weaponentity, false, 3, SND_LASERGUN_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hlac, damage), WEP_HLAC.m_id | HITTYPE_SECONDARY);
        Send_Effect(EFFECT_BLASTER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
        missile = new(hlacbolt);
@@ -106,6 +108,7 @@ void W_HLAC_Attack2(entity actor, .entity weaponentity)
        IL_PUSH(g_bot_dodge, missile);
        missile.missile_flags = MIF_SPLASH;
        missile.projectiledeathtype = WEP_HLAC.m_id | HITTYPE_SECONDARY;
+       missile.weaponentity_fld = weaponentity;
 
        CSQCProjectile(missile, true, PROJECTILE_HLAC, true);
 
index 13b5661fecae03d87bbe6de17346c2b4a5e549f2..e17e97620884e3ed75c1259a43f8da23d603abe2 100644 (file)
@@ -12,7 +12,7 @@ void W_Hook_ExplodeThink(entity this)
        f = this.dmg_last - dmg_remaining_next;
        this.dmg_last = dmg_remaining_next;
 
-       RadiusDamage(this, this.realowner, this.dmg * f, this.dmg_edge * f, this.dmg_radius, this.realowner, NULL, this.dmg_force * f, this.projectiledeathtype, NULL);
+       RadiusDamage(this, this.realowner, this.dmg * f, this.dmg_edge * f, this.dmg_radius, this.realowner, NULL, this.dmg_force * f, this.projectiledeathtype, this.weaponentity_fld, NULL);
        this.projectiledeathtype |= HITTYPE_BOUNCE;
        //RadiusDamage(this, NULL, this.dmg * f, this.dmg_edge * f, this.dmg_radius, NULL, NULL, this.dmg_force * f, this.projectiledeathtype, NULL);
 
@@ -46,17 +46,17 @@ void W_Hook_Explode2_use(entity this, entity actor, entity trigger)
        W_Hook_Explode2(this);
 }
 
-void W_Hook_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Hook_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_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;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, this.realowner, W_Hook_Explode2);
 }
 
@@ -69,7 +69,7 @@ void W_Hook_Touch2(entity this, entity toucher)
 void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
 {
        //W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(hook, ammo)); // WEAPONTODO: Figure out how to handle ammo with hook secondary (gravitybomb)
-       W_SetupShot(actor, weaponentity, false, 4, SND_HOOKBOMB_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hook, damage));
+       W_SetupShot(actor, weaponentity, false, 4, SND_HOOKBOMB_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(hook, damage), WEP_HOOK.m_id | HITTYPE_SECONDARY);
 
        entity gren = new(hookbomb);
        gren.owner = gren.realowner = actor;
@@ -78,6 +78,7 @@ void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        set_movetype(gren, MOVETYPE_TOSS);
        PROJECTILE_MAKETRIGGER(gren);
        gren.projectiledeathtype = WEP_HOOK.m_id | HITTYPE_SECONDARY;
+       gren.weaponentity_fld = weaponentity;
        setorigin(gren, w_shotorg);
        setsize(gren, '0 0 0', '0 0 0');
 
@@ -87,7 +88,7 @@ void W_Hook_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        settouch(gren, W_Hook_Touch2);
 
        gren.takedamage = DAMAGE_YES;
-       gren.health = WEP_CVAR_SEC(hook, health);
+       SetResourceAmountExplicit(gren, RESOURCE_HEALTH, WEP_CVAR_SEC(hook, health));
        gren.damageforcescale = WEP_CVAR_SEC(hook, damageforcescale);
        gren.event_damage = W_Hook_Damage;
        gren.damagedbycontents = true;
@@ -164,7 +165,7 @@ METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity,
             {
                 if(!(actor.items & IT_UNLIMITED_WEAPON_AMMO))
                 {
-                    if( actor.ammo_fuel >= (time - actor.(weaponentity).hook_time_fueldecrease) * hooked_fuel )
+                    if( GetResourceAmount(actor, RESOURCE_FUEL) >= (time - actor.(weaponentity).hook_time_fueldecrease) * hooked_fuel )
                     {
                         W_DecreaseAmmo(thiswep, actor, (time - actor.(weaponentity).hook_time_fueldecrease) * hooked_fuel, weaponentity);
                         actor.(weaponentity).hook_time_fueldecrease = time;
@@ -172,7 +173,7 @@ METHOD(Hook, wr_think, void(entity thiswep, entity actor, .entity weaponentity,
                     }
                     else
                     {
-                        actor.ammo_fuel = 0;
+                        SetResourceAmount(actor, RESOURCE_FUEL, 0);
                         actor.(weaponentity).hook_state |= HOOK_REMOVING;
                         if(actor.(weaponentity).m_weapon != WEP_Null) // offhand
                                W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
@@ -213,9 +214,9 @@ METHOD(Hook, wr_checkammo1, bool(Hook thiswep, entity actor, .entity weaponentit
     if (!thiswep.ammo_factor) return true;
 
     if(actor.(weaponentity).hook)
-       return actor.ammo_fuel > 0;
+       return GetResourceAmount(actor, RESOURCE_FUEL) > 0;
 
-    return actor.ammo_fuel >= WEP_CVAR_PRI(hook, ammo);
+    return GetResourceAmount(actor, RESOURCE_FUEL) >= WEP_CVAR_PRI(hook, ammo);
 }
 METHOD(Hook, wr_checkammo2, bool(Hook thiswep, entity actor, .entity weaponentity))
 {
@@ -260,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;
@@ -280,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;
@@ -465,16 +466,12 @@ NET_HANDLE(ENT_CLIENT_HOOK, bool bIsNew)
        }
        if(sf & 2)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
                setorigin(this, this.origin);
        }
        if(sf & 4)
        {
-               this.velocity_x = ReadCoord();
-               this.velocity_y = ReadCoord();
-               this.velocity_z = ReadCoord();
+               this.velocity = ReadVector();
        }
 
        InterpolateOrigin_Note(this);
index 294d556379205c3f7423a81e39f0cd0d1632aabd..bc51577c9c018661f9fbf6a896605e825e22eb95 100644 (file)
@@ -50,7 +50,7 @@ void W_MachineGun_MuzzleFlash(entity actor, .entity weaponentity)
 
 void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity weaponentity)
 {
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, ((actor.(weaponentity).misc_bulletcounter == 1) ? WEP_CVAR(machinegun, first_damage) : WEP_CVAR(machinegun, sustained_damage)), deathtype);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
@@ -86,7 +86,7 @@ void W_MachineGun_Attack(Weapon thiswep, int deathtype, entity actor, .entity we
 // weapon frames
 void W_MachineGun_Attack_Frame(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
-       if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon) // abort immediately if switching
+       if(actor.(weaponentity).m_weapon != actor.(weaponentity).m_switchweapon || !weapon_prepareattack_check(thiswep, actor, weaponentity, (fire & 2), -1)) // abort immediately if switching
        {
                w_ready(thiswep, actor, weaponentity, fire);
                return;
@@ -113,7 +113,7 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity
 {
        float machinegun_spread;
 
-       if(!(fire & 1))
+       if(!(fire & 1) || !weapon_prepareattack_check(thiswep, actor, weaponentity, false, -1))
        {
                w_ready(thiswep, actor, weaponentity, fire);
                return;
@@ -129,7 +129,7 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity
 
        W_DecreaseAmmo(WEP_MACHINEGUN, actor, WEP_CVAR(machinegun, sustained_ammo), weaponentity);
 
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage), WEP_MACHINEGUN.m_id);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
@@ -159,7 +159,7 @@ void W_MachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity
 
 void W_MachineGun_Attack_Burst(Weapon thiswep, entity actor, .entity weaponentity, int fire)
 {
-       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage));
+       W_SetupShot(actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(machinegun, sustained_damage), WEP_MACHINEGUN.m_id);
        if(!autocvar_g_norecoil)
        {
                actor.punchangle_x = random() - 0.5;
index 575b76d72e12f4fbf9000331b3ed56a32cafd338..6d3270a2b22788e6539f82115f93d72a2ef8b18c 100644 (file)
@@ -27,7 +27,7 @@ void W_MineLayer_Stick(entity this, entity to)
 
        newmine.takedamage = this.takedamage;
        newmine.damageforcescale = this.damageforcescale;
-       newmine.health = this.health;
+       SetResourceAmountExplicit(newmine, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
        newmine.event_damage = this.event_damage;
        newmine.spawnshieldtime = this.spawnshieldtime;
        newmine.damagedbycontents = true;
@@ -64,7 +64,7 @@ void W_MineLayer_Explode(entity this, entity directhitentity)
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
 
-       RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), NULL, NULL, WEP_CVAR(minelayer, force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, damage), WEP_CVAR(minelayer, edgedamage), WEP_CVAR(minelayer, radius), NULL, NULL, WEP_CVAR(minelayer, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        .entity weaponentity = this.weaponentity_fld;
        if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER)
@@ -96,7 +96,8 @@ 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), NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, NULL);
+       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;
        if(this.realowner.(weaponentity).m_weapon == WEP_MINE_LAYER)
@@ -246,9 +247,9 @@ void W_MineLayer_Touch(entity this, entity toucher)
        }
 }
 
-void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        float is_from_enemy = (inflictor.realowner != this.realowner);
@@ -256,10 +257,10 @@ void W_MineLayer_Damage(entity this, entity inflictor, entity attacker, float da
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, (is_from_enemy ? 1 : -1)))
                return; // g_projectiles_damage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
        this.angles = vectoangles(this.velocity);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, W_MineLayer_Explode_think);
 }
 
@@ -282,7 +283,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(minelayer, ammo), weaponentity);
 
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(minelayer, damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-4 -4 -4', '4 4 4', false, 5, SND_MINE_FIRE, CH_WEAPON_A, WEP_CVAR(minelayer, damage), WEP_MINE_LAYER.m_id);
        Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
        mine = WarpZone_RefSys_SpawnSameRefSys(actor);
@@ -299,7 +300,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        mine.takedamage = DAMAGE_YES;
        mine.damageforcescale = WEP_CVAR(minelayer, damageforcescale);
-       mine.health = WEP_CVAR(minelayer, health);
+       SetResourceAmountExplicit(mine, RESOURCE_HEALTH, WEP_CVAR(minelayer, health));
        mine.event_damage = W_MineLayer_Damage;
        mine.damagedbycontents = true;
        IL_PUSH(g_damagedbycontents, mine);
@@ -307,6 +308,7 @@ void W_MineLayer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        set_movetype(mine, MOVETYPE_TOSS);
        PROJECTILE_MAKETRIGGER(mine);
        mine.projectiledeathtype = WEP_MINE_LAYER.m_id;
+       mine.weaponentity_fld = weaponentity;
        setsize(mine, '-4 -4 -4', '4 4 4'); // give it some size so it can be shot
 
        setorigin(mine, w_shotorg - v_forward * 4); // move it back so it hits the wall at the right point
@@ -437,7 +439,7 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentit
         // but don't fire a new shot at the same time!
         if(desirabledamage >= 0.75 * coredamage) //this should do group damage in rare fortunate events
             PHYS_INPUT_BUTTON_ATCK2(actor) = true;
-        if((skill > 6.5) && (selfdamage > actor.health))
+        if((skill > 6.5) && (selfdamage > GetResourceAmount(actor, RESOURCE_HEALTH)))
             PHYS_INPUT_BUTTON_ATCK2(actor) = false;
         //if(PHYS_INPUT_BUTTON_ATCK2(actor) == true)
         //     dprint(ftos(desirabledamage),"\n");
@@ -446,9 +448,6 @@ METHOD(MineLayer, wr_aim, void(entity thiswep, entity actor, .entity weaponentit
 }
 METHOD(MineLayer, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
 {
-       if(weaponslot(weaponentity) == 0)
-               actor.minelayer_mines = actor.(weaponentity).minelayer_mines;
-
     if(autocvar_g_balance_minelayer_reload_ammo && actor.(weaponentity).clip_load < WEP_CVAR(minelayer, ammo)) // forced reload
     {
         // not if we're holding the minelayer without enough ammo, but can detonate existing mines
@@ -492,7 +491,6 @@ METHOD(MineLayer, wr_checkammo2, bool(entity thiswep, entity actor, .entity weap
 }
 METHOD(MineLayer, wr_resetplayer, void(entity thiswep, entity actor))
 {
-    actor.minelayer_mines = 0;
     for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
     {
        .entity weaponentity = weaponentities[slot];
index 6ada37cd675fd92db33ab02e849df8fcc364968a..51267e50d4f80ad7d2d1de58b156328a2bd967ca 100644 (file)
@@ -17,7 +17,7 @@ void W_Mortar_Grenade_Explode(entity this, entity directhitentity)
        if(this.move_movetype == MOVETYPE_NONE)
                this.velocity = this.oldvelocity;
 
-       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), NULL, NULL, WEP_CVAR_PRI(mortar, force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR_PRI(mortar, damage), WEP_CVAR_PRI(mortar, edgedamage), WEP_CVAR_PRI(mortar, radius), NULL, NULL, WEP_CVAR_PRI(mortar, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -42,7 +42,7 @@ void W_Mortar_Grenade_Explode2(entity this, entity directhitentity)
        if(this.move_movetype == MOVETYPE_NONE)
                this.velocity = this.oldvelocity;
 
-       RadiusDamage(this, this.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), NULL, NULL, WEP_CVAR_SEC(mortar, force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR_SEC(mortar, damage), WEP_CVAR_SEC(mortar, edgedamage), WEP_CVAR_SEC(mortar, radius), NULL, NULL, WEP_CVAR_SEC(mortar, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -52,17 +52,17 @@ void W_Mortar_Grenade_Explode2_use(entity this, entity actor, entity trigger)
        W_Mortar_Grenade_Explode2(this, trigger);
 }
 
-void W_Mortar_Grenade_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Mortar_Grenade_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_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;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, adaptor_think2use);
 }
 
@@ -151,7 +151,7 @@ void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 {
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(mortar, ammo), weaponentity);
 
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(mortar, damage), WEP_MORTAR.m_id);
        w_shotdir = v_forward; // no TrueAim for grenades please
 
        Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
@@ -165,6 +165,7 @@ void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        gren.bouncestop = WEP_CVAR(mortar, bouncestop);
        PROJECTILE_MAKETRIGGER(gren);
        gren.projectiledeathtype = WEP_MORTAR.m_id;
+       gren.weaponentity_fld = weaponentity;
        setorigin(gren, w_shotorg);
        setsize(gren, '-3 -3 -3', '3 3 3');
 
@@ -175,7 +176,7 @@ void W_Mortar_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        settouch(gren, W_Mortar_Grenade_Touch1);
 
        gren.takedamage = DAMAGE_YES;
-       gren.health = WEP_CVAR_PRI(mortar, health);
+       SetResourceAmountExplicit(gren, RESOURCE_HEALTH, WEP_CVAR_PRI(mortar, health));
        gren.damageforcescale = WEP_CVAR_PRI(mortar, damageforcescale);
        gren.event_damage = W_Mortar_Grenade_Damage;
        gren.damagedbycontents = true;
@@ -202,7 +203,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
 
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(mortar, ammo), weaponentity);
 
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 4, SND_GRENADE_FIRE, CH_WEAPON_A, WEP_CVAR_SEC(mortar, damage), WEP_MORTAR.m_id | HITTYPE_SECONDARY);
        w_shotdir = v_forward; // no TrueAim for grenades please
 
        Send_Effect(EFFECT_GRENADE_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
@@ -216,6 +217,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        gren.bouncestop = WEP_CVAR(mortar, bouncestop);
        PROJECTILE_MAKETRIGGER(gren);
        gren.projectiledeathtype = WEP_MORTAR.m_id | HITTYPE_SECONDARY;
+       gren.weaponentity_fld = weaponentity;
        setorigin(gren, w_shotorg);
        setsize(gren, '-3 -3 -3', '3 3 3');
 
@@ -225,7 +227,7 @@ void W_Mortar_Attack2(Weapon thiswep, entity actor, .entity weaponentity)
        settouch(gren, W_Mortar_Grenade_Touch2);
 
        gren.takedamage = DAMAGE_YES;
-       gren.health = WEP_CVAR_SEC(mortar, health);
+       SetResourceAmountExplicit(gren, RESOURCE_HEALTH, WEP_CVAR_SEC(mortar, health));
        gren.damageforcescale = WEP_CVAR_SEC(mortar, damageforcescale);
        gren.event_damage = W_Mortar_Grenade_Damage;
        gren.damagedbycontents = true;
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 a134c03ab5cce4368ca971fce13701a3ed1de8d8..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);
@@ -202,7 +202,7 @@ void W_Porto_Attack(entity actor, .entity weaponentity, float type)
 {
        entity gren;
 
-       W_SetupShot(actor, weaponentity, false, 4, SND_PORTO_FIRE, CH_WEAPON_A, 0);
+       W_SetupShot(actor, weaponentity, false, 4, SND_PORTO_FIRE, CH_WEAPON_A, 0, WEP_PORTO.m_id); // TODO: does the deathtype even need to be set here? porto can't hurt people
        // always shoot from the eye
        w_shotdir = v_forward;
        w_shotorg = actor.origin + actor.view_ofs + ((w_shotorg - actor.origin - actor.view_ofs) * v_forward) * v_forward;
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 f713200eee5cb0343bd9c311f6dcae79082109be..b96fa35831c0095baf37399663968e4e75e7597f 100644 (file)
@@ -8,7 +8,7 @@ void W_Rifle_FireBullet(Weapon thiswep, .entity weaponentity, float pSpread, flo
 
        W_DecreaseAmmo(thiswep, actor, pAmmo, weaponentity);
 
-       W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots);
+       W_SetupShot(actor, weaponentity, true, 2, pSound, CH_WEAPON_A, pDamage * pShots, deathtype);
 
        Send_Effect(EFFECT_RIFLE_MUZZLEFLASH, w_shotorg, w_shotdir * 2000, 1);
 
@@ -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))
 {
@@ -223,5 +227,9 @@ METHOD(Rifle, wr_zoom, bool(entity thiswep, entity actor))
         return false;
     }
 }
+METHOD(Rifle, wr_zoomdir, bool(entity thiswep))
+{
+    return button_attack2 && !WEP_CVAR(rifle, secondary);
+}
 
 #endif
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 5e3faeeab94a347424dda81601187a329f229f53..10080bbad275bd71b067ffcefcfd333b03998894 100644 (file)
@@ -8,7 +8,7 @@
 void W_Seeker_Missile_Explode(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
-       RadiusDamage(this, this.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), NULL, NULL, WEP_CVAR(seeker, missile_force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR(seeker, missile_damage), WEP_CVAR(seeker, missile_edgedamage), WEP_CVAR(seeker, missile_radius), NULL, NULL, WEP_CVAR(seeker, missile_force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -122,20 +122,20 @@ void W_Seeker_Missile_Think(entity this)
 
 
 
-void W_Seeker_Missile_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Seeker_Missile_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if(!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
                return; // g_projectiles_damage says to halt
 
        if(this.realowner == attacker)
-               this.health = this.health - (damage * 0.25);
+               TakeResource(this, RESOURCE_HEALTH, (damage * 0.25));
        else
-               this.health = this.health - damage;
+               TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_PrepareExplosionByDamage(this, attacker, W_Seeker_Missile_Explode_think);
 }
 
@@ -169,7 +169,7 @@ void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, v
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, missile_ammo), weaponentity);
 
        makevectors(actor.v_angle);
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_SEEKER_FIRE, CH_WEAPON_A, 0);
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_SEEKER_FIRE, CH_WEAPON_A, 0, ((m_target != NULL) ? WEP_SEEKER.m_id | HITTYPE_SECONDARY : WEP_SEEKER.m_id));
        w_shotorg += f_diff;
        Send_Effect(EFFECT_SEEKER_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -189,7 +189,8 @@ void W_Seeker_Fire_Missile(Weapon thiswep, entity actor, .entity weaponentity, v
        missile.solid           = SOLID_BBOX;
        missile.scale           = 2;
        missile.takedamage      = DAMAGE_YES;
-       missile.health          = WEP_CVAR(seeker, missile_health);
+       missile.weaponentity_fld = weaponentity;
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(seeker, missile_health));
        missile.damageforcescale = WEP_CVAR(seeker, missile_damageforcescale);
        missile.damagedbycontents = true;
        IL_PUSH(g_damagedbycontents, missile);
@@ -225,7 +226,7 @@ void W_Seeker_Flac_Explode(entity this, entity directhitentity)
 {
        this.event_damage = func_null;
 
-       RadiusDamage(this, this.realowner, WEP_CVAR(seeker, flac_damage), WEP_CVAR(seeker, flac_edgedamage), WEP_CVAR(seeker, flac_radius), NULL, NULL, WEP_CVAR(seeker, flac_force), this.projectiledeathtype, directhitentity);
+       RadiusDamage(this, this.realowner, WEP_CVAR(seeker, flac_damage), WEP_CVAR(seeker, flac_edgedamage), WEP_CVAR(seeker, flac_radius), NULL, NULL, WEP_CVAR(seeker, flac_force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
 
        delete(this);
 }
@@ -265,7 +266,7 @@ void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity)
                        f_diff = '+1.25 +3.75 0';
                        break;
        }
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_FLAC_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, flac_damage));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_FLAC_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, flac_damage), WEP_SEEKER.m_id | HITTYPE_SECONDARY);
        w_shotorg += f_diff;
 
        Send_Effect(EFFECT_HAGAR_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
@@ -280,8 +281,8 @@ void W_Seeker_Fire_Flac(Weapon thiswep, entity actor, .entity weaponentity)
        missile.nextthink               = time + WEP_CVAR(seeker, flac_lifetime) + WEP_CVAR(seeker, flac_lifetime_rand);
        missile.solid                   = SOLID_BBOX;
        set_movetype(missile, MOVETYPE_FLY);
-       missile.projectiledeathtype = WEP_SEEKER.m_id;
        missile.projectiledeathtype = WEP_SEEKER.m_id | HITTYPE_SECONDARY;
+       missile.weaponentity_fld = weaponentity;
        missile.flags = FL_PROJECTILE;
        IL_PUSH(g_projectiles, missile);
        IL_PUSH(g_bot_dodge, missile);
@@ -412,12 +413,12 @@ void W_Seeker_Tag_Explode(entity this)
        delete(this);
 }
 
-void W_Seeker_Tag_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void W_Seeker_Tag_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
-       this.health = this.health - damage;
-       if(this.health <= 0)
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                W_Seeker_Tag_Explode(this);
 }
 
@@ -490,7 +491,7 @@ void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity)
 {
        W_DecreaseAmmo(thiswep, actor, WEP_CVAR(seeker, tag_ammo), weaponentity);
 
-       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_TAG_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count));
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-2 -2 -2', '2 2 2', false, 2, SND_TAG_FIRE, CH_WEAPON_A, WEP_CVAR(seeker, missile_damage) * WEP_CVAR(seeker, missile_count), WEP_SEEKER.m_id | HITTYPE_BOUNCE | HITTYPE_SECONDARY);
 
        entity missile          = new(seeker_tag);
        missile.weaponentity_fld = weaponentity;
@@ -505,7 +506,7 @@ void W_Seeker_Fire_Tag(Weapon thiswep, entity actor, .entity weaponentity)
 
        missile.takedamage       = DAMAGE_YES;
        missile.event_damage     = W_Seeker_Tag_Damage;
-       missile.health           = WEP_CVAR(seeker, tag_health);
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, WEP_CVAR(seeker, tag_health));
        missile.damageforcescale = WEP_CVAR(seeker, tag_damageforcescale);
 
        setorigin(missile, w_shotorg);
index 0ca4d528fe62ea550776a9d6ee1c9ad56dc6a526..e9d55b24232353c0a5f086f5b40373f60b17f0c3 100644 (file)
@@ -99,6 +99,7 @@ void W_Shockwave_Melee_Think(entity this)
                                this.realowner,
                                swing_damage,
                                (WEP_SHOCKWAVE.m_id | HITTYPE_SECONDARY),
+                               this.weaponentity_fld,
                                (this.realowner.origin + this.realowner.view_ofs),
                                (v_forward * WEP_CVAR(shockwave, melee_force))
                        );
@@ -155,7 +156,8 @@ void W_Shockwave_Melee(Weapon thiswep, entity actor, .entity weaponentity, int f
        meleetemp.owner = meleetemp.realowner = actor;
        setthink(meleetemp, W_Shockwave_Melee_Think);
        meleetemp.nextthink = time + WEP_CVAR(shockwave, melee_delay) * W_WeaponRateFactor(actor);
-       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR(shockwave, melee_damage), WEP_CVAR(shockwave, melee_range));
+       meleetemp.weaponentity_fld = weaponentity;
+       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR(shockwave, melee_damage), WEP_CVAR(shockwave, melee_range), WEP_SHOCKWAVE.m_id | HITTYPE_SECONDARY);
 }
 
 // SHOCKWAVE ATTACK MODE
@@ -255,12 +257,8 @@ float W_Shockwave_Attack_CheckHit(
 void W_Shockwave_Send(entity actor)
 {
        WriteHeader(MSG_BROADCAST, TE_CSQC_SHOCKWAVEPARTICLE);
-       WriteCoord(MSG_BROADCAST, w_shotorg.x);
-       WriteCoord(MSG_BROADCAST, w_shotorg.y);
-       WriteCoord(MSG_BROADCAST, w_shotorg.z);
-       WriteCoord(MSG_BROADCAST, w_shotdir.x);
-       WriteCoord(MSG_BROADCAST, w_shotdir.y);
-       WriteCoord(MSG_BROADCAST, w_shotdir.z);
+       WriteVector(MSG_BROADCAST, w_shotorg);
+       WriteVector(MSG_BROADCAST, w_shotdir);
        WriteShort(MSG_BROADCAST, WEP_CVAR(shockwave, blast_distance));
        WriteByte(MSG_BROADCAST, bound(0, WEP_CVAR(shockwave, blast_spread_max), 255));
        WriteByte(MSG_BROADCAST, bound(0, WEP_CVAR(shockwave, blast_spread_min), 255));
@@ -278,7 +276,7 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity)
        float i, queue = 0;
 
        // set up the shot direction
-       W_SetupShot(actor, weaponentity, true, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage));
+       W_SetupShot(actor, weaponentity, true, 3, SND_LASERGUN_FIRE, CH_WEAPON_B, WEP_CVAR(shockwave, blast_damage), WEP_SHOCKWAVE.m_id);
        vector attack_endpos = (w_shotorg + (w_shotdir * WEP_CVAR(shockwave, blast_distance)));
        WarpZone_TraceLine(w_shotorg, attack_endpos, MOVE_NOMONSTERS, actor);
        vector attack_hitpos = trace_endpos;
@@ -384,6 +382,7 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity)
                                        actor,
                                        final_damage,
                                        WEP_SHOCKWAVE.m_id,
+                                       weaponentity,
                                        head.origin,
                                        final_force
                                );
@@ -568,6 +567,7 @@ void W_Shockwave_Attack(entity actor, .entity weaponentity)
                        actor,
                        final_damage,
                        WEP_SHOCKWAVE.m_id,
+                       weaponentity,
                        head.origin,
                        final_force
                );
@@ -762,8 +762,8 @@ void Net_ReadShockwaveParticle()
        shockwave.draw = Draw_Shockwave;
        IL_PUSH(g_drawables, shockwave);
 
-       shockwave.sw_shotorg_x = ReadCoord(); shockwave.sw_shotorg_y = ReadCoord(); shockwave.sw_shotorg_z = ReadCoord();
-       shockwave.sw_shotdir_x = ReadCoord(); shockwave.sw_shotdir_y = ReadCoord(); shockwave.sw_shotdir_z = ReadCoord();
+       shockwave.sw_shotorg = ReadVector();
+       shockwave.sw_shotdir = ReadVector();
 
        shockwave.sw_distance = ReadShort();
        shockwave.sw_spread_max = ReadByte();
index 5429b35417a7f2afb4b20bb57cecb65f6e4e6c97..fe465e52848bf34d739c8a650bdda87436c8c8a1 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));
-       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, EFFECT_RIFLE_WEAK);
+       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, EFFECT_RIFLE_WEAK);
 
-       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)
@@ -68,7 +69,7 @@ void W_Shotgun_Melee_Think(entity this)
                        + (v_up * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_up))
                        + (v_right * swing_factor * WEP_CVAR_SEC(shotgun, melee_swing_side)));
 
-               WarpZone_traceline_antilag(this, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
+               WarpZone_traceline_antilag(this.realowner, this.realowner.origin + this.realowner.view_ofs, targpos, false, this.realowner, ((IS_CLIENT(this.realowner)) ? ANTILAG_LATENCY(this.realowner) : 0));
 
                // draw lightning beams for debugging
                //te_lightning2(NULL, targpos, this.realowner.origin + this.realowner.view_ofs + v_forward * 5 - v_up * 5);
@@ -77,7 +78,7 @@ void W_Shotgun_Melee_Think(entity this)
                is_player = (IS_PLAYER(trace_ent) || trace_ent.classname == "body" || IS_MONSTER(trace_ent));
 
                if((trace_fraction < 1) // if trace is good, apply the damage and remove this
-                       && (trace_ent.takedamage == DAMAGE_AIM)
+                       && (trace_ent.takedamage != DAMAGE_NO)
                        && (trace_ent != this.swing_alreadyhit)
                        && (is_player || WEP_CVAR_SEC(shotgun, melee_nonplayerdamage)))
                {
@@ -91,7 +92,7 @@ void W_Shotgun_Melee_Think(entity this)
                        //print(strcat(this.realowner.netname, " hitting ", target_victim.netname, " with ", strcat(ftos(swing_damage), " damage (factor: ", ftos(swing_factor), ") at "), ftos(time), " seconds.\n"));
 
                        Damage(target_victim, this.realowner, this.realowner,
-                               swing_damage, WEP_SHOTGUN.m_id | HITTYPE_SECONDARY,
+                               swing_damage, WEP_SHOTGUN.m_id | HITTYPE_SECONDARY, this.weaponentity_fld,
                                this.realowner.origin + this.realowner.view_ofs,
                                v_forward * WEP_CVAR_SEC(shotgun, force));
 
@@ -136,7 +137,8 @@ void W_Shotgun_Attack2(Weapon thiswep, entity actor, .entity weaponentity, int f
        meleetemp.realowner = actor;
        setthink(meleetemp, W_Shotgun_Melee_Think);
        meleetemp.nextthink = time + WEP_CVAR_SEC(shotgun, melee_delay) * W_WeaponRateFactor(actor);
-       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range));
+       meleetemp.weaponentity_fld = weaponentity;
+       W_SetupShot_Range(actor, weaponentity, true, 0, SND_Null, 0, WEP_CVAR_SEC(shotgun, damage), WEP_CVAR_SEC(shotgun, melee_range), WEP_SHOTGUN.m_id | HITTYPE_SECONDARY);
 }
 
 // alternate secondary weapon frames
@@ -151,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)
@@ -164,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);
 }
 
@@ -177,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
@@ -194,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);
                 }
@@ -206,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 37c36964a2299655452f9cffb2e9397181aaaabe..eb780808932fcd471d96d4727f6aa9cf6aae87a0 100644 (file)
@@ -223,9 +223,7 @@ bool W_Tuba_NoteSendEntity(entity this, entity to, int sf)
        }
        if (sf & 2)
        {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
+               WriteVector(MSG_ENTITY, this.origin);
        }
        return true;
 }
@@ -268,11 +266,7 @@ void W_Tuba_NoteThink(entity this)
 void W_Tuba_NoteOn(entity actor, .entity weaponentity, float hittype)
 {
        vector o;
-       float n;
-
-       W_SetupShot(actor, weaponentity, false, 2, SND_Null, 0, WEP_CVAR(tuba, damage));
-
-       n = W_Tuba_GetNote(actor, hittype);
+       float n = W_Tuba_GetNote(actor, hittype);
 
        hittype = 0;
        if(actor.(weaponentity).tuba_instrument & 1)
@@ -280,6 +274,8 @@ void W_Tuba_NoteOn(entity actor, .entity weaponentity, float hittype)
        if(actor.(weaponentity).tuba_instrument & 2)
                hittype |= HITTYPE_BOUNCE;
 
+       W_SetupShot(actor, weaponentity, false, 2, SND_Null, 0, WEP_CVAR(tuba, damage), hittype | WEP_TUBA.m_id);
+
        if(actor.(weaponentity).tuba_note)
        {
                if(actor.(weaponentity).tuba_note.cnt != n || actor.(weaponentity).tuba_note.tuba_instrument != actor.(weaponentity).tuba_instrument)
@@ -305,7 +301,7 @@ void W_Tuba_NoteOn(entity actor, .entity weaponentity, float hittype)
        actor.(weaponentity).tuba_note.teleport_time = time + WEP_CVAR(tuba, refire) * 2 * W_WeaponRateFactor(actor); // so it can get prolonged safely
 
        //sound(actor, c, TUBA_NOTE(n), bound(0, VOL_BASE * cvar("g_balance_tuba_volume"), 1), autocvar_g_balance_tuba_attenuation);
-       RadiusDamage(actor, actor, WEP_CVAR(tuba, damage), WEP_CVAR(tuba, edgedamage), WEP_CVAR(tuba, radius), NULL, NULL, WEP_CVAR(tuba, force), hittype | WEP_TUBA.m_id, NULL);
+       RadiusDamage(actor, actor, WEP_CVAR(tuba, damage), WEP_CVAR(tuba, edgedamage), WEP_CVAR(tuba, radius), NULL, NULL, WEP_CVAR(tuba, force), hittype | WEP_TUBA.m_id, weaponentity, NULL);
 
        o = gettaginfo(actor.exteriorweaponentity, 0);
        if(time > actor.(weaponentity).tuba_smoketime)
@@ -378,7 +374,12 @@ METHOD(Tuba, wr_reload, void(Tuba this, entity actor, .entity weaponentity))
                                actor.(weaponentity).weaponname = "tuba";
                                break;
                }
-               W_SetupShot(actor, weaponentity, false, 0, SND_Null, 0, 0);
+               int hittype = 0;
+               if(actor.(weaponentity).tuba_instrument & 1)
+                       hittype |= HITTYPE_SECONDARY;
+               if(actor.(weaponentity).tuba_instrument & 2)
+                       hittype |= HITTYPE_BOUNCE;
+               W_SetupShot(actor, weaponentity, false, 0, SND_Null, 0, 0, hittype | WEP_TUBA.m_id);
                Send_Effect(EFFECT_TELEPORT, w_shotorg, '0 0 0', 1);
                actor.(weaponentity).state = WS_INUSE;
                weapon_thinkf(actor, weaponentity, WFRAME_RELOAD, 0.5, w_ready);
@@ -550,9 +551,7 @@ NET_HANDLE(ENT_CLIENT_TUBANOTE, bool isNew)
        }
 
        if (f & 2) {
-               this.enemy.origin_x = ReadCoord();
-               this.enemy.origin_y = ReadCoord();
-               this.enemy.origin_z = ReadCoord();
+               this.enemy.origin = ReadVector();
                setorigin(this.enemy, this.enemy.origin);
                if (this.enemy.enemy) {
                        setorigin(this.enemy.enemy, this.enemy.origin);
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 4a9475a9ccebc212ebfc9ff36016c546865a1aef..2dd5cae1552e6434c95a6eddd0cdbfa9cb2cd226 100644 (file)
@@ -7,12 +7,8 @@ void SendCSQCVaporizerBeamParticle(entity player, int hit) {
        vector v;
        v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
        WriteHeader(MSG_BROADCAST, TE_CSQC_VAPORBEAMPARTICLE);
-       WriteCoord(MSG_BROADCAST, w_shotorg.x);
-       WriteCoord(MSG_BROADCAST, w_shotorg.y);
-       WriteCoord(MSG_BROADCAST, w_shotorg.z);
-       WriteCoord(MSG_BROADCAST, v.x);
-       WriteCoord(MSG_BROADCAST, v.y);
-       WriteCoord(MSG_BROADCAST, v.z);
+       WriteVector(MSG_BROADCAST, w_shotorg);
+       WriteVector(MSG_BROADCAST, v);
        WriteByte(MSG_BROADCAST, hit);
        WriteByte(MSG_BROADCAST, etof(player));
        WriteByte(MSG_BROADCAST, player.team);
@@ -82,8 +78,8 @@ NET_HANDLE(TE_CSQC_VAPORBEAMPARTICLE, bool isNew)
        if (isNew) IL_PUSH(g_drawables, this);
        this.drawmask = MASK_NORMAL;
 
-       this.vorg1_x = ReadCoord(); this.vorg1_y = ReadCoord(); this.vorg1_z = ReadCoord();
-       this.vorg2_x = ReadCoord(); this.vorg2_y = ReadCoord(); this.vorg2_z = ReadCoord();
+       this.vorg1 = ReadVector();
+       this.vorg2 = ReadVector();
        this.cnt = ReadByte();
        int myowner = ReadByte();
        this.owner = playerslots[myowner - 1];
@@ -106,14 +102,14 @@ NET_HANDLE(TE_CSQC_VAPORBEAMPARTICLE, bool isNew)
 
 #ifdef SVQC
 
-void W_RocketMinsta_Explosion(entity actor, vector loc)
+void W_RocketMinsta_Explosion(entity actor, .entity weaponentity, vector loc)
 {
        if(accuracy_canbegooddamage(actor))
                accuracy_add(actor, WEP_DEVASTATOR.m_id, autocvar_g_rm_damage, 0);
        entity dmgent = spawn();
        dmgent.owner = dmgent.realowner = actor;
        setorigin(dmgent, loc);
-       RadiusDamage (dmgent, actor, autocvar_g_rm_damage, autocvar_g_rm_edgedamage, autocvar_g_rm_radius, NULL, NULL, autocvar_g_rm_force, WEP_DEVASTATOR.m_id | HITTYPE_SPLASH, NULL);
+       RadiusDamage (dmgent, actor, autocvar_g_rm_damage, autocvar_g_rm_edgedamage, autocvar_g_rm_radius, NULL, NULL, autocvar_g_rm_force, WEP_DEVASTATOR.m_id | HITTYPE_SPLASH, weaponentity, NULL);
        delete(dmgent);
 }
 
@@ -122,14 +118,14 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
        bool flying = IsFlying(actor); // do this BEFORE to make the trace values from FireRailgunBullet last
        float vaporizer_damage = ((WEP_CVAR_PRI(vaporizer, damage) > 0) ? WEP_CVAR_PRI(vaporizer, damage) : 10000);
 
-       W_SetupShot(actor, weaponentity, true, 0, SND_Null, CH_WEAPON_A, vaporizer_damage);
+       W_SetupShot(actor, weaponentity, true, 0, SND_Null, CH_WEAPON_A, vaporizer_damage, WEP_VAPORIZER.m_id);
        // handle sound separately so we can change the volume
        // added bonus: no longer plays the strength sound (strength gives no bonus to instakill anyway)
        sound (actor, CH_WEAPON_A, SND_MINSTANEXFIRE, VOL_BASE * 0.8, ATTEN_NORM);
 
        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);
@@ -146,9 +142,9 @@ void W_Vaporizer_Attack(Weapon thiswep, entity actor, .entity weaponentity)
 
        if(autocvar_g_rm)
        if(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
-               W_RocketMinsta_Explosion(actor, trace_endpos);
+               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)
@@ -162,7 +158,7 @@ void W_RocketMinsta_Laser_Explode (entity this, entity directhitentity)
 
        this.event_damage = func_null;
        this.takedamage = DAMAGE_NO;
-       RadiusDamage (this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, directhitentity);
+       RadiusDamage (this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, this.weaponentity_fld, directhitentity);
        delete(this);
 }
 
@@ -175,7 +171,7 @@ void W_RocketMinsta_Laser_Touch(entity this, entity toucher)
 {
        PROJECTILE_TOUCH(this, toucher);
        //W_RocketMinsta_Laser_Explode ();
-       RadiusDamage(this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, toucher);
+       RadiusDamage(this, this.realowner, this.rm_damage, this.rm_edmg, autocvar_g_rm_laser_radius, NULL, NULL, this.rm_force, this.projectiledeathtype, this.weaponentity_fld, toucher);
        delete(this);
 }
 
@@ -189,10 +185,7 @@ void W_RocketMinsta_Attack2(entity actor, .entity weaponentity)
        float spread = autocvar_g_rm_laser_spread;
        float rndspread = autocvar_g_rm_laser_spread_random;
 
-       Weapon w = actor.(weaponentity).m_weapon;
-       actor.(weaponentity).m_weapon = WEP_ELECTRO;
-       W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, autocvar_g_rm_laser_damage);
-       actor.(weaponentity).m_weapon = w;
+       W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_CRYLINK_FIRE, CH_WEAPON_A, autocvar_g_rm_laser_damage, WEP_ELECTRO.m_id);
 
        Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -207,6 +200,7 @@ void W_RocketMinsta_Attack2(entity actor, .entity weaponentity)
         proj.nextthink = time + autocvar_g_rm_laser_lifetime;
         PROJECTILE_MAKETRIGGER(proj);
         proj.projectiledeathtype = WEP_ELECTRO.m_id;
+        proj.weaponentity_fld = weaponentity;
         setorigin(proj, w_shotorg);
 
                proj.rm_force = autocvar_g_rm_laser_force / total;
@@ -243,10 +237,7 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity)
        float counter = 0;
        float total = 1;
 
-       Weapon w = actor.(weaponentity).m_weapon;
-       actor.(weaponentity).m_weapon = WEP_ELECTRO;
-       W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, autocvar_g_rm_laser_damage);
-       actor.(weaponentity).m_weapon = w;
+       W_SetupShot_ProjectileSize (actor, weaponentity, '0 0 -3', '0 0 -3', false, 2, SND_ELECTRO_FIRE2, CH_WEAPON_A, autocvar_g_rm_laser_damage, WEP_ELECTRO.m_id);
 
        Send_Effect(EFFECT_ELECTRO_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
 
@@ -261,6 +252,7 @@ void W_RocketMinsta_Attack3 (entity actor, .entity weaponentity)
         proj.nextthink = time + autocvar_g_rm_laser_lifetime;
         PROJECTILE_MAKETRIGGER(proj);
         proj.projectiledeathtype = WEP_ELECTRO.m_id;
+        proj.weaponentity_fld = weaponentity;
         setorigin(proj, w_shotorg);
 
                proj.rm_force = autocvar_g_rm_laser_force / total;
@@ -296,14 +288,14 @@ 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);
     } else if(WEP_CVAR(vaporizer, reload_ammo) && actor.(weaponentity).clip_load < vaporizer_ammo) { // forced reload
         thiswep.wr_reload(thiswep, actor, weaponentity);
     }
-    if((fire & 1) && (actor.ammo_cells || !autocvar_g_rm) && !forbidWeaponUse(actor))
+    if((fire & 1) && (GetResourceAmount(actor, RESOURCE_CELLS) || !autocvar_g_rm) && !forbidWeaponUse(actor))
     {
         if(weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(vaporizer, refire)))
         {
@@ -311,7 +303,7 @@ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponent
             weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(vaporizer, animtime), w_ready);
         }
     }
-    if((fire & 2) || ((fire & 1) && !actor.ammo_cells && autocvar_g_rm))
+    if((fire & 2) || ((fire & 1) && !GetResourceAmount(actor, RESOURCE_CELLS) && autocvar_g_rm))
     {
         if((autocvar_g_rm && autocvar_g_rm_laser) || autocvar_g_rm_laser == 2)
         {
@@ -342,25 +334,7 @@ METHOD(Vaporizer, wr_think, void(entity thiswep, entity actor, .entity weaponent
             if(WEP_CVAR_SEC(vaporizer, ammo))
                 W_DecreaseAmmo(thiswep, actor, WEP_CVAR_SEC(vaporizer, ammo), weaponentity);
 
-            // ugly instagib hack to reuse the fire mode of the laser
-            makevectors(actor.v_angle);
-            Weapon oldwep = actor.(weaponentity).m_weapon; // we can't avoid this hack
-            actor.(weaponentity).m_weapon = WEP_BLASTER;
-            W_Blaster_Attack(
-                actor,
-                weaponentity,
-                WEP_BLASTER.m_id | HITTYPE_SECONDARY,
-                WEP_CVAR_SEC(vaporizer, shotangle),
-                WEP_CVAR_SEC(vaporizer, damage),
-                WEP_CVAR_SEC(vaporizer, edgedamage),
-                WEP_CVAR_SEC(vaporizer, radius),
-                WEP_CVAR_SEC(vaporizer, force),
-                WEP_CVAR_SEC(vaporizer, speed),
-                WEP_CVAR_SEC(vaporizer, spread),
-                WEP_CVAR_SEC(vaporizer, delay),
-                WEP_CVAR_SEC(vaporizer, lifetime)
-            );
-            actor.(weaponentity).m_weapon = oldwep;
+            BLASTER_SECONDARY_ATTACK(vaporizer, actor, weaponentity);
 
             // now do normal refire
             weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(vaporizer, animtime), w_ready);
@@ -375,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;
@@ -394,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 60557cbf8d42211602f985a6ba32da1c22551fa1..b8963229710e23266cba03cb023c2a443773d6b1 100644 (file)
@@ -38,21 +38,16 @@ void SendCSQCVortexBeamParticle(float charge) {
        vector v;
        v = WarpZone_UnTransformOrigin(WarpZone_trace_transform, trace_endpos);
        WriteHeader(MSG_BROADCAST, TE_CSQC_VORTEXBEAMPARTICLE);
-       WriteCoord(MSG_BROADCAST, w_shotorg.x);
-       WriteCoord(MSG_BROADCAST, w_shotorg.y);
-       WriteCoord(MSG_BROADCAST, w_shotorg.z);
-       WriteCoord(MSG_BROADCAST, v.x);
-       WriteCoord(MSG_BROADCAST, v.y);
-       WriteCoord(MSG_BROADCAST, v.z);
+       WriteVector(MSG_BROADCAST, w_shotorg);
+       WriteVector(MSG_BROADCAST, v);
        WriteByte(MSG_BROADCAST, bound(0, 255 * charge, 255));
 }
 #elif defined(CSQC)
 NET_HANDLE(TE_CSQC_VORTEXBEAMPARTICLE, bool isNew)
 {
-       vector shotorg, endpos;
        float charge;
-       shotorg.x = ReadCoord(); shotorg.y = ReadCoord(); shotorg.z = ReadCoord();
-       endpos.x = ReadCoord(); endpos.y = ReadCoord(); endpos.z = ReadCoord();
+    vector shotorg = ReadVector();
+    vector endpos = ReadVector();
        charge = ReadByte() / 255.0;
 
        pointparticles(EFFECT_VORTEX_MUZZLEFLASH, shotorg, normalize(endpos - shotorg) * 1000, 1);
@@ -110,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
 
@@ -125,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);
+       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);
@@ -133,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);
@@ -168,9 +167,6 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity
     if(WEP_CVAR(vortex, charge) && actor.(weaponentity).vortex_charge < WEP_CVAR(vortex, charge_limit))
         actor.(weaponentity).vortex_charge = min(1, actor.(weaponentity).vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME);
 
-    if(weaponslot(weaponentity) == 0)
-        actor.vortex_charge = actor.(weaponentity).vortex_charge;
-
     if(WEP_CVAR_SEC(vortex, chargepool))
         if(actor.(weaponentity).vortex_chargepool_ammo < 1)
         {
@@ -179,9 +175,6 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity
             actor.pauseregen_finished = max(actor.pauseregen_finished, time + WEP_CVAR_SEC(vortex, chargepool_pause_regen));
         }
 
-    if(weaponslot(weaponentity) == 0)
-        actor.vortex_chargepool_ammo = actor.(weaponentity).vortex_chargepool_ammo;
-
     if(autocvar_g_balance_vortex_reload_ammo && actor.(weaponentity).clip_load < min(WEP_CVAR_PRI(vortex, ammo), WEP_CVAR_SEC(vortex, ammo))) { // forced reload
         thiswep.wr_reload(thiswep, actor, weaponentity);
     } else
@@ -208,11 +201,11 @@ METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity
                         if(WEP_CVAR_SEC(vortex, ammo))
                         {
                             // always deplete if secondary is held
-                            actor.vortex_chargepool_ammo = max(0, actor.vortex_chargepool_ammo - WEP_CVAR_SEC(vortex, ammo) * dt);
+                            actor.(weaponentity).vortex_chargepool_ammo = max(0, actor.(weaponentity).vortex_chargepool_ammo - WEP_CVAR_SEC(vortex, ammo) * dt);
 
                             dt = min(dt, (1 - actor.(weaponentity).vortex_charge) / WEP_CVAR(vortex, charge_rate));
                             actor.vortex_chargepool_pauseregen_finished = time + WEP_CVAR_SEC(vortex, chargepool_pause_regen);
-                            dt = min(dt, actor.vortex_chargepool_ammo);
+                            dt = min(dt, actor.(weaponentity).vortex_chargepool_ammo);
                             dt = max(0, dt);
 
                             actor.(weaponentity).vortex_charge += dt * WEP_CVAR(vortex, charge_rate);
@@ -296,10 +289,6 @@ METHOD(Vortex, wr_checkammo2, bool(entity thiswep, entity actor, .entity weapone
 METHOD(Vortex, wr_resetplayer, void(entity thiswep, entity actor))
 {
     if (WEP_CVAR(vortex, charge)) {
-        if (WEP_CVAR_SEC(vortex, chargepool)) {
-            actor.vortex_chargepool_ammo = 1;
-        }
-        actor.vortex_charge = WEP_CVAR(vortex, charge_start);
         for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
         {
             .entity weaponentity = weaponentities[slot];
@@ -358,5 +347,9 @@ METHOD(Vortex, wr_zoom, bool(entity thiswep, entity actor))
         return false;
     }
 }
+METHOD(Vortex, wr_zoomdir, bool(entity thiswep))
+{
+    return button_attack2 && !WEP_CVAR(vortex, secondary);
+}
 
 #endif
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 8d74a7b3272ffc2da3ef3650fff42a223357cf16..9488c4c2c6bc0927a3ba8b30eebeb96baf9a2ccc 100644 (file)
@@ -23,8 +23,12 @@ MACRO_END
        { (viewmodels[this.m_wepent_slot]).alpha = (ReadByte() + -1) / 254; }) \
     \
     PROP(false, vortex_charge, WEPENT_SET_NORMAL, \
-       { WriteByte(chan, this.vortex_charge * 16); }, \
-       { (viewmodels[this.m_wepent_slot]).vortex_charge = ReadByte() / 16; }) \
+       { 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); }, \
@@ -41,6 +45,34 @@ MACRO_END
     PROP(false, tuba_instrument, WEPENT_SET_NORMAL, \
        { WriteByte(chan, this.tuba_instrument); }, \
        { (viewmodels[this.m_wepent_slot]).tuba_instrument = ReadByte(); }) \
+    \
+    PROP(false, hagar_load, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.hagar_load); }, \
+       { (viewmodels[this.m_wepent_slot]).hagar_load = ReadByte(); }) \
+    \
+    PROP(false, minelayer_mines, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.minelayer_mines); }, \
+       { (viewmodels[this.m_wepent_slot]).minelayer_mines = ReadByte(); }) \
+    \
+    PROP(false, arc_heat_percent, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.arc_heat_percent * 255); }, \
+       { (viewmodels[this.m_wepent_slot]).arc_heat_percent = ReadByte() / 255; }) \
+    \
+    PROP(false, vortex_chargepool_ammo, WEPENT_SET_NORMAL, \
+       { WriteByte(chan, this.vortex_chargepool_ammo * 16); }, \
+       { (viewmodels[this.m_wepent_slot]).vortex_chargepool_ammo = ReadByte() / 16; }) \
+    \
+       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(); }) \
+    \
+    PROP(false, clip_size, WEPENT_SET_NORMAL, \
+       { WriteShort(chan, this.clip_size); }, \
+       { (viewmodels[this.m_wepent_slot]).clip_size = ReadShort(); }) \
     \
        /**/
 
@@ -58,7 +90,7 @@ MACRO_END
                }
                WEPENT_NETPROPS(X);
        #undef X
-               if (i >= BITS(16 - 1)) LOG_FATAL("Exceeded WEPENT_NETPROPS limit");
+               if (i >= BITS(24 - 1)) LOG_FATAL("Exceeded WEPENT_NETPROPS limit");
        }
 
        bool _wepent_send(entity this, entity to, int sf, int chan)
@@ -71,7 +103,7 @@ MACRO_END
                        WriteHeader(chan, CLIENT_WEPENT);
                .entity weaponentity = this.owner.weaponentity_fld;
                WriteByte(chan, weaponslot(weaponentity));
-               WriteShort(chan, sf);
+               WriteInt24_t(chan, sf);
                int i = 0;
                #define X(public, fld, set, sv, cl) { \
                        if (sf & BIT(i)) { \
@@ -115,9 +147,9 @@ MACRO_END
 
        bool wepent_customize(entity this, entity client)
        {
-               //entity e = WaypointSprite_getviewentity(client);
+               entity e = WaypointSprite_getviewentity(client);
                .entity weaponentity = this.owner.weaponentity_fld;
-               return client.(weaponentity) == this.owner;
+               return e.(weaponentity) == this.owner;
        }
 
        void wepent_link(entity wep)
@@ -140,7 +172,7 @@ MACRO_END
                int slot = ReadByte();
                this.m_wepent_slot = slot;
                viewmodels[slot].m_wepent_slot = slot;
-               int sf = ReadShort();
+               int sf = ReadInt24_t();
                int i = 0;
                #define X(public, fld, set, sv, cl) { \
                        if (sf & BIT(i)) { \
index 46180d7c0b4e2c82fe02ee5fb6f6e1e8b8234c0d..d6db7745b9fe1cc5e1ebc8f0f0edcfca78382214 100644 (file)
@@ -4,7 +4,15 @@ REGISTER_NET_LINKED(ENT_CLIENT_WEPENT)
 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;
+.int hagar_load;
+.int clip_load;
+.int clip_size;
 
 #ifdef SVQC
 
index f74e9c2d5526c895fd8b28c1bdd9bb7a884faef0..fa087b5eb48bbb29c78bee163e703ee7e9e60a3a 100644 (file)
@@ -6,7 +6,6 @@ void sys_phys_fix(entity this, float dt)
        PHYS_WATERJUMP_TIME(this) -= dt;
        this.movement = PHYS_INPUT_MOVEVALUES(this);
        this.items = STAT(ITEMS, this);
-       this.spectatorspeed = STAT(SPECTATORSPEED, this);
        if (!(PHYS_INPUT_BUTTON_JUMP(this))) // !jump
                UNSET_JUMP_HELD(this);           // canjump = true
        PM_ClientMovement_UpdateStatus(this);
index ec97bb2a15734f9bbc7c6f3b700e752a1527f8dc..ae5f119e7fe8db0eea039a57032af553cd4d7d24 100644 (file)
@@ -6,6 +6,8 @@
 void sys_phys_simulate(entity this, float dt);
 void sys_phys_simulate_simple(entity this, float dt);
 
+void sys_phys_postupdate(entity this);
+
 void sys_phys_update(entity this, float dt)
 {
        if (!IS_CLIENT(this)) {
@@ -43,12 +45,12 @@ 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)) {
                sys_phys_spectator_control(this);
-               maxspeed_mod = this.spectatorspeed;
+               maxspeed_mod = STAT(SPECTATORSPEED, this);
        }
        sys_phys_fixspeed(this, maxspeed_mod);
 
@@ -63,7 +65,8 @@ void sys_phys_update(entity this, float dt)
                        // if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
                        // { this.velocity_z = 70; }
                }
-               goto end;
+               sys_phys_postupdate(this);
+               return;
        }
 
        PM_check_slick(this);
@@ -153,10 +156,14 @@ void sys_phys_update(entity this, float dt)
                this.com_phys_air = false;
        }
 
-       LABEL(end)
+       sys_phys_postupdate(this);
+}
+
+void sys_phys_postupdate(entity this)
+{
        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 6677d1782fe0c17720c8ef7d4a6f45c092419ce9..45128393baee77d55b07b436b735291ae9c08e0c 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)
@@ -33,7 +34,6 @@ void sys_phys_monitor(entity this, float dt)
 void sys_phys_ai(entity this)
 {
        if (!IS_BOT_CLIENT(this)) { return; }
-       if (playerdemo_read(this)) { return; }
        bot_think(this);
 }
 
@@ -54,7 +54,7 @@ void sys_phys_pregame_hold(entity this)
 void sys_phys_spectator_control(entity this)
 {
        float maxspeed_mod = autocvar_sv_spectator_speed_multiplier;
-       if (!this.spectatorspeed) { this.spectatorspeed = maxspeed_mod; }
+       if (!STAT(SPECTATORSPEED, this)) { STAT(SPECTATORSPEED, this) = maxspeed_mod; }
        if ((CS(this).impulse >= 1 && CS(this).impulse <= 19)
            || (CS(this).impulse >= 200 && CS(this).impulse <= 209)
            || (CS(this).impulse >= 220 && CS(this).impulse <= 229)
@@ -65,17 +65,17 @@ void sys_phys_spectator_control(entity this)
                            || CS(this).impulse == 18
                            || (CS(this).impulse >= 200 && CS(this).impulse <= 209)
                           ) {
-                               this.spectatorspeed = bound(autocvar_sv_spectator_speed_multiplier_min, this.spectatorspeed + 0.5, autocvar_sv_spectator_speed_multiplier_max);
+                               STAT(SPECTATORSPEED, this) = bound(autocvar_sv_spectator_speed_multiplier_min, STAT(SPECTATORSPEED, this) + 0.5, autocvar_sv_spectator_speed_multiplier_max);
                        } else if (CS(this).impulse == 11) {
-                               this.spectatorspeed = maxspeed_mod;
+                               STAT(SPECTATORSPEED, this) = maxspeed_mod;
                        } else if (CS(this).impulse == 12
                            || CS(this).impulse == 16
                            || CS(this).impulse == 19
                            || (CS(this).impulse >= 220 && CS(this).impulse <= 229)
                                  ) {
-                               this.spectatorspeed = bound(autocvar_sv_spectator_speed_multiplier_min, this.spectatorspeed - 0.5, autocvar_sv_spectator_speed_multiplier_max);
+                               STAT(SPECTATORSPEED, this) = bound(autocvar_sv_spectator_speed_multiplier_min, STAT(SPECTATORSPEED, this) - 0.5, autocvar_sv_spectator_speed_multiplier_max);
                        } else if (CS(this).impulse >= 1 && CS(this).impulse <= 9) {
-                               this.spectatorspeed = 1 + 0.5 * (CS(this).impulse - 1);
+                               STAT(SPECTATORSPEED, this) = 1 + 0.5 * (CS(this).impulse - 1);
                        }
                }  // otherwise just clear
                CS(this).impulse = 0;
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 225c7307ded6c60a192056eafde3078912c4ae52..f87f00033762b4fbe18f2d5305989941a191828b 100644 (file)
@@ -291,7 +291,7 @@ void CSQCPlayer_SetCamera()
                // note: these two only work in WIP2, but are harmless in WIP1
                if (PHYS_HEALTH(NULL) <= 0 && PHYS_HEALTH(NULL) != -666 && PHYS_HEALTH(NULL) != -2342) refdefflags |= REFDEFFLAG_DEAD;
                if (intermission) refdefflags |= REFDEFFLAG_INTERMISSION;
-               V_CalcRefdef(view, refdefflags);
+               V_CalcRefdef(view, refdefflags); // TODO? uses .health stat in the engine when this isn't called here, may be broken!
        }
        else
        {
index 37b88997ef84bf7d456e34575fc0859d79f01442..f8375d09e8202de55cdda5a61dcc6de4d85b9912 100644 (file)
@@ -66,15 +66,9 @@ const int CSQCMODEL_PROPERTY_SIZE = BIT(15);
 #define ALLPROPERTIES_COMMON \
        CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_FRAME, int, ReadByte, WriteByte, frame) \
        CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_MODELINDEX, int, ReadShort, WriteShort, modelindex) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, float, ReadCoord, WriteCoord, origin_z) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, mins_z) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_x) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_y) \
-       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, float, ReadShort, WriteShort, maxs_z) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_ORIGIN, vector, ReadVector, WriteVector, origin) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, vector, ReadVector, WriteVector, mins) \
+       CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_SIZE, vector, ReadVector, WriteVector, maxs) \
        CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_x) \
        CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_YAW, float, ReadAngle, WriteAngle, angles_y) \
        CSQCMODEL_PROPERTY(CSQCMODEL_PROPERTY_PITCHROLL, float, ReadAngle, WriteAngle, angles_z) \
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 09f430407ef8ea26ba38dcb577047f5cdea9bc52..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) { \
@@ -156,12 +156,14 @@ noref bool require_spawnfunc_prefix;
                FIELD_SCALAR(fld, ammo_cells) \
                FIELD_SCALAR(fld, ammo_nails) \
                FIELD_SCALAR(fld, ammo_rockets) \
+               FIELD_SCALAR(fld, antiwall_flag) \
                FIELD_SCALAR(fld, armorvalue) \
                FIELD_SCALAR(fld, atten) \
                FIELD_SCALAR(fld, bgmscriptdecay) \
                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) \
@@ -181,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) \
@@ -215,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) \
@@ -242,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) \
@@ -255,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 15a3ca4c3ccc6e90870c72ab7bc74251777dd397..3a6765e9d46fbfc7ed9025238cfe8017a1fc5bde 100644 (file)
@@ -42,32 +42,18 @@ NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
        this.warpzone_isboxy = (f & 1);
        if(f & 4)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
        }
        else
                this.origin = '0 0 0';
        this.modelindex = ReadShort();
-       this.mins_x = ReadCoord();
-       this.mins_y = ReadCoord();
-       this.mins_z = ReadCoord();
-       this.maxs_x = ReadCoord();
-       this.maxs_y = ReadCoord();
-       this.maxs_z = ReadCoord();
+       this.mins = ReadVector();
+       this.maxs = ReadVector();
        this.scale = ReadByte() / 16;
-       this.enemy.oldorigin_x = ReadCoord();
-       this.enemy.oldorigin_y = ReadCoord();
-       this.enemy.oldorigin_z = ReadCoord();
-       this.enemy.avelocity_x = ReadCoord();
-       this.enemy.avelocity_y = ReadCoord();
-       this.enemy.avelocity_z = ReadCoord();
-       this.oldorigin_x = ReadCoord();
-       this.oldorigin_y = ReadCoord();
-       this.oldorigin_z = ReadCoord();
-       this.avelocity_x = ReadCoord();
-       this.avelocity_y = ReadCoord();
-       this.avelocity_z = ReadCoord();
+       this.enemy.oldorigin = ReadVector();
+       this.enemy.avelocity = ReadVector();
+       this.oldorigin = ReadVector();
+       this.avelocity = ReadVector();
 
        if(f & 2)
        {
@@ -104,26 +90,16 @@ NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
        int f = ReadByte();
        if(f & 4)
        {
-               this.origin_x = ReadCoord();
-               this.origin_y = ReadCoord();
-               this.origin_z = ReadCoord();
+               this.origin = ReadVector();
        }
        else
                this.origin = '0 0 0';
        this.modelindex = ReadShort();
-       this.mins_x = ReadCoord();
-       this.mins_y = ReadCoord();
-       this.mins_z = ReadCoord();
-       this.maxs_x = ReadCoord();
-       this.maxs_y = ReadCoord();
-       this.maxs_z = ReadCoord();
+       this.mins = ReadVector();
+       this.maxs = ReadVector();
        this.scale = ReadByte() / 16;
-       this.oldorigin_x = ReadCoord();
-       this.oldorigin_y = ReadCoord();
-       this.oldorigin_z = ReadCoord();
-       this.avelocity_x = ReadCoord();
-       this.avelocity_y = ReadCoord();
-       this.avelocity_z = ReadCoord();
+       this.oldorigin = ReadVector();
+       this.avelocity = ReadVector();
 
        if(f & 2)
        {
@@ -157,10 +133,7 @@ void CL_RotateMoves(vector ang) = #638;
 NET_HANDLE(ENT_CLIENT_WARPZONE_TELEPORTED, bool isnew)
 {
        this.classname = "warpzone_teleported";
-       vector v;
-       v.x = ReadCoord();
-       v.y = ReadCoord();
-       v.z = ReadCoord();
+       vector v = ReadVector();
        return = true;
        if (!isnew) return;
        this.warpzone_transform = v;
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 936d075da8f69e2b3057d965dc35029b57b1cf23..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>
@@ -61,9 +61,7 @@ void WarpZone_TeleportPlayer(entity teleporter, entity player, vector to, vector
 bool WarpZone_Teleported_Send(entity this, entity to, int sf)
 {
        WriteHeader(MSG_ENTITY, ENT_CLIENT_WARPZONE_TELEPORTED);
-       WriteCoord(MSG_ENTITY, this.angles.x);
-       WriteCoord(MSG_ENTITY, this.angles.y);
-       WriteCoord(MSG_ENTITY, this.angles.z);
+       WriteVector(MSG_ENTITY, this.angles);
        return true;
 }
 #endif
@@ -179,11 +177,7 @@ void WarpZone_Touch(entity this, entity toucher)
                return;
 
        // FIXME needs a better check to know what is safe to teleport and what not
-       if((toucher.move_movetype == MOVETYPE_NONE && toucher.move_movetype == MOVETYPE_NONE) || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.tag_entity
-#ifdef CSQC
-       || tag_networkentity
-#endif
-       )
+       if(toucher.move_movetype == MOVETYPE_NONE || toucher.move_movetype == MOVETYPE_FOLLOW || toucher.tag_entity)
                return;
 
        if(WarpZoneLib_ExactTrigger_Touch(this, toucher))
index 72bcc5e94ec44a294f1b9eaa86b5cad566b0a22d..c651a4ffc4fcfd277b208b46e457d675e43ba30d 100644 (file)
                this.delta = e - s;
        }
 
-       METHOD(Animation, setValueStartDelta, void(entity this, float s, float d))
-       {
-               this.startValue = s;
-               this.delta = d;
-       }
-
        METHOD(Animation, setObjectSetter, void(entity this, entity o, void(entity, float) s))
        {
                this.object = o;
index 009feb577c00fbaa1454ed373845f7cd6998fedb..1fdea3dd6fbfdd4fae41cce56ffd80b179910b39 100644 (file)
@@ -6,7 +6,6 @@ CLASS(Animation, Object)
        METHOD(Animation, setTimeStartEnd, void(Animation this, float, float));
        METHOD(Animation, setTimeStartDuration, void(Animation this, float, float));
        METHOD(Animation, setValueStartEnd, void(Animation this, float, float));
-       METHOD(Animation, setValueStartDelta, void(Animation this, float, float));
        METHOD(Animation, setObjectSetter, void(Animation this, entity, void(entity, float)));
        METHOD(Animation, tick, void(Animation this, float));
        METHOD(Animation, calcValue, float(Animation this, float, float, float, float));
index 18e5ae08123ff999f479c896f2eadc79de4972d6..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>
 
@@ -48,6 +48,7 @@ void GameCommand(string theCommand)
                LOG_INFO(_("Usage: menu_cmd command..., where possible commands are:"));
                LOG_INFO(_("  sync - reloads all cvars on the current menu page"));
                LOG_INFO(_("  directmenu ITEM - select a menu item as main item"));
+               LOG_INFO(_("  dumptree - dump the state of the menu as a tree to the console"));
 
                LOG_INFO("Generic commands shared by all programs:");
                GenericCommand_macro_help();
index 01184a4bf5d026e2c5c0580c8ef625e07610772a..ae6967e367565fc02c38f08f57c77ac0ccca706d 100644 (file)
@@ -312,32 +312,55 @@ float draw_CondensedFontFactor(string theText, float ICanHasKallerz, vector Size
        return 1.0;
 }
 
-float draw_clipSet;
+IntrusiveList draw_clip;
+STATIC_INIT(draw_clip) { draw_clip = IL_NEW(); }
+CLASS(ClipFrame, Object)
+       ATTRIB(ClipFrame, clip_shift, vector, '0 0 0');
+       ATTRIB(ClipFrame, clip_scale, vector, '0 0 0');
+ENDCLASS(ClipFrame)
+
+void _draw_SetClip(vector o, vector s)
+{
+       ClipFrame prev = IL_PEEK(draw_clip);
+       if (prev) {
+               o.x = bound(prev.clip_shift.x, o.x, prev.clip_shift.x + prev.clip_scale.x);
+               o.y = bound(prev.clip_shift.y, o.y, prev.clip_shift.y + prev.clip_scale.y);
+               s.x = bound(0, s.x, prev.clip_scale.x - (o.x - prev.clip_shift.x));
+               s.y = bound(0, s.y, prev.clip_scale.y - (o.y - prev.clip_shift.y));
+       }
+       ClipFrame e = NEW(ClipFrame);
+       e.clip_shift = o;
+       e.clip_scale = s;
+       IL_PUSH(draw_clip, e);
+       drawsetcliparea(o.x, o.y, s.x, s.y);
+}
+
 void draw_SetClip()
 {
-       if(draw_clipSet)
-               error("Already clipping, no stack implemented here, sorry");
-       drawsetcliparea(draw_shift.x, draw_shift.y, draw_scale.x, draw_scale.y);
-       draw_clipSet = 1;
+       _draw_SetClip(draw_shift, draw_scale);
 }
 
 void draw_SetClipRect(vector theOrigin, vector theScale)
 {
-       vector o, s;
-       if(draw_clipSet)
-               error("Already clipping, no stack implemented here, sorry");
-       o = boxToGlobal(theOrigin, draw_shift, draw_scale);
-       s = boxToGlobalSize(theScale, draw_scale);
-       drawsetcliparea(o.x, o.y, s.x, s.y);
-       draw_clipSet = 1;
+       _draw_SetClip(
+               boxToGlobal(theOrigin, draw_shift, draw_scale),
+               boxToGlobalSize(theScale, draw_scale)
+       );
 }
 
 void draw_ClearClip()
 {
-       if(!draw_clipSet)
-               error("Not clipping, can't clear it then");
+       if (IL_EMPTY(draw_clip)) {
+               LOG_FATAL("Not clipping, can't clear it then");
+       }
+       entity currentSettings = IL_PEEK(draw_clip);
+       IL_REMOVE(draw_clip, currentSettings);
+       delete(currentSettings);
        drawresetcliparea();
-       draw_clipSet = 0;
+       ClipFrame e = IL_PEEK(draw_clip);
+       if (e) {
+               drawsetcliparea(e.clip_shift.x, e.clip_shift.y, e.clip_scale.x, e.clip_scale.y);
+       }
 }
 
 string draw_TextShortenToWidth(string theText, float maxWidth, float ICanHasKallerz, vector SizeThxBye)
index 1d31e95a9c7d5c513ea9f2766da4c574a1d7eca3..a5c7cfa8544c70219099a4a12079b7a87dd5a408 100644 (file)
@@ -74,9 +74,9 @@
                return 0;  // unhandled
        }
 
-       METHOD(Item, mousePress, float(Item this, vector pos))
+       METHOD(Item, mousePress, bool(Item this, vector pos))
        {
-               return 0;  // unhandled
+               return false;  // unhandled
        }
 
        METHOD(Item, mouseDrag, float(Item this, vector pos))
index a5df526806e851e7777f0e6792de627881a46145..6cee17b3fdd5f9ccd24a66d078f040aaee9110a2 100644 (file)
@@ -10,7 +10,7 @@ CLASS(Item, Object)
        METHOD(Item, keyDown, float(Item, float, float, float));
        METHOD(Item, keyUp, float(Item, float, float, float));
        METHOD(Item, mouseMove, float(Item, vector));
-       METHOD(Item, mousePress, float(Item, vector));
+       METHOD(Item, mousePress, bool(Item this, vector pos));
        METHOD(Item, mouseDrag, float(Item, vector));
        METHOD(Item, mouseRelease, float(Item, vector));
        METHOD(Item, focusEnter, void(Item));
index 8299a6859f539c097404e15184437e0903b44c4f..77e4ccad264fee8f912abdb8573ba154af71289c 100644 (file)
                if (pos.y >= 1) me.pressed = 0;
                return 1;
        }
-       float Button_mousePress(entity me, vector pos)
+       METHOD(Button, mousePress, bool(Button this, vector pos))
        {
-               me.mouseDrag(me, pos);  // verify coordinates
-               return 1;
+               this.mouseDrag(this, pos);  // verify coordinates
+               return true;
        }
        float Button_mouseRelease(entity me, vector pos)
        {
index 1a164245c8f269368067b3b43c4ae6f92fd9066f..2077da70071c5b680c55e6ac83b10838b83bf2a4 100644 (file)
@@ -9,7 +9,7 @@ CLASS(Button, Label)
        METHOD(Button, showNotify, void(entity));
        METHOD(Button, resizeNotify, void(entity, vector, vector, vector, vector));
        METHOD(Button, keyDown, float(entity, float, float, float));
-       METHOD(Button, mousePress, float(entity, vector));
+       METHOD(Button, mousePress, bool(Button this, vector pos));
        METHOD(Button, mouseDrag, float(entity, vector));
        METHOD(Button, mouseRelease, float(entity, vector));
        METHOD(Button, playClickSound, void(entity));
index 56535bf71c18f5ddd24202dc534642568948c1c2..329ddf0f6e201c880a09883f0fdc3af296e78dce 100644 (file)
                }
                return 0;
        }
-       float Container_mousePress(entity me, vector pos)
+       METHOD(Container, mousePress, bool(Container this, vector pos))
        {
-               entity f;
-               float r;
-               f = me.focusedChild;
+               entity f = this.focusedChild;
                if (f)
                {
-                       me.enterSubitem(me, f);
-                       r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
-                       me.leaveSubitem(me);
+                       this.enterSubitem(this, f);
+                       bool r = f.mousePress(f, globalToBox(pos, f.Container_origin, f.Container_size));
+                       this.leaveSubitem(this);
                        return r;
                }
-               return 0;
+               return false;
        }
        float Container_mouseDrag(entity me, vector pos)
        {
                                me.focusedChild.focused = 1;
                                me.focusedChild.focusEnter(me.focusedChild);
 
-                               if (me.focusedChild.instanceOfContainer) me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
+                               if (me.focusedChild.instanceOfContainer)
+                                       me.focusedChild.setFocus(me.focusedChild, me.focusedChild.savedFocus);
                        }
                        else
                        {
index 8273f5ddde38a43ec3e153d3a5f02247f452a775..b73752685030a8ef57277ddaf3a3b7b7279f26f1 100644 (file)
@@ -7,7 +7,7 @@ CLASS(Container, Item)
        METHOD(Container, keyUp, float(entity, float, float, float));
        METHOD(Container, keyDown, float(entity, float, float, float));
        METHOD(Container, mouseMove, float(entity, vector));
-       METHOD(Container, mousePress, float(entity, vector));
+       METHOD(Container, mousePress, bool(Container this, vector pos));
        METHOD(Container, mouseDrag, float(entity, vector));
        METHOD(Container, mouseRelease, float(entity, vector));
        METHOD(Container, focusLeave, void(entity));
index 59405ec169f15448df4e7f028c67b8e43ef56c0b..73b302c4a7716a6e7f7b363b030a3d46ff7058a8 100644 (file)
 
        void Image_draw(entity me)
        {
-               if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_SetClip();
+               bool willClip = me.imgSize.x > 1 || me.imgSize.y > 1;
+               if (willClip) draw_SetClip();
                draw_Picture(me.imgOrigin, me.src, me.imgSize, me.color, 1);
-               if (me.imgSize.x > 1 || me.imgSize.y > 1) draw_ClearClip();
+               if (willClip) draw_ClearClip();
                SUPER(Image).draw(me);
        }
        void Image_updateAspect(entity me)
index 6f7ed9f24309b7d7556d5d594144acf642198a83..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));
        }
 
                return 1;
        }
 
-       float InputBox_mousePress(entity me, vector pos)
+       METHOD(InputBox, mousePress, bool(InputBox this, vector pos))
        {
-               if (me.enableClearButton)
-                       if (over_ClearButton(me, pos))
+               if (this.enableClearButton)
+                       if (over_ClearButton(this, pos))
                        {
-                               me.cb_pressed = 1;
-                               return 1;
+                               this.cb_pressed = 1;
+                               return true;
                        }
-               me.dragScrollTimer = time;
-               me.pressed = 1;
-               return InputBox_mouseDrag(me, pos);
+               this.dragScrollTimer = time;
+               this.pressed = 1;
+               return InputBox_mouseDrag(this, pos);
        }
 
        float InputBox_mouseRelease(entity me, vector pos)
index e3eede653b9c0c297bf698b36ed1b4108ae5035b..5b0c28f9e454d49eb6990e9cd694abe845f8e4dd 100644 (file)
@@ -9,7 +9,7 @@ CLASS(InputBox, Label)
        METHOD(InputBox, keyDown, float(entity, float, float, float));
        METHOD(InputBox, mouseMove, float(entity, vector));
        METHOD(InputBox, mouseRelease, float(entity, vector));
-       METHOD(InputBox, mousePress, float(entity, vector));
+       METHOD(InputBox, mousePress, bool(InputBox this, vector pos));
        METHOD(InputBox, mouseDrag, float(entity, vector));
        METHOD(InputBox, showNotify, void(entity));
        METHOD(InputBox, resizeNotify, void(entity, vector, vector, vector, vector));
index 37c46240f77fdcd8bf704b1b6d999aaa3de5e254..cda342677262206dd8afb2bcdb011f136ed2edc9 100644 (file)
                if (e && !e.focusable) e = NULL;
                entity prev = this.mouseFocusedChild;
                this.mouseFocusedChild = e;
-               if (!e) return false;  // keep focus when hovering over non-focusable elements
                if (e != prev)
                {
                        this.setFocus(this, e);
-                       if (e.instanceOfInputContainer)
+                       if (e && e.instanceOfInputContainer)
                        {
                                e.focusedChild = NULL;
                                e._changeFocusXY(e, globalToBox(pos, e.Container_origin, e.Container_size));
                if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
                return 0;
        }
-       float InputContainer_mousePress(entity me, vector pos)
+       METHOD(InputContainer, mousePress, bool(InputContainer this, vector pos))
        {
-               me.mouseFocusedChild = NULL;  // force focusing
-               if (me._changeFocusXY(me, pos))
-                       if (SUPER(InputContainer).mousePress(me, pos)) return 1;
-               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return 1;
-               return 0;
+               this.mouseFocusedChild = NULL;  // force focusing
+               if (this._changeFocusXY(this, pos))
+                       if (SUPER(InputContainer).mousePress(this, pos)) return true;
+               if (pos.x >= 0 && pos.y >= 0 && pos.x < 1 && pos.y < 1) return true;
+               return false;
        }
        float InputContainer_mouseRelease(entity me, vector pos)
        {
index 9ae4a537506bcad1a54fb7721b7816dd74685d35..8ded2e657bcba13f3a7f594c078d6dafceee4043 100644 (file)
@@ -4,7 +4,7 @@
 CLASS(InputContainer, Container)
        METHOD(InputContainer, keyDown, float(entity, float, float, float));
        METHOD(InputContainer, mouseMove, float(entity, vector));
-       METHOD(InputContainer, mousePress, float(entity, vector));
+       METHOD(InputContainer, mousePress, bool(InputContainer this, vector pos));
        METHOD(InputContainer, mouseRelease, float(entity, vector));
        METHOD(InputContainer, mouseDrag, float(entity, vector));
        METHOD(InputContainer, focusLeave, void(entity));
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 aa10c20b3b0f6d04bac8d5810e8b53b74bb799f2..97f08c98113e520e6d55457356befca52319f28b 100644 (file)
                if (me.pressed == 1)
                {
                        hit = 1;
-                       if (pos.x < 1 - me.controlWidth - me.tolerance.y * me.controlWidth) hit = 0;
-                       if (pos.y < 0 - me.tolerance.x) hit = 0;
-                       if (pos.x >= 1 + me.tolerance.y * me.controlWidth) hit = 0;
-                       if (pos.y >= 1 + me.tolerance.x) hit = 0;
+                       if (pos.x < 1 - me.controlWidth - me.tolerance.x * me.controlWidth) hit = 0;
+                       if (pos.y < 0 - me.tolerance.y) hit = 0;
+                       if (pos.x >= 1 + me.tolerance.x * me.controlWidth) hit = 0;
+                       if (pos.y >= 1 + me.tolerance.y) hit = 0;
                        if (hit)
                        {
                                // calculate new pos to v
                }
                return 1;
        }
-       float ListBox_mousePress(entity me, vector pos)
+       METHOD(ListBox, mousePress, bool(ListBox this, vector pos))
        {
-               if (pos.x < 0) return 0;
-               if (pos.y < 0) return 0;
-               if (pos.x >= 1) return 0;
-               if (pos.y >= 1) return 0;
-               me.dragScrollPos = pos;
-               me.updateControlTopBottom(me);
-               if (pos.x >= 1 - me.controlWidth)
+               if (pos.x < 0) return false;
+               if (pos.y < 0) return false;
+               if (pos.x >= 1) return false;
+               if (pos.y >= 1) return false;
+               this.dragScrollPos = pos;
+               this.updateControlTopBottom(this);
+               if (pos.x >= 1 - this.controlWidth)
                {
-                       // if hit, set me.pressed, otherwise scroll by one page
-                       if (pos.y < me.controlTop)
+                       // if hit, set this.pressed, otherwise scroll by one page
+                       if (pos.y < this.controlTop)
                        {
                                // page up
-                               me.scrollPosTarget = max(me.scrollPosTarget - 1, 0);
+                               this.scrollPosTarget = max(this.scrollPosTarget - 1, 0);
                        }
-                       else if (pos.y > me.controlBottom)
+                       else if (pos.y > this.controlBottom)
                        {
                                // page down
-                               me.scrollPosTarget = min(me.scrollPosTarget + 1, me.getTotalHeight(me) - 1);
+                               this.scrollPosTarget = min(this.scrollPosTarget + 1, this.getTotalHeight(this) - 1);
                        }
                        else
                        {
-                               me.pressed = 1;
-                               me.pressOffset = pos.y;
-                               me.previousValue = me.scrollPos;
+                               this.pressed = 1;
+                               this.pressOffset = pos.y;
+                               this.previousValue = this.scrollPos;
                        }
                }
                else
                {
                        // continue doing that while dragging (even when dragging outside). When releasing, forward the click to the then selected item.
-                       me.pressed = 2;
+                       this.pressed = 2;
                        // an item has been clicked. Select it, ...
-                       me.setSelected(me, me.getItemAtPos(me, me.scrollPos + pos.y));
-                       me.setFocusedItem(me, me.selectedItem);
+                       this.setSelected(this, this.getItemAtPos(this, this.scrollPos + pos.y));
+                       this.setFocusedItem(this, this.selectedItem);
                }
-               return 1;
+               return true;
        }
        void ListBox_setFocusedItem(entity me, int item)
        {
        AUTOCVAR(menu_scroll_averaging_time_pressed, float, 0.06, "smooth scroll averaging time when dragging the scrollbar");
        void ListBox_draw(entity me)
        {
-               float i;
-               vector absSize, fillSize = '0 0 0';
-               vector oldshift, oldscale;
+               vector fillSize = '0 0 0';
 
                // we can't do this in mouseMove as the list can scroll without moving the cursor
                if (me.mouseMoveOffset != -1) me.setFocusedItem(me, me.getItemAtPos(me, me.scrollPos + me.mouseMoveOffset));
                        }
                }
                draw_SetClip();
-               oldshift = draw_shift;
-               oldscale = draw_scale;
+               vector oldshift = draw_shift;
+               vector oldscale = draw_scale;
 
-               i = me.getItemAtPos(me, me.scrollPos);
-               float j = me.getItemStart(me, i) - me.scrollPos;
-               for ( ; i < me.nItems && j < 1; ++i)
+               int i = me.getItemAtPos(me, me.scrollPos);
+               float y = me.getItemStart(me, i) - me.scrollPos;
+               for ( ; i < me.nItems && y < 1; ++i)
                {
-                       draw_shift = boxToGlobal(eY * j, oldshift, oldscale);
+                       draw_shift = boxToGlobal(eY * y, oldshift, oldscale);
                        vector relSize = eX * (1 - me.controlWidth) + eY * me.getItemHeight(me, i);
-                       absSize = boxToGlobalSize(relSize, me.size);
+                       vector absSize = boxToGlobalSize(relSize, me.size);
                        draw_scale = boxToGlobalSize(relSize, oldscale);
                        me.drawListBoxItem(me, i, absSize, (me.selectedItem == i), (me.focusedItem == i));
-                       j += relSize.y;
+                       y += relSize.y;
                }
                draw_ClearClip();
 
index 56fda91cc15d82e163e362e9a250c38a8c1bb525..b3f5164a4d0937f769a55c68fb9cfbf474b07a99 100644 (file)
@@ -7,7 +7,7 @@ CLASS(ListBox, Item)
        METHOD(ListBox, draw, void(entity));
        METHOD(ListBox, keyDown, float(entity, float, float, float));
        METHOD(ListBox, mouseMove, float(entity, vector));
-       METHOD(ListBox, mousePress, float(entity, vector));
+       METHOD(ListBox, mousePress, bool(ListBox this, vector pos));
        METHOD(ListBox, mouseDrag, float(entity, vector));
        METHOD(ListBox, mouseRelease, float(entity, vector));
        METHOD(ListBox, focusLeave, void(entity));
index c0f18cf859476eff528f0f9a9ebb10a1eee3acdd..d42fceb533a787a35a340eaa517aa964e1843247 100644 (file)
@@ -154,35 +154,35 @@ LABEL(have_overlap)
                SUPER(Nexposee).draw(me);
        }
 
-       float Nexposee_mousePress(entity me, vector pos)
+       METHOD(Nexposee, mousePress, bool(Nexposee this, vector pos))
        {
-               if (me.animationState == 0)
+               if (this.animationState == 0)
                {
-                       me.mouseFocusedChild = NULL;
-                       Nexposee_mouseMove(me, pos);
-                       if (me.mouseFocusedChild)
+                       this.mouseFocusedChild = NULL;
+                       Nexposee_mouseMove(this, pos);
+                       if (this.mouseFocusedChild)
                        {
                                m_play_click_sound(MENU_SOUND_OPEN);
-                               me.animationState = 1;
-                               SUPER(Nexposee).setFocus(me, NULL);
+                               this.animationState = 1;
+                               SUPER(Nexposee).setFocus(this, NULL);
                        }
                        else
                        {
-                               me.close(me);
+                               this.close(this);
                        }
-                       return 1;
+                       return true;
                }
-               else if (me.animationState == 2)
+               else if (this.animationState == 2)
                {
-                       if (!(SUPER(Nexposee).mousePress(me, pos)))
+                       if (!(SUPER(Nexposee).mousePress(this, pos)))
                        {
                                m_play_click_sound(MENU_SOUND_CLOSE);
-                               me.animationState = 3;
-                               SUPER(Nexposee).setFocus(me, NULL);
+                               this.animationState = 3;
+                               SUPER(Nexposee).setFocus(this, NULL);
                        }
-                       return 1;
+                       return true;
                }
-               return 0;
+               return false;
        }
 
        float Nexposee_mouseRelease(entity me, vector pos)
index 4159648f974207260d502ab8efb4ad90907258f4..440413b5e59616332194103a7c6f1b30cb8f0649 100644 (file)
@@ -5,7 +5,7 @@ CLASS(Nexposee, Container)
        METHOD(Nexposee, draw, void(entity));
        METHOD(Nexposee, keyDown, float(entity, float, float, float));
        METHOD(Nexposee, keyUp, float(entity, float, float, float));
-       METHOD(Nexposee, mousePress, float(entity, vector));
+       METHOD(Nexposee, mousePress, bool(Nexposee this, vector pos));
        METHOD(Nexposee, mouseMove, float(entity, vector));
        METHOD(Nexposee, mouseRelease, float(entity, vector));
        METHOD(Nexposee, mouseDrag, float(entity, vector));
index 2e89bb68ee21e7356dcc906653a73c9a35b385c1..b569c3b0c4c228bec7d158f558129e21fded4f7c 100644 (file)
 
                return 1;
        }
-       float Slider_mousePress(entity me, vector pos)
+       METHOD(Slider, mousePress, bool(Slider this, vector pos))
        {
                float controlCenter;
-               if (me.disabled) return 0;
-               if (pos.x < 0) return 0;
-               if (pos.y < 0) return 0;
-               if (pos.x >= 1 - me.textSpace) return 0;
-               if (pos.y >= 1) return 0;
-               controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
-               if (fabs(pos.x - controlCenter) <= 0.5 * me.controlWidth)
+               if (this.disabled) return false;
+               if (pos.x < 0) return false;
+               if (pos.y < 0) return false;
+               if (pos.x >= 1 - this.textSpace) return false;
+               if (pos.y >= 1) return false;
+               controlCenter = (this.value - this.valueMin) / (this.valueMax - this.valueMin) * (1 - this.textSpace - this.controlWidth) + 0.5 * this.controlWidth;
+               if (fabs(pos.x - controlCenter) <= 0.5 * this.controlWidth)
                {
-                       me.pressed = 1;
-                       me.pressOffset = pos.x - controlCenter;
-                       me.previousValue = me.value;
-                       // me.mouseDrag(me, pos);
+                       this.pressed = 1;
+                       this.pressOffset = pos.x - controlCenter;
+                       this.previousValue = this.value;
+                       // this.mouseDrag(this, pos);
                }
                else
                {
                        float clickValue, pageValue, inRange;
-                       clickValue = median(0, (pos.x - me.pressOffset - 0.5 * me.controlWidth) / (1 - me.textSpace - me.controlWidth), 1) * (me.valueMax - me.valueMin) + me.valueMin;
-                       inRange = (almost_in_bounds(me.valueMin, me.value, me.valueMax));
+                       clickValue = median(0, (pos.x - this.pressOffset - 0.5 * this.controlWidth) / (1 - this.textSpace - this.controlWidth), 1) * (this.valueMax - this.valueMin) + this.valueMin;
+                       inRange = (almost_in_bounds(this.valueMin, this.value, this.valueMax));
                        if (pos.x < controlCenter)
                        {
-                               pageValue = me.value - me.valuePageStep;
-                               if (me.valueStep) clickValue = floor(clickValue / me.valueStep) * me.valueStep;
+                               pageValue = this.value - this.valuePageStep;
+                               if (this.valueStep) clickValue = floor(clickValue / this.valueStep) * this.valueStep;
                                pageValue = max(pageValue, clickValue);
                        }
                        else
                        {
-                               pageValue = me.value + me.valuePageStep;
-                               if (me.valueStep) clickValue = ceil(clickValue / me.valueStep) * me.valueStep;
+                               pageValue = this.value + this.valuePageStep;
+                               if (this.valueStep) clickValue = ceil(clickValue / this.valueStep) * this.valueStep;
                                pageValue = min(pageValue, clickValue);
                        }
-                       if (inRange) me.setValue(me, median(me.valueMin, pageValue, me.valueMax));
-                       else me.setValue(me, me.valueMax);
-                       if(me.applyButton)
-                               me.applyButton.disabled = false;
+                       if (inRange) this.setValue(this, median(this.valueMin, pageValue, this.valueMax));
+                       else this.setValue(this, this.valueMax);
+                       if(this.applyButton)
+                               this.applyButton.disabled = false;
                        if (pageValue == clickValue)
                        {
-                               controlCenter = (me.value - me.valueMin) / (me.valueMax - me.valueMin) * (1 - me.textSpace - me.controlWidth) + 0.5 * me.controlWidth;
-                               me.pressed = 1;
-                               me.pressOffset = pos.x - controlCenter;
-                               me.previousValue = me.value;
-                               // me.mouseDrag(me, pos);
+                               controlCenter = (this.value - this.valueMin) / (this.valueMax - this.valueMin) * (1 - this.textSpace - this.controlWidth) + 0.5 * this.controlWidth;
+                               this.pressed = 1;
+                               this.pressOffset = pos.x - controlCenter;
+                               this.previousValue = this.value;
+                               // this.mouseDrag(this, pos);
                        }
                }
-               return 1;
+               return true;
        }
        float Slider_mouseRelease(entity me, vector pos)
        {
index 3b7327788c0d130afb230471b076b8b8262587e9..b70d3880bae819100350f8aba68ff240e8367158 100644 (file)
@@ -10,7 +10,7 @@ CLASS(Slider, Label)
        METHOD(Slider, draw, void(entity));
        METHOD(Slider, keyDown, float(entity, float, float, float));
        METHOD(Slider, keyUp, float(entity, float, float, float));
-       METHOD(Slider, mousePress, float(entity, vector));
+       METHOD(Slider, mousePress, bool(Slider this, vector pos));
        METHOD(Slider, mouseDrag, float(entity, vector));
        METHOD(Slider, mouseRelease, float(entity, vector));
        METHOD(Slider, valueToText, string(entity, float));
@@ -39,7 +39,7 @@ CLASS(Slider, Label)
        ATTRIB(Slider, pressed, float, 0);
        ATTRIB(Slider, pressOffset, float, 0);
        ATTRIB(Slider, previousValue, float, 0);
-       ATTRIB(Slider, tolerance, vector, '0 0 0');
+       ATTRIB(Slider, tolerance, vector, '0 0 0'); // drag tolerance
        ATTRIB(Slider, disabled, float, 0);
        ATTRIB(Slider, color, vector, '1 1 1');
        ATTRIB(Slider, color2, vector, '1 1 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 d5e1f82eba4ab0ece3d7fb7995ec4b7838c455a3..3889b341b795c1893c81afb2b43c15136c1053db 100644 (file)
@@ -274,5 +274,4 @@ SKINBEGIN
        SKINVECTOR(COLOR_SLIDER_D, '1 1 1');
        SKINVECTOR(COLOR_SLIDER_S, '1 1 1');
        SKINFLOAT(WIDTH_SLIDERTEXT, 0.333333333333);
-       SKINVECTOR(TOLERANCE_SLIDER, '0.2 2 0');
 SKINEND
index 577c8225803461225c818ce07f6cf396d1806f10..fd83718283928e45f0c77ad9d3af81cc62ad88d1 100644 (file)
@@ -98,6 +98,7 @@
 #include <menu/xonotic/rootdialog.qc>
 #include <menu/xonotic/screenshotimage.qc>
 #include <menu/xonotic/screenshotlist.qc>
+#include <menu/xonotic/scrollpanel.qc>
 #include <menu/xonotic/serverlist.qc>
 #include <menu/xonotic/skinlist.qc>
 #include <menu/xonotic/slider.qc>
index b6e34eff247606d774eb1d321fe9f7539071d3ff..f1644a2f5cfc0bb76657141f15d34dea80b340a8 100644 (file)
@@ -98,6 +98,7 @@
 #include <menu/xonotic/rootdialog.qh>
 #include <menu/xonotic/screenshotimage.qh>
 #include <menu/xonotic/screenshotlist.qh>
+#include <menu/xonotic/scrollpanel.qh>
 #include <menu/xonotic/serverlist.qh>
 #include <menu/xonotic/skinlist.qh>
 #include <menu/xonotic/slider.qh>
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 357276e16adf3794334eb7d640089b78350504ca..d8aedf69512a7349910fb0a0c6ba06e0009b6059 100644 (file)
@@ -16,10 +16,10 @@ void XonoticColorpicker_configureXonoticColorpicker(entity me, entity theTextbox
        me.configureImage(me, me.image);
 }
 
-float XonoticColorpicker_mousePress(entity me, vector coords)
+METHOD(XonoticColorpicker, mousePress, bool(XonoticColorpicker this, vector pos))
 {
-       me.mouseDrag(me, coords);
-       return 1;
+       this.mouseDrag(this, pos);
+       return true;
 }
 
 // must match hslimage.c
index b1c9d1e80ae566dd5a5dcddc8fb569f46bb3f3b3..149357dd9f2695065045d97edd6fb27be5b0d2ff 100644 (file)
@@ -3,7 +3,7 @@
 #include "../item/image.qh"
 CLASS(XonoticColorpicker, Image)
        METHOD(XonoticColorpicker, configureXonoticColorpicker, void(entity, entity));
-       METHOD(XonoticColorpicker, mousePress, float(entity, vector));
+       METHOD(XonoticColorpicker, mousePress, bool(XonoticColorpicker this, vector pos));
        METHOD(XonoticColorpicker, mouseRelease, float(entity, vector));
        METHOD(XonoticColorpicker, mouseDrag, float(entity, vector));
        ATTRIB(XonoticColorpicker, controlledTextbox, entity);
index 200204c00d131cc9fb3e62615215fd74a6577b1f..5a44e58830862c9e668185b3f21bda1bffadd076 100644 (file)
@@ -50,10 +50,10 @@ void XonoticColorpickerString_saveCvars(entity me)
                cvar_set(me.cvarName, sprintf("%v", hslimage_color(me.prevcoords, me.imagemargin)));
 }
 
-float XonoticColorpickerString_mousePress(entity me, vector coords)
+METHOD(XonoticColorpickerString, mousePress, bool(XonoticColorpickerString this, vector pos))
 {
-       me.mouseDrag(me, coords);
-       return 1;
+       this.mouseDrag(this, pos);
+       return true;
 }
 
 float XonoticColorpickerString_mouseDrag(entity me, vector coords)
index e990234b3f0a24779b9e3b40da6850b31299cd82..aa4a10c93a7d45a9583f4c8b57f671d135f20b81 100644 (file)
@@ -5,7 +5,7 @@
 #include "../item/image.qh"
 CLASS(XonoticColorpickerString, Image)
        METHOD(XonoticColorpickerString, configureXonoticColorpickerString, void(entity, string, string));
-       METHOD(XonoticColorpickerString, mousePress, float(entity, vector));
+       METHOD(XonoticColorpickerString, mousePress, bool(XonoticColorpickerString this, vector pos));
        METHOD(XonoticColorpickerString, mouseRelease, float(entity, vector));
        METHOD(XonoticColorpickerString, mouseDrag, float(entity, vector));
 
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..21e7ecadc454fdc7168a1e0c5314892f5d028749 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, ", ", _("Jetpack"));
        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"),
@@ -205,7 +209,7 @@ void XonoticMutatorsDialog_fill(entity me)
                        _("Players spawn with the grappling hook")));
        me.TR(me);
                me.TDempty(me, 0.2);
-               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_jetpack", _("Jet pack"),
+               me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "g_jetpack", _("Jetpack"),
                        _("Players spawn with the jetpack")));
        me.TR(me);
                me.TDempty(me, 0.2);
@@ -233,32 +237,38 @@ 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)
+               if ((j % 3) == 0)
+               {
                        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.2, 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 6f5ba8f57913e8ae5ba336c7f6a554001684890f..a9375327ec2e9735b2ea65db1e1632cc44edc5e1 100644 (file)
@@ -64,7 +64,7 @@ void XonoticEffectsSettingsTab_fill(entity me)
        me.gotoRC(me, 1.25, 0);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Geometry detail:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider_T("r_subdivisions_tolerance",
-                       _("Change the smoothness of the curves on the map (default: normal)")));
+                       _("Change the smoothness of the curves on the map")));
                        e.addValue(e, ZCTX(_("DET^Lowest")), "16");
                        e.addValue(e, ZCTX(_("DET^Low")), "8");
                        e.addValue(e, ZCTX(_("DET^Normal")), "4");
@@ -129,31 +129,31 @@ void XonoticEffectsSettingsTab_fill(entity me)
                {
                        me.TDempty(me, 0.2);
                        me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx_T(3, 0, "r_showsurfaces", _("Show surfaces"),
-                               _("Disable textures completely for very slow hardware. This gives a huge performance boost, but looks very ugly. (default: disabled)")));
+                               _("Disable textures completely for very slow hardware. This gives a huge performance boost, but looks very ugly.")));
                }
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(1, "mod_q3bsp_nolightmaps", _("Use lightmaps"),
-                       _("Use high resolution lightmaps, which will look pretty but use up some extra video memory (default: enabled)")));
+                       _("Use high resolution lightmaps, which will look pretty but use up some extra video memory")));
                        e.applyButton = effectsApplyButton;
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_glsl_deluxemapping", _("Deluxe mapping"),
-                       _("Use per-pixel lighting effects (default: enabled)")));
+                       _("Use per-pixel lighting effects")));
                        setDependentAND(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_shadow_gloss", _("Gloss"),
-                       _("Enable the use of glossmaps on textures supporting it (default: enabled)")));
+                       _("Enable the use of glossmaps on textures supporting it")));
                        setDependentAND3(e, "vid_gl20", 1, 1, "mod_q3bsp_nolightmaps", 0, 0, "r_glsl_deluxemapping", 1, 1);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_glsl_offsetmapping", _("Offset mapping"),
-                       _("Offset mapping effect that will make textures with bumpmaps appear like they \"pop out\" of the flat 2D surface (default: disabled)")));
+                       _("Offset mapping effect that will make textures with bumpmaps appear like they \"pop out\" of the flat 2D surface")));
                        setDependent(e, "vid_gl20", 1, 1);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_glsl_offsetmapping_reliefmapping", _("Relief mapping"),
-                       _("Higher quality offset mapping, which also has a huge impact on performance (default: disabled)")));
+                       _("Higher quality offset mapping, which also has a huge impact on performance")));
                        setDependentAND(e, "vid_gl20", 1, 1, "r_glsl_offsetmapping", 1, 1);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_water", _("Reflections:"),
-                       _("Reflection and refraction quality, has a huge impact on performance on maps with reflecting surfaces (default: disabled)")));
+                       _("Reflection and refraction quality, has a huge impact on performance on maps with reflecting surfaces")));
                        setDependent(e, "vid_gl20", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticTextSlider_T("r_water_resolutionmultiplier",
-                       _("Resolution of reflections/refractions (default: good)")));
+                       _("Resolution of reflections/refractions")));
                        e.addValue(e, _("Blurred"), "0.25");
                        e.addValue(e, ZCTX(_("REFL^Good")), "0.5");
                        e.addValue(e, _("Sharp"), "1");
@@ -161,7 +161,7 @@ void XonoticEffectsSettingsTab_fill(entity me)
                        setDependentAND(e, "vid_gl20", 1, 1, "r_water", 1, 1);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "cl_decals", _("Decals"),
-                       _("Enable decals (bullet holes and blood) (default: enabled)")));
+                       _("Enable decals (bullet holes and blood)")));
                me.TD(me, 1, 2, e = makeXonoticCheckBox(0, "cl_decals_models", _("Decals on models")));
                        setDependent(e, "cl_decals", 1, 1);
        me.TR(me);
@@ -169,14 +169,14 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
                        setDependent(e, "cl_decals", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 500, 20, "r_drawdecals_drawdistance",
-                       _("Decals further away than this will not be drawn (default: 300)")));
+                       _("Decals further away than this will not be drawn")));
                        setDependent(e, "cl_decals", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Time:")));
                        setDependent(e, "cl_decals", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(1, 20, 1, "cl_decals_fadetime",
-                       _("Time in seconds before decals fade away (default: 2)")));
+                       _("Time in seconds before decals fade away")));
                        setDependent(e, "cl_decals", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
@@ -189,42 +189,42 @@ void XonoticEffectsSettingsTab_fill(entity me)
 
        me.gotoRC(me, 1.25, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 3, e = makeXonoticRadioButton_T(1, "r_coronas", "0", _("No dynamic lighting"),
-                       _("Enable corona flares around certain lights (default: enabled)")));
+                       _("Enable corona flares around certain lights")));
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticRadioButton_T(1, "gl_flashblend", string_null, _("Fake corona lighting"),
-                       _("Enable faster but uglier dynamic lights by rendering bright coronas instead of real dynamic lights (default: disabled)")));
+                       _("Enable faster but uglier dynamic lights by rendering bright coronas instead of real dynamic lights")));
                makeMulti(e, "r_coronas");
        me.TR(me);
                me.TD(me, 1, 2, e = makeXonoticRadioButton_T(1, "r_shadow_realtime_dlight", string_null, _("Realtime dynamic lighting"),
-                       _("Enable rendering of dynamic lights such as explosions and rocket lights (default: enabled)")));
+                       _("Enable rendering of dynamic lights such as explosions and rocket lights")));
                makeMulti(e, "r_coronas");
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_shadow_realtime_dlight_shadows", _("Shadows"),
-                       _("Enable rendering of shadows from dynamic lights (default: disabled)")));
+                       _("Enable rendering of shadows from dynamic lights")));
                        setDependent(e, "r_shadow_realtime_dlight", 1, 1);
        me.TR(me);
                me.TD(me, 1, 2, e = makeXonoticCheckBox_T(0, "r_shadow_realtime_world", _("Realtime world lighting"),
-                       _("Enable rendering of full realtime world lighting on maps that support it. Note that this might have a big impact on performance. (default: disabled)")));
+                       _("Enable rendering of full realtime world lighting on maps that support it. Note that this might have a big impact on performance.")));
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_shadow_realtime_world_shadows", _("Shadows"),
-                       _("Enable rendering of shadows from realtime world lights (default: disabled)")));
+                       _("Enable rendering of shadows from realtime world lights")));
                        setDependent(e, "r_shadow_realtime_world", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 1.8, e = makeXonoticCheckBox_T(0, "r_shadow_usenormalmap", _("Use normal maps"),
-                       _("Enable use of directional shading on textures (default: enabled)")));
+                       _("Enable use of directional shading on textures")));
                        setDependentOR(e, "r_shadow_realtime_dlight", 1, 1, "r_shadow_realtime_world", 1, 1);
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "r_shadow_shadowmapping", _("Soft shadows")));
                        setDependentWeird(e, someShadowCvarIsEnabled);
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 2.8, e = makeXonoticCheckBox_T(0, "r_coronas_occlusionquery", _("Fade corona according to visibility"),
-                       _("Fade coronas according to visibility (default: enabled)")));
+                       _("Fade coronas according to visibility")));
                        setDependent(e, "r_coronas", 1, 1);
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticCheckBox_T(0, "r_bloom", _("Bloom"),
-                       _("Enable bloom effect, which brightens the neighboring pixels of very bright pixels. Has a big impact on performance. (default: disabled)")));
+                       _("Enable bloom effect, which brightens the neighboring pixels of very bright pixels. Has a big impact on performance.")));
                me.TD(me, 1, 2, e = makeXonoticCheckBoxEx_T(0.5, 0, "hud_postprocessing_maxbluralpha", _("Extra postprocessing effects"),
-                       _("Enables special postprocessing effects for when damaged or under water or using a powerup (default: disabled)")));
+                       _("Enables special postprocessing effects for when damaged or under water or using a powerup")));
                        makeMulti(e, "hud_powerup");
                        setDependent(e, "vid_gl20", 1, 1);
        me.TR(me);
@@ -246,14 +246,14 @@ void XonoticEffectsSettingsTab_fill(entity me)
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Quality:")));
                        setDependent(e, "cl_particles", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0, 3.0, 0.25, "cl_particles_quality",
-                       _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1.0)")));
+                       _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance")));
                        setDependent(e, "cl_particles", 1, 1);
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.8, e = makeXonoticTextLabel(0, _("Distance:")));
                        setDependent(e, "cl_particles", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(200, 3000, 200, "r_drawparticles_drawdistance",
-                       _("Particles further away than this will not be drawn (default: 1000)")));
+                       _("Particles further away than this will not be drawn")));
                        setDependent(e, "cl_particles", 1, 1);
 
        me.gotoRC(me, me.rows - 1, 0);
index d2ce368d1d0b225452230bfef96ff4770f540890..87134cb7812c15635247ec2799c21abf88c8a27e 100644 (file)
@@ -94,7 +94,9 @@ CONSTRUCTOR(XonoticRegisteredSettingsList, DataSource _source) {
 
 METHOD(XonoticGameSettingsTab, topicChangeNotify, void(entity, entity this))
 {
-    entity c = this.currentPanel;
+    entity s = this.currentPanel;
+    s.viewportHeight = 15.5;
+    entity c = s.currentPanel;
     entity removing = this.currentItem;
     DataSource data = this.topicList.source;
     entity adding = data.getEntry(data, this.topicList.selectedItem, func_null);
@@ -107,6 +109,7 @@ METHOD(XonoticGameSettingsTab, topicChangeNotify, void(entity, entity this))
         this.currentItem = adding;
         adding.resizeNotify(adding, '0 0 0', c.size, '0 0 0', c.size);
         c.addItem(c, adding, '0 0 0', '1 1 0', 1);
+               s.resizeNotify(s, '0 0 0', s.size, '0 0 0', s.size);
     }
 }
 METHOD(XonoticGameSettingsTab, fill, void(entity this))
index b9231642b18e9b016afb5277531a6e15fe1bea84..c9617f582f55fa01e9caefeb624cdbc54e9ae180 100644 (file)
@@ -32,13 +32,14 @@ CLASS(XonoticRegisteredSettingsList, XonoticListBox)
 ENDCLASS(XonoticRegisteredSettingsList)
 
 #include "tab.qh"
+#include "scrollpanel.qh"
 CLASS(XonoticGameSettingsTab, XonoticTab)
        ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameSettingsTab, columns, float, 6.5);
        ATTRIB(XonoticGameSettingsTab, source, DataSource, NEW(SettingSource));
        ATTRIB(XonoticGameSettingsTab, topicList, entity, NEW(XonoticRegisteredSettingsList, this.source));
-       ATTRIB(XonoticGameSettingsTab, currentPanel, entity, NEW(XonoticTab));
+       ATTRIB(XonoticGameSettingsTab, currentPanel, entity, NEW(XonoticScrollPanel));
        ATTRIB(XonoticGameSettingsTab, currentItem, entity);
        METHOD(XonoticGameSettingsTab, topicChangeNotify, void(entity, entity this));
        METHOD(XonoticGameSettingsTab, fill, void(entity this));
index e16693675b91cafa32da4601b4436a30e0698626..88fba8dd0250345442b73809800aeb9eb46f708d 100644 (file)
@@ -88,6 +88,10 @@ void XonoticGameHUDSettingsTab_fill(entity me)
                me.TDempty(me, 0.2);
                me.TD(me, 1, 2.8, e = makeXonoticCheckBoxEx(0.25, 1, "g_waypointsprite_crosshairfadealpha", _("Fade when near the crosshair")));
                        setDependent(e, "cl_hidewaypoints", 0, 0);
+       me.TR(me);
+               me.TDempty(me, 0.2);
+               me.TD(me, 1, 2.8, e = makeXonoticCheckBox(0, "g_waypointsprite_text", _("Display names instead of icons")));
+                       setDependent(e, "cl_hidewaypoints", 0, 0);
 
        #if 0
        me.TR(me);
index 2f5d795867844c5ab011970bf2bb4c32edc7a145..c1caddd7d4def04098368961477a35ba6eaa1e90 100644 (file)
@@ -69,7 +69,7 @@ void XonoticGameViewSettingsTab_fill(entity me)
        me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(60, 130, 5, "fov",
-                       _("Field of vision in degrees (default: 100)")));
+                       _("Field of vision in degrees")));
        me.TR(me);
        me.TR(me);
                //me.TDempty(me, 0.2);
index d3ba0e4206f92cc453f4ec32b9aad91123a6f43f..c0d064a7daf865256118cd52311fa3b75033cdf6 100644 (file)
@@ -13,7 +13,7 @@ void XonoticResetDialog_fill(entity me)
                me.TD(me, 1, 2, makeXonoticTextLabel(0.5, _("This will create a backup config in your data directory")));
        me.TR(me);
        me.TR(me);
-               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "saveconfig backup.cfg\n;\n exec defaultXonotic.cfg\n", 0));
+               me.TD(me, 1, 1, e = makeXonoticCommandButton(_("Yes"), '1 0 0', "saveconfig backup.cfg\n;\n exec default.cfg\n", 0));
                me.TD(me, 1, 1, e = makeXonoticButton(_("No"), '0 1 0'));
                        e.onClick = Dialog_Close;
                        e.onClickEntity = me;
index fc6521c4d2b9a7bd03e9b567ceecb9dd6f9247d2..27d6d4a82ec3a143f93ececce635ac37fba1892e 100644 (file)
@@ -72,7 +72,7 @@ void XonoticUserSettingsTab_fill(entity me)
 
        me.gotoRC(me, 11.5, 3.25); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 2.5, e = makeXonoticCheckBox_T(0, "cl_gentle", _("Disable gore effects and harsh language"),
-                       _("Replace blood and gibs with content that does not have any gore effects (default: disabled)")));
+                       _("Replace blood and gibs with content that does not have any gore effects")));
                        e.applyButton = userApplyButton;
 
        me.gotoRC(me, me.rows - 1, 0);
index 8ee51fde97405b4a424ff79f699c3fd6ded25684..0e524b6e23852cedf80e6c5c3e66e3841ac430ef 100644 (file)
@@ -59,18 +59,18 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticCheckBox(0, "vid_fullscreen", _("Full screen")));
                        e.applyButton = videoApplyButton;
                me.TD(me, 1, 2, e = makeXonoticCheckBox_T(0, "vid_vsync", _("Vertical Synchronization"),
-                       _("Enable vertical synchronization to prevent tearing, will cap your fps to the screen refresh rate (default: disabled)")));
+                       _("Enable vertical synchronization to prevent tearing, will cap your fps to the screen refresh rate")));
 
        me.TR(me);
                if(cvar("developer"))
                {
                        me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "v_flipped", _("Flip view horizontally"),
-                               _("Poor man's left handed mode (default: off)")));
+                               _("Poor man's left handed mode")));
                }
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Anisotropy:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider_T("gl_texture_anisotropy",
-                       _("Anisotropic filtering quality (default: 1x)")));
+                       _("Anisotropic filtering quality")));
                        e.addValue(e, ZCTX(_("ANISO^Disabled")), "1");
                        e.addValue(e, _("2x"), "2");
                        e.addValue(e, _("4x"), "4");
@@ -81,7 +81,7 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Antialiasing:")));
                        setDependent(e, "r_viewfbo", 0, 0);
                me.TD(me, 1, 2, e = makeXonoticTextSlider_T("vid_samples",
-                       _("Enable antialiasing, which smooths the edges of 3D geometry. Note that it might decrease performance by quite a lot (default: disabled)")));
+                       _("Enable antialiasing, which smooths the edges of 3D geometry. Note that it might decrease performance by quite a lot")));
                        e.addValue(e, ZCTX(_("AA^Disabled")), "1");
                        e.addValue(e, _("2x"), "2");
                        e.addValue(e, _("4x"), "4");
@@ -96,7 +96,7 @@ void XonoticVideoSettingsTab_fill(entity me)
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Depth first:")));
                me.TD(me, 1, 2, e = makeXonoticTextSlider_T("r_depthfirst",
-                       _("Eliminate overdraw by rendering a depth-only version of the scene before the normal rendering starts (default: disabled)")));
+                       _("Eliminate overdraw by rendering a depth-only version of the scene before the normal rendering starts")));
                        e.addValue(e, ZCTX(_("DF^Disabled")), "0");
                        e.addValue(e, ZCTX(_("DF^World")), "1");
                        e.addValue(e, ZCTX(_("DF^All")), "2");
@@ -107,60 +107,60 @@ void XonoticVideoSettingsTab_fill(entity me)
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.9, e = makeXonoticRadioButton(1, "gl_vbo", "0", ZCTX(_("VBO^Off"))));
                me.TD(me, 1, 1.9, e = makeXonoticRadioButton_T(1, "gl_vbo", "3", _("Vertices, some Tris (compatible)"),
-                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering (default: Vertex and Triangles)")));
+                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering")));
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 0.9, e = makeXonoticRadioButton_T(1, "gl_vbo", "2", _("Vertices"),
-                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering (default: Vertex and Triangles)")));
+                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering")));
                me.TD(me, 1, 1.9, e = makeXonoticRadioButton_T(1, "gl_vbo", "1", _("Vertices and Triangles"),
-                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering (default: Vertex and Triangles)")));
+                       _("Make use of Vertex Buffer Objects to store static geometry in video memory for faster rendering")));
 
        me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Brightness:")));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0.0, 0.5, 0.02, "v_brightness",
-                       _("Brightness of black (default: 0)")));
+                       _("Brightness of black")));
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast:")));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(1.0, 3.0, 0.05, "v_contrast",
-                       _("Brightness of white (default: 1)")));
+                       _("Brightness of white")));
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Gamma:")));
                        setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0.5, 2.0, 0.05, "v_gamma",
-                       _("Inverse gamma correction value, a brightness effect that does not affect white or black (default: 1.125)")));
+                       _("Inverse gamma correction value, a brightness effect that does not affect white or black")));
                        setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Contrast boost:")));
                        setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(1.0, 5.0, 0.1, "v_contrastboost",
-                       _("By how much to multiply the contrast in dark areas (default: 1)")));
+                       _("By how much to multiply the contrast in dark areas")));
                        setDependentAND(e, "vid_gl20", 1, 1, "v_glslgamma", 1, 1);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Saturation:")));
                        setDependent(e, "vid_gl20", 1, 1);
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0.5, 2.0, 0.05, "r_glsl_saturation",
-                       _("Saturation adjustment (0 = grayscale, 1 = normal, 2 = oversaturated), requires GLSL color control (default: 1)")));
+                       _("Saturation adjustment (0 = grayscale, 1 = normal, 2 = oversaturated), requires GLSL color control")));
                        setDependent(e, "vid_gl20", 1, 1);
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, ZCTX(_("LIT^Ambient:"))));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0, 20.0, 0.25, "r_ambient",
-                       _("Ambient lighting, if set too high it tends to make light on maps look dull and flat (default: 4)")));
+                       _("Ambient lighting, if set too high it tends to make light on maps look dull and flat")));
        me.TR(me);
                me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Intensity:")));
                me.TD(me, 1, 2, e = makeXonoticSlider_T(0.5, 2.0, 0.05, "r_hdr_scenebrightness",
-                       _("Global rendering brightness (default: 1)")));
+                       _("Global rendering brightness")));
        me.TR(me);
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "gl_finish", _("Wait for GPU to finish each frame"),
-                       _("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)")));
+                       _("Make the CPU wait for the GPU to finish each frame, can help with some strange input or video lag on some machines")));
        me.TR(me);
                me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "vid_gl20", _("Use OpenGL 2.0 shaders (GLSL)")));
                        e.applyButton = videoApplyButton;
        me.TR(me);
                me.TDempty(me, 0.2);
                me.TD(me, 1, 2.8, e = makeXonoticCheckBox_T(0, "v_glslgamma", _("Use GLSL to handle color control"),
-                       _("Enable use of GLSL to apply gamma correction, note that it might decrease performance by a lot (default: disabled)")));
+                       _("Enable use of GLSL to apply gamma correction, note that it might decrease performance by a lot")));
                        setDependent(e, "vid_gl20", 1, 1);
        if(cvar("developer"))
        {
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..a14406bcec7202aa518df979bcb29f619f5c90a3 100644 (file)
@@ -34,7 +34,7 @@ void Xonotic_KeyBinds_Read()
        KEYBIND_DEF("+jump"                                 , _("jump / swim"));
        KEYBIND_DEF("+crouch"                               , _("crouch / sink"));
        KEYBIND_DEF("+hook"                                 , _("off-hand hook"));
-       KEYBIND_DEF("+jetpack"                              , _("jet pack"));
+       KEYBIND_DEF("+jetpack"                              , _("jetpack"));
        KEYBIND_DEF(""                                      , "");
        KEYBIND_DEF(""                                      , _("Attacking"));
        KEYBIND_DEF("+fire"                                 , _("primary fire"));
@@ -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 14272cb19ba9f8e6db66f2a309daf000430adc10..b6ad4af100ca132d4d90532ec11a56a9ca24df77 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticListBox, ListBox)
        ATTRIB(XonoticListBox, fontSize, float, SKINFONTSIZE_NORMAL);
        ATTRIB(XonoticListBox, scrollbarWidth, float, SKINWIDTH_SCROLLBAR);
        ATTRIB(XonoticListBox, src, string, SKINGFX_SCROLLBAR);
-       ATTRIB(XonoticListBox, tolerance, vector, SKINTOLERANCE_SLIDER);
+       ATTRIB(XonoticListBox, tolerance, vector, '2 0.2 0');
        ATTRIB(XonoticListBox, rowsPerItem, float, 1);
        METHOD(XonoticListBox, resizeNotify, void(entity, vector, vector, vector, vector));
        ATTRIB(XonoticListBox, color, vector, SKINCOLOR_SCROLLBAR_N);
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 db302e9a8ca11b435bd9e6b2e7c006fcc05268b8..527697683218d87a2550f862ddd36b2a3dd67299 100644 (file)
@@ -39,17 +39,17 @@ float XonoticPicker_mouseDrag(entity me, vector coords)
        return me.mouseMove(me, coords);
 }
 
-float XonoticPicker_mousePress(entity me, vector coords)
+METHOD(XonoticPicker, mousePress, bool(XonoticPicker this, vector pos))
 {
-       me.mouseMove(me, coords);
+       this.mouseMove(this, pos);
 
-       if(me.focusedCell.x >= 0)
+       if(this.focusedCell.x >= 0)
        {
-               me.pressed = 1;
-               me.pressedCell = me.focusedCell;
+               this.pressed = 1;
+               this.pressedCell = this.focusedCell;
        }
 
-       return 1;
+       return true;
 }
 
 float XonoticPicker_mouseRelease(entity me, vector coords)
index b8e19cf19ebaedf19a3fcb0f440f877ae3006012..c98e9fc9b6fa8f082a3bd346dad51c48edd36048 100644 (file)
@@ -3,7 +3,7 @@
 #include "../item.qh"
 CLASS(XonoticPicker, Item)
        METHOD(XonoticPicker, configureXonoticPicker, void(entity));
-       METHOD(XonoticPicker, mousePress, float(entity, vector));
+       METHOD(XonoticPicker, mousePress, bool(XonoticPicker this, vector pos));
        METHOD(XonoticPicker, mouseRelease, float(entity, vector));
        METHOD(XonoticPicker, mouseMove, float(entity, vector));
        METHOD(XonoticPicker, mouseDrag, float(entity, vector));
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 42e168b4b58b2617d5978b7bce289bd8ac4a8131..af987e7b58c9ab78491ef7829a8e57a1885842f5 100644 (file)
@@ -19,17 +19,15 @@ 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);
 }
 
-float XonoticScreenshotImage_mousePress(entity me, vector coords)
+METHOD(XonoticScreenshotImage, mousePress, bool(XonoticScreenshotImage this, vector pos))
 {
-       return me.drag_setStartPos(me, coords);
+       return this.drag_setStartPos(this, pos);
 }
 
 float XonoticScreenshotImage_mouseDrag(entity me, vector coords)
index 8920bed287f50fceed2527f56646d36a8599f812..c27a853377ce51eb18270adb6c7197e4811fb2e9 100644 (file)
@@ -6,7 +6,7 @@ CLASS(XonoticScreenshotImage, XonoticImage)
        METHOD(XonoticScreenshotImage, load, void(entity, string));
        METHOD(XonoticScreenshotImage, draw, void(entity));
        ATTRIB(XonoticScreenshotImage, focusable, float, 1);  // mousePress and mouseDrag work only if focusable is set
-       METHOD(XonoticScreenshotImage, mousePress, float(entity, vector));
+       METHOD(XonoticScreenshotImage, mousePress, bool(XonoticScreenshotImage this, vector pos));
        METHOD(XonoticScreenshotImage, mouseDrag, float(entity, vector));
        METHOD(XonoticScreenshotImage, mouseMove, float(entity, vector));
        METHOD(XonoticScreenshotImage, resizeNotify, void(entity, vector, vector, vector, vector));
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);
 }
diff --git a/qcsrc/menu/xonotic/scrollpanel.qc b/qcsrc/menu/xonotic/scrollpanel.qc
new file mode 100644 (file)
index 0000000..4543f0b
--- /dev/null
@@ -0,0 +1,46 @@
+#include "scrollpanel.qh"
+
+METHOD(XonoticScrollPanel, drawListBoxItem, void(XonoticScrollPanel this, int i, vector absSize, bool isSelected, bool isFocused))
+{
+       XonoticTab p = this.currentPanel;
+       p.draw(p);
+}
+
+METHOD(XonoticScrollPanel, resizeNotify, void(XonoticScrollPanel this, vector relOrigin, vector relSize, vector absOrigin, vector absSize))
+{
+       SUPER(XonoticScrollPanel).resizeNotify(this, relOrigin, relSize, absOrigin, absSize);
+       this.scrollToItem(this, 0);
+       XonoticTab p = this.currentPanel;
+       float m = p.firstChild.rows / this.viewportHeight;
+       this.itemHeight = m;
+       relSize.y *= m;
+       absSize.y *= m;
+       p.resizeNotify(p, relOrigin, relSize, absOrigin, absSize);
+}
+
+#define X(mouseFunc) \
+METHOD(XonoticScrollPanel, mouseFunc, bool(XonoticScrollPanel this, vector pos)) \
+{ \
+       SUPER(XonoticScrollPanel).mouseFunc(this, pos); \
+       XonoticTab p = this.currentPanel; \
+       this.setFocus(this, p); \
+       \
+       vector o = -eY * this.scrollPos; \
+       vector s = eX * (1 - this.controlWidth) + eY * this.itemHeight; \
+       return p.mouseFunc(p, globalToBox(pos, o, s)); \
+}
+X(mouseMove)
+X(mousePress)
+X(mouseDrag)
+X(mouseRelease)
+#undef X
+
+#define X(keyFunc) \
+METHOD(XonoticScrollPanel, keyFunc, bool(XonoticScrollPanel this, int key, int ascii, bool shift)) \
+{ \
+       XonoticTab p = this.currentPanel; \
+       return p.keyFunc(p, key, ascii, shift) || SUPER(XonoticScrollPanel).keyFunc(this, key, ascii, shift); \
+}
+X(keyDown)
+X(keyUp)
+#undef X
diff --git a/qcsrc/menu/xonotic/scrollpanel.qh b/qcsrc/menu/xonotic/scrollpanel.qh
new file mode 100644 (file)
index 0000000..f675e86
--- /dev/null
@@ -0,0 +1,24 @@
+#pragma once
+
+#include "listbox.qh"
+#include "tab.qh"
+CLASS(XonoticScrollPanel, XonoticListBox)
+       /** container for single child panel */
+       ATTRIB(XonoticScrollPanel, currentPanel, entity, NEW(XonoticTab));
+       ATTRIB(XonoticScrollPanel, nItems, int, 1);
+       ATTRIB(XonoticScrollPanel, selectionDoesntMatter, bool, true);
+       ATTRIB(XonoticScrollPanel, itemHeight, float, 1);
+       /** number of rows to show at once */
+       ATTRIB(XonoticScrollPanel, viewportHeight, float, 12);
+       ATTRIB(XonoticScrollPanel, alphaBG, float, 0);
+
+       METHOD(XonoticScrollPanel, getItemAtPos, float(XonoticScrollPanel this, float pos)) { return 0; }
+       METHOD(XonoticScrollPanel, getItemHeight, float(XonoticScrollPanel this, int i)) { return this.itemHeight; }
+       METHOD(XonoticScrollPanel, getItemStart, float(XonoticScrollPanel this, int i)) { return 0; }
+       METHOD(XonoticScrollPanel, getTotalHeight, float(XonoticScrollPanel this)) { return this.itemHeight; }
+       METHOD(XonoticScrollPanel, setFocus, void(XonoticScrollPanel this, entity other)) { Container_setFocus(this, other); }
+       METHOD(XonoticScrollPanel, setSelected, void(XonoticScrollPanel this, int i)) { }
+
+       METHOD(XonoticScrollPanel, drawListBoxItem, void(XonoticScrollPanel this, int i, vector absSize, bool isSelected, bool isFocused));
+       METHOD(XonoticScrollPanel, resizeNotify, void(XonoticScrollPanel this, vector relOrigin, vector relSize, vector absOrigin, vector absSize));
+ENDCLASS(XonoticScrollPanel)
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 9204c5eb35b501481d2be533c53c361b18b10245..fea35745896a6a71f3773fd22becebe0e0f59627 100644 (file)
@@ -8,7 +8,7 @@ CLASS(XonoticSlider, Slider)
        ATTRIB(XonoticSlider, fontSize, float, SKINFONTSIZE_NORMAL);
        ATTRIB(XonoticSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT);
        ATTRIB(XonoticSlider, image, string, SKINGFX_SLIDER);
-       ATTRIB(XonoticSlider, tolerance, vector, SKINTOLERANCE_SLIDER);
+       ATTRIB(XonoticSlider, tolerance, vector, '0.2 2 0');
        ATTRIB(XonoticSlider, align, float, 0.5);
        ATTRIB(XonoticSlider, color, vector, SKINCOLOR_SLIDER_N);
        ATTRIB(XonoticSlider, colorC, vector, SKINCOLOR_SLIDER_C);
index 3a89b00a7b21a5cf102a93d951c2e685e8b4e120..72639fcb1ca93ddd504d34c262d3a5d8854ace78 100644 (file)
@@ -10,7 +10,7 @@ entity makeXonoticParticlesSlider()
 void XonoticParticlesSlider_configureXonoticParticlesSlider(entity me)
 {
        me.configureXonoticTextSlider(me, "cl_particles_quality",
-               _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance (default: 1)"));
+               _("Multiplier for amount of particles. Less means less particles, which in turn gives for better performance"));
        if(cvar("developer")) { me.addValue(me, ZCTX(_("PART^OMG")),      "0.25 250 0"); }
        me.addValue(me,                         ZCTX(_("PART^Low")),      "0.5 500 0");
        me.addValue(me,                         ZCTX(_("PART^Medium")),   "0.75 750 0");
index c6b7c1e8cc7b5cbaaace86d9bb4cd5fedd8b4e06..c0b03af57df5afea037fda43c2953ad794ed596b 100644 (file)
@@ -10,7 +10,7 @@ entity makeXonoticPicmipSlider()
 void XonoticPicmipSlider_configureXonoticPicmipSlider(entity me)
 {
        me.configureXonoticTextSlider(me, "gl_picmip",
-               _("Change the sharpness of the textures. Lowering it will effectively reduce texture memory usage, but make the textures appear very blurry. (default: good)"));
+               _("Change the sharpness of the textures. Lowering it will effectively reduce texture memory usage, but make the textures appear very blurry."));
        me.autofix(me);
        me.have_s3tc = GL_Have_TextureCompression();
 }
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 3e94738a9ab500d89a162003be58ef67106e49f0..401a6eadda0026b5f7e2b6533c40352c597961ea 100644 (file)
@@ -100,21 +100,21 @@ void XonoticStatsList_getStats(entity me)
                        case "overall/last_seen_dt":
                        {
                                order = 1;
-                               outstr = _("Last_Seen:");
+                               outstr = _("Last match:");
                                data = XonoticStatsList_convertDate(car(data));
                                break;
                        }
                        case "overall/alivetime":
                        {
                                order = 1;
-                               outstr = _("Time_Played:");
+                               outstr = _("Time played:");
                                data = process_time(3, stof(data));
                                break;
                        }
                        case "overall/favorite-map":
                        {
                                order = 2;
-                               outstr = _("Favorite_Map:");
+                               outstr = _("Favorite map:");
                                data = car(data);
                                break;
                        }
@@ -146,13 +146,13 @@ void XonoticStatsList_getStats(entity me)
 
                if((order == -1) && (out_total_matches >= 0) && (out_total_wins >= 0))
                {
-                       bufstr_add(me.listStats, sprintf("003Matches: %d", out_total_matches), true);
+                       bufstr_add(me.listStats, sprintf("003%s\n%d", _("Matches:"), out_total_matches), true);
 
                        if(out_total_matches > 0) // don't show extra info if there are no matches played
                        {
                                out_total_losses = max(0, (out_total_matches - out_total_wins));
-                               bufstr_add(me.listStats, sprintf("003Wins/Losses: %d/%d", out_total_wins, out_total_losses), true);
-                               bufstr_add(me.listStats, sprintf("004Win_Percentage: %d%%", ((out_total_wins / out_total_matches) * 100)), true);
+                               bufstr_add(me.listStats, sprintf("003%s\n%d/%d", _("Wins/Losses:"), out_total_wins, out_total_losses), true);
+                               bufstr_add(me.listStats, sprintf("004%s\n%d%%", _("Win percentage:"), ((out_total_wins / out_total_matches) * 100)), true);
                        }
 
                        out_total_matches = -1;
@@ -163,13 +163,13 @@ void XonoticStatsList_getStats(entity me)
 
                if((order == -1) && (out_total_kills >= 0) && (out_total_deaths >= 0))
                {
-                       bufstr_add(me.listStats, sprintf("005Kills/Deaths: %d/%d", out_total_kills, out_total_deaths), true);
+                       bufstr_add(me.listStats, sprintf("005%s\n%d/%d", _("Kills/Deaths:"), out_total_kills, out_total_deaths), true);
 
                        // if there are no deaths, just show kill count
-                       if(out_total_deaths > 0)
-                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", (out_total_kills / out_total_deaths)), true);
-                       else
-                               bufstr_add(me.listStats, sprintf("006Kill_Ratio: %.2f", out_total_kills), true);
+                       if(out_total_deaths == 0)
+                               out_total_deaths = 1;
+
+                       bufstr_add(me.listStats, sprintf("006%s\n%.2f", _("Kill ratio:"), (out_total_kills / out_total_deaths)), true);
 
                        out_total_kills = -1;
                        out_total_deaths = -1;
@@ -198,28 +198,27 @@ void XonoticStatsList_getStats(entity me)
                                        case "matches":
                                        {
                                                order = 1;
-                                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
-                                               //data = sprintf(_("%d (unranked)"), data);
+                                               outstr = _("Matches:");
                                                break;
                                        }
                                        case "elo":
                                        {
                                                order = 2;
-                                               outstr = sprintf(_("%s_ELO:"), strtoupper(gametype));
+                                               outstr = _("ELO:");
                                                data = sprintf("%d", stof(data));
                                                break;
                                        }
                                        case "rank":
                                        {
                                                order = 3;
-                                               outstr = sprintf(_("%s_Rank:"), strtoupper(gametype));
+                                               outstr = _("Rank:");
                                                data = sprintf("%d", stof(data));
                                                break;
                                        }
                                        case "percentile":
                                        {
                                                order = 4;
-                                               outstr = sprintf(_("%s_Percentile:"), strtoupper(gametype));
+                                               outstr = _("Percentile:");
                                                data = sprintf("%d%%", stof(data));
                                                break;
                                        }
@@ -228,8 +227,7 @@ void XonoticStatsList_getStats(entity me)
                                        case "favorite-map":
                                        {
                                                order = 5;
-                                               outstr = sprintf(_("%s_Favorite_Map:"), strtoupper(gametype));
-                                               //data = sprintf(_("%d (unranked)"), data);
+                                               outstr = _("Favorite map:");
                                                break;
                                        }
                                        #endif
@@ -237,12 +235,14 @@ void XonoticStatsList_getStats(entity me)
                                        default: continue; // nothing to see here
                                }
 
+                               outstr = strcat(strtoupper(gametype), " ", outstr);
                                // now set up order for sorting later
                                orderstr = sprintf("%2.2s%d", gametype, order);
                        }
                        else if(event == "matches")
                        {
-                               outstr = sprintf(_("%s_Matches:"), strtoupper(gametype));
+                               outstr = _("Matches:");
+                               outstr = strcat(strtoupper(gametype), " ", outstr);
                                data = sprintf(_("%d (unranked)"), stof(data));
 
                                // unranked game modes ALWAYS get put last
@@ -251,7 +251,7 @@ void XonoticStatsList_getStats(entity me)
                        else { continue; }
                }
 
-               bufstr_add(me.listStats, sprintf("%s%s %s", orderstr, outstr, data), true);
+               bufstr_add(me.listStats, sprintf("%s%s\n%s", orderstr, outstr, data), true);
        }
 
        me.nItems = buf_getsize(me.listStats);
@@ -294,14 +294,13 @@ void XonoticStatsList_drawListBoxItem(entity me, int i, vector absSize, bool isS
        }
 
        string data = bufstr_get(me.listStats, i);
-       string s = car(data);
-       string d = cdr(data);
+       int ofs = strstrofs(data, "\n", 0);
 
-       s = substring(s, 3, strlen(s) - 3);
-       s = strreplace("_", " ", s);
+       string s = substring(data, 3, ofs - 3);
        s = draw_TextShortenToWidth(s, 0.5 * me.columnNameSize, 0, me.realFontSize);
        draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
 
+       string d = substring(data, ofs + 1, strlen(data) - (ofs + 1));
        d = draw_TextShortenToWidth(d, me.columnNameSize - draw_TextWidth(s, 0, me.realFontSize), 0, me.realFontSize);
        draw_Text(me.realUpperMargin * eY + (me.columnNameOrigin + 1 * (me.columnNameSize - draw_TextWidth(d, 0, me.realFontSize))) * eX, d, me.realFontSize, '1 1 1', SKINALPHA_TEXT, 1);
 }
index 58fe8e86bbe4a0becaac10ea463fe493f50b2d72..3c588ce55000415a1aa1a5688e0199b2bdce32f8 100644 (file)
@@ -9,7 +9,7 @@ CLASS(XonoticTextSlider, TextSlider)
        ATTRIB(XonoticTextSlider, fontSize, float, SKINFONTSIZE_NORMAL);
        ATTRIB(XonoticTextSlider, valueSpace, float, SKINWIDTH_SLIDERTEXT);
        ATTRIB(XonoticTextSlider, image, string, SKINGFX_SLIDER);
-       ATTRIB(XonoticTextSlider, tolerance, vector, SKINTOLERANCE_SLIDER);
+       ATTRIB(XonoticTextSlider, tolerance, vector, '0.2 2 0');
        ATTRIB(XonoticTextSlider, align, float, 0.5);
        ATTRIB(XonoticTextSlider, color, vector, SKINCOLOR_SLIDER_N);
        ATTRIB(XonoticTextSlider, colorC, vector, SKINCOLOR_SLIDER_C);
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..a4cb8bd5e1c5779b2274a01448ceeb39a689c867 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>
@@ -19,7 +16,6 @@
 #include <server/matrix.qc>
 #include <server/miscfunctions.qc>
 #include <server/player.qc>
-#include <server/playerdemo.qc>
 #include <server/portals.qc>
 #include <server/race.qc>
 #include <server/resources.qc>
index 2013fd6bb5db5c521737cf0985fc65c13a43846e..0a00d680786fa51c84701339d0b9f82fe01000aa 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>
@@ -19,7 +16,6 @@
 #include <server/matrix.qh>
 #include <server/miscfunctions.qh>
 #include <server/player.qh>
-#include <server/playerdemo.qh>
 #include <server/portals.qh>
 #include <server/race.qh>
 #include <server/resources.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 80da3f403ac97c025274b109d1ede8f5c8c8ea83..7d73a73a8b7e65086756c1e261a1b9edcacd3b90 100644 (file)
@@ -79,6 +79,7 @@ float autocvar_g_balance_pause_health_rot_spawn;
 float autocvar_g_balance_portal_health;
 float autocvar_g_balance_portal_lifetime;
 float autocvar_g_balance_powerup_invincible_takedamage;
+float autocvar_g_balance_powerup_invincible_takeforce = 0.33;
 //float autocvar_g_balance_powerup_invincible_time;
 float autocvar_g_balance_powerup_strength_damage;
 float autocvar_g_balance_powerup_strength_force;
@@ -166,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;
@@ -203,8 +204,6 @@ bool autocvar_g_respawn_ghosts;
 float autocvar_g_respawn_ghosts_maxtime;
 float autocvar_g_respawn_ghosts_speed;
 int autocvar_g_respawn_waves;
-bool autocvar_g_shootfromcenter;
-bool autocvar_g_shootfromeye;
 string autocvar_g_shootfromfixedorigin;
 int autocvar_g_showweaponspawns;
 bool autocvar_g_spawn_alloweffects;
@@ -241,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;
@@ -257,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;
@@ -324,9 +323,6 @@ string autocvar_sv_motd;
 bool autocvar_sv_precacheplayermodels;
 //float autocvar_sv_precacheweapons; // WEAPONTODO?
 bool autocvar_sv_q3acompat_machineshotgunswap;
-bool autocvar_sv_ready_restart;
-bool autocvar_sv_ready_restart_after_countdown;
-bool autocvar_sv_ready_restart_repeatable;
 bool autocvar_sv_servermodelsonly;
 int autocvar_sv_spectate;
 float autocvar_sv_spectator_speed_multiplier;
@@ -474,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..08d16a71f091dcf626eeae7ae918cb825c8da8e6 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"
 
@@ -74,12 +74,6 @@ void bot_think(entity this)
 
        this.bot_nextthink = max(time, this.bot_nextthink) + max(0.01, autocvar_bot_ai_thinkinterval * (0.5 ** this.bot_aiskill) * min(14 / (skill + 14), 1));
 
-       //if (this.bot_painintensity > 0)
-       //      this.bot_painintensity = this.bot_painintensity - (skill + 1) * 40 * frametime;
-
-       //this.bot_painintensity = this.bot_painintensity + this.bot_oldhealth - this.health;
-       //this.bot_painintensity = bound(0, this.bot_painintensity, 100);
-
        if (!IS_PLAYER(this) || (autocvar_g_campaign && !campaign_bots_may_start))
        {
                CS(this).movement = '0 0 0';
@@ -255,16 +249,23 @@ void bot_setnameandstuff(entity this)
                name = bot_name;
 
        // number bots with identical names
-       int j = 0;
-       FOREACH_CLIENT(IS_BOT_CLIENT(it), {
-               if(it.cleanname == name)
-                       ++j;
-       });
-       if (j)
-               this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
-       else
+       if (name == "")
+       {
+               name = ftos(etof(this));
                this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
-
+       }
+       else
+       {
+               int j = 0;
+               FOREACH_CLIENT(IS_BOT_CLIENT(it), {
+                       if(it.cleanname == name)
+                               ++j;
+               });
+               if (j)
+                       this.netname = this.netname_freeme = strzone(strcat(prefix, name, "(", ftos(j), ")", suffix));
+               else
+                       this.netname = this.netname_freeme = strzone(strcat(prefix, name, suffix));
+       }
        this.cleanname = strzone(name);
 
        // pick the model and skin
@@ -396,18 +397,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..357b37da00337b99e929787cafda0741674ce1e3 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;
@@ -500,7 +500,7 @@ void havocbot_movetogoal(entity this)
        // Jetpack navigation
        if(this.navigation_jetpack_goal)
        if(this.goalcurrent==this.navigation_jetpack_goal)
-       if(this.ammo_fuel)
+       if(GetResourceAmount(this, RESOURCE_FUEL))
        {
                if(autocvar_bot_debug_goalstack)
                {
@@ -525,13 +525,13 @@ void havocbot_movetogoal(entity this)
                {
                        // Calculate brake distance in xy
                        float d = vlen(vec2(this.origin - (this.goalcurrent.absmin + this.goalcurrent.absmax) * 0.5));
-                       float v = vlen(vec2(this.velocity));
-                       float db = ((v ** 2) / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
+                       float vel2 = vlen2(vec2(this.velocity));
+                       float db = (vel2 / (autocvar_g_jetpack_acceleration_side * 2)) + 100;
                        //LOG_INFOF("distance %d, velocity %d, brake at %d ", ceil(d), ceil(v), ceil(db));
                        if(d < db || d < 500)
                        {
                                // Brake
-                               if(v > maxspeed * 0.3)
+                               if (vel2 > (maxspeed * 0.3) ** 2)
                                {
                                        CS(this).movement_x = dir * v_forward * -maxspeed;
                                        return;
@@ -695,7 +695,7 @@ void havocbot_movetogoal(entity this)
 
                        return;
                }
-               else if(this.health + this.armorvalue > ROCKETJUMP_DAMAGE())
+               else if(GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR) > ROCKETJUMP_DAMAGE())
                {
                        if(this.velocity.z < 0)
                        {
@@ -748,9 +748,10 @@ void havocbot_movetogoal(entity this)
                else
                        PHYS_INPUT_BUTTON_JUMP(this) = false;
                makevectors(this.v_angle.y * '0 1 0');
-               CS(this).movement_x = dir * v_forward * maxspeed;
-               CS(this).movement_y = dir * v_right * maxspeed;
-               CS(this).movement_z = dir * v_up * maxspeed;
+               vector v = dir * maxspeed;
+               CS(this).movement.x = v * v_forward;
+               CS(this).movement.y = v * v_right;
+               CS(this).movement.z = v * v_up;
        }
 
        // if there is nowhere to go, exit
@@ -885,17 +886,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)
        {
@@ -1167,7 +1168,7 @@ void havocbot_chooseenemy(entity this)
                        traceline(this.origin+this.view_ofs, ( this.enemy.absmin + this.enemy.absmax ) * 0.5,false,NULL);
                        if (trace_ent == this.enemy || trace_fraction == 1)
                        if (vdist(((this.enemy.absmin + this.enemy.absmax) * 0.5) - this.origin, <, 1000))
-                       if (this.health > 30)
+                       if (GetResourceAmount(this, RESOURCE_HEALTH) > 30)
                        {
                                // remain tracking him for a shot while (case he went after a small corner or pilar
                                this.havocbot_chooseenemy_finished = time + 0.5;
@@ -1238,7 +1239,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..9ca2b1208e91a2e828b13ba4ce1646111ac1fc22 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"
@@ -49,14 +50,14 @@ void havocbot_goalrating_waypoints(entity this, float ratingscale, vector org, f
 
 bool havocbot_goalrating_item_can_be_left_to_teammate(entity this, entity player, entity item)
 {
-       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 (GetResourceAmount(item, RESOURCE_HEALTH) && GetResourceAmount(player, RESOURCE_HEALTH) <= GetResourceAmount(this, RESOURCE_HEALTH)) {return true;}
+       if (GetResourceAmount(item, RESOURCE_ARMOR) && GetResourceAmount(player, RESOURCE_ARMOR) <= GetResourceAmount(this, RESOURCE_ARMOR)) {return true;}
+       if (STAT(WEAPONS, item) && !(STAT(WEAPONS, player) & STAT(WEAPONS, item))) {return true;}
+       if (GetResourceAmount(item, RESOURCE_SHELLS) && GetResourceAmount(player, RESOURCE_SHELLS) <= GetResourceAmount(this, RESOURCE_SHELLS)) {return true;}
+       if (GetResourceAmount(item, RESOURCE_BULLETS) && GetResourceAmount(player, RESOURCE_BULLETS) <= GetResourceAmount(this, RESOURCE_BULLETS)) {return true;}
+       if (GetResourceAmount(item, RESOURCE_ROCKETS) && GetResourceAmount(player, RESOURCE_ROCKETS) <= GetResourceAmount(this, RESOURCE_ROCKETS)) {return true;}
+       if (GetResourceAmount(item, RESOURCE_CELLS) && GetResourceAmount(player, RESOURCE_CELLS) <= GetResourceAmount(this, RESOURCE_CELLS)) {return true;}
+       if (GetResourceAmount(item, RESOURCE_PLASMA) && GetResourceAmount(player, RESOURCE_PLASMA) <= GetResourceAmount(this, RESOURCE_PLASMA)) {return true;}
        if (item.itemdef.instanceOfPowerup) {return true;}
 
        return false;
@@ -207,7 +208,7 @@ void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org
                        continue;
                */
 
-               t = ((this.health + this.armorvalue) - (it.health + it.armorvalue)) / 150;
+               t = ((GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR)) - (GetResourceAmount(it, RESOURCE_HEALTH) + GetResourceAmount(it, RESOURCE_ARMOR))) / 150;
                t = bound(0, 1 + t, 3);
                if (skill > 3)
                {
index 7b80a1a6f27cfd790fb59f325f8eda9404dfbcf9..555cfd0ef0a1f4da4beb81ebc73577ced6dd0360 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)
@@ -1233,12 +1234,13 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                {
                        entity theEnemy = e;
                        entity best_wp = NULL;
-                       float best_dist = 10000;
-                       IL_EACH(g_waypoints, vdist(it.origin - theEnemy.origin, <, 500)
+                       float best_dist = FLOAT_MAX;
+                       IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT)
+                               && vdist(it.origin - theEnemy.origin, <, 500)
                                && vdist(it.origin - this.origin, >, 100)
-                               && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+                               && vdist(it.origin - this.origin, <, 10000),
                        {
-                               float dist = vlen(it.origin - theEnemy.origin);
+                               float dist = vlen2(it.origin - theEnemy.origin);
                                if (dist < best_dist)
                                {
                                        best_wp = it;
@@ -1256,7 +1258,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))
@@ -1315,10 +1316,10 @@ void navigation_routerating(entity this, entity e, float f, float rangebias)
                        t += xydistance / autocvar_g_jetpack_maxspeed_side;
                        fuel = t * autocvar_g_jetpack_fuel * 0.8;
 
-                       LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
+                       LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), ", have ", ftos(GetResourceAmount(this, RESOURCE_FUEL)));
 
                        // enough fuel ?
-                       if(this.ammo_fuel>fuel)
+                       if(GetResourceAmount(this, RESOURCE_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 +1574,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 +1840,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..48975b8367e58766668e59027e5e73000b9b4d51 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) != "\'")
@@ -622,10 +620,11 @@ float bot_cmd_eval(entity this, string expr)
                return cvar(substring(expr, 5, strlen(expr)));
 
        // Search for fields
+       // TODO: expand with support for more fields (key carrier, ball carrier, armor etc)
        switch(expr)
        {
                case "health":
-                       return this.health;
+                       return GetResourceAmount(this, RESOURCE_HEALTH);
                case "speed":
                        return vlen(this.velocity);
                case "flagcarrier":
@@ -1170,8 +1169,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 3233a141dd9e1b14b71437c49e016ed77d6acf2e..04172b5eb2b59d74de854c3c1d440ad4c5f7827a 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;
-                       this.personal.health = max(1, this.health);
-                       this.personal.armorvalue = this.armorvalue;
-                       this.personal.weapons = this.weapons;
+                       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));
+                       SetResourceAmount(this.personal, RESOURCE_HEALTH, max(1, GetResourceAmount(this, RESOURCE_HEALTH)));
+                       SetResourceAmount(this.personal, RESOURCE_ARMOR, GetResourceAmount(this, RESOURCE_ARMOR));
+                       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;
-                               this.health = this.personal.health;
-                               this.armorvalue = this.personal.armorvalue;
-                               this.weapons = this.personal.weapons;
+                               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));
+                               SetResourceAmount(this, RESOURCE_HEALTH, GetResourceAmount(this.personal, RESOURCE_HEALTH));
+                               SetResourceAmount(this, RESOURCE_ARMOR, GetResourceAmount(this.personal, RESOURCE_ARMOR));
+                               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;
@@ -279,7 +280,7 @@ float CheatImpulse(entity this, int imp)
 
                        e2 = spawn();
                        setorigin(e2, e.origin);
-                       RadiusDamage(e2, this, 1000, 0, 128, NULL, NULL, 500, DEATH_CHEAT.m_id, e);
+                       RadiusDamage(e2, this, 1000, 0, 128, NULL, NULL, 500, DEATH_CHEAT.m_id, DMG_NOWEP, e);
                        delete(e2);
 
                        LOG_INFO("404 Sportsmanship not found.");
@@ -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)
 {
@@ -329,7 +329,7 @@ float CheatCommand(entity this, int argc)
                                // arguments:
                                //   effectname
                                effectnum = _particleeffectnum(argv(1));
-                               W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0);
+                               W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0, 0);
                                traceline(w_shotorg, w_shotorg + w_shotdir * max_shot_distance, MOVE_NORMAL, this);
                                __trailparticles(this, effectnum, w_shotorg, trace_endpos);
                                DID_CHEAT();
@@ -344,7 +344,7 @@ float CheatCommand(entity this, int argc)
                                // arguments:
                                //   modelname mode
                                f = stof(argv(2));
-                               W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0);
+                               W_SetupShot(this, weaponentities[0], false, false, SND_Null, CH_WEAPON_A, 0, 0);
                                traceline(w_shotorg, w_shotorg + w_shotdir * 2048, MOVE_NORMAL, this);
                                if((trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT) || trace_fraction == 1)
                                {
@@ -355,7 +355,7 @@ float CheatCommand(entity this, int argc)
                                        entity e = spawn();
                                        e.model = strzone(argv(1));
                                        e.mdl = "rocket_explode";
-                                       e.health = 1000;
+                                       SetResourceAmountExplicit(e, RESOURCE_HEALTH, 1000);
                                        setorigin(e, trace_endpos);
                                        e.effects = EF_NOMODELFLAGS;
                                        if(f == 1)
@@ -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 3333c04e49180286b6ef8806c91aa410baf0de1e..43174dd5539253a0fbf4ebaaa7c7d0940ef37830 100644 (file)
 #include "miscfunctions.qh"
 #include "portals.qh"
 #include "teamplay.qh"
-#include "playerdemo.qh"
 #include "spawnpoints.qh"
 #include "resources.qh"
 #include "g_damage.qh"
 #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,8 +33,9 @@
 
 #include <common/effects/qc/globalsound.qh>
 
-#include "../common/triggers/func/conveyor.qh"
-#include "../common/triggers/teleporters.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"
 
@@ -61,6 +66,8 @@
 
 #include "../lib/warpzone/server.qh"
 
+#include <common/mutators/mutator/overkill/oknex.qh>
+
 STATIC_METHOD(Client, Add, void(Client this, int _team))
 {
     ClientConnect(this);
@@ -70,8 +77,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);
@@ -151,15 +156,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);
-
 
 /*
 =============
@@ -213,7 +220,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)
 {
@@ -222,7 +228,7 @@ void PutObserverInServer(entity this)
 
        if (IS_PLAYER(this))
        {
-               if(this.health >= 1)
+               if(GetResourceAmount(this, RESOURCE_HEALTH) >= 1)
                {
                        // despawn effect
                        Send_Effect(EFFECT_SPAWN_NEUTRAL, this.origin, '0 0 0', 1);
@@ -307,22 +313,24 @@ void PutObserverInServer(entity this)
        if(this.bot_attack)
                IL_REMOVE(g_bot_targets, this);
        this.bot_attack = false;
-    this.hud = HUD_NORMAL;
+       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;
        this.teleportable = TELEPORT_SIMPLE;
        if(this.damagedbycontents)
                IL_REMOVE(g_damagedbycontents, this);
        this.damagedbycontents = false;
-       this.health = FRAGS_SPECTATOR;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, FRAGS_SPECTATOR);
        SetSpectatee_status(this, etof(this));
        this.takedamage = DAMAGE_NO;
        this.solid = SOLID_NOT;
        set_movetype(this, MOVETYPE_FLY_WORLDONLY); // user preference is controlled by playerprethink
        this.flags = FL_CLIENT | FL_NOTARGET;
-       this.armorvalue = 666;
        this.effects = 0;
-       this.armorvalue = autocvar_g_balance_armor_start;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, autocvar_g_balance_armor_start); // was 666?!
        this.pauserotarmor_finished = 0;
        this.pauserothealth_finished = 0;
        this.pauseregen_finished = 0;
@@ -330,7 +338,7 @@ void PutObserverInServer(entity this)
        this.death_time = 0;
        this.respawn_flags = 0;
        this.respawn_time = 0;
-       this.stat_respawn_time = 0;
+       STAT(RESPAWN_TIME, this) = 0;
        this.alpha = 0;
        this.scale = 0;
        this.fade_time = 0;
@@ -339,19 +347,24 @@ 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);
        this.nextthink = 0;
        this.deadflag = DEAD_NO;
        this.crouch = false;
-       this.revive_progress = 0;
+       STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
 
        this.items = 0;
-       this.weapons = '0 0 0';
+       STAT(WEAPONS, this) = '0 0 0';
        this.drawonlytoclient = this;
 
+       this.viewloc = NULL;
+
+       //this.spawnpoint_targ = NULL; // keep it so they can return to where they were?
+
        this.weaponmodel = "";
        for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
        {
@@ -366,6 +379,7 @@ void PutObserverInServer(entity this)
        this.oldvelocity = this.velocity;
        this.fire_endtime = -1;
        this.event_damage = func_null;
+       this.event_heal = func_null;
 
        for(int slot = 0; slot < MAX_AXH; ++slot)
        {
@@ -539,25 +553,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;
-               this.health = warmup_start_health;
-               this.armorvalue = warmup_start_armorvalue;
-               this.weapons = WARMUP_START_WEAPONS;
+               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);
+               SetResourceAmount(this, RESOURCE_HEALTH, warmup_start_health);
+               SetResourceAmount(this, RESOURCE_ARMOR, warmup_start_armorvalue);
+               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;
-               this.health = start_health;
-               this.armorvalue = start_armorvalue;
-               this.weapons = start_weapons;
+               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);
+               SetResourceAmount(this, RESOURCE_HEALTH, start_health);
+               SetResourceAmount(this, RESOURCE_ARMOR, start_armorvalue);
+               STAT(WEAPONS, this) = start_weapons;
                if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
                {
                        GiveRandomWeapons(this, random_start_weapons_count,
@@ -568,7 +582,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;
 
@@ -577,19 +591,20 @@ void PutPlayerInServer(entity this)
        this.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot_spawn;
        this.pauserotfuel_finished = time + autocvar_g_balance_pause_fuel_rot_spawn;
        this.pauseregen_finished = time + autocvar_g_balance_pause_health_regen_spawn;
-       // extend the pause of rotting if client was reset at the beginning of the countdown
-       if (!autocvar_sv_ready_restart_after_countdown && time < game_starttime) { // TODO why is this cvar NOTted?
+       if (!sv_ready_restart_after_countdown && time < game_starttime)
+       {
                float f = game_starttime - time;
                this.spawnshieldtime += f;
                this.pauserotarmor_finished += f;
                this.pauserothealth_finished += f;
                this.pauseregen_finished += f;
        }
+
        this.damageforcescale = 2;
        this.death_time = 0;
        this.respawn_flags = 0;
        this.respawn_time = 0;
-       this.stat_respawn_time = 0;
+       STAT(RESPAWN_TIME, this) = 0;
        this.scale = autocvar_sv_player_scale;
        this.fade_time = 0;
        this.pain_frame = 0;
@@ -615,7 +630,7 @@ void PutPlayerInServer(entity this)
        this.strength_finished = 0;
        this.invincible_finished = 0;
        this.fire_endtime = -1;
-       this.revive_progress = 0;
+       STAT(REVIVE_PROGRESS, this) = 0;
        this.revival_time = 0;
 
        this.air_finished = time + 12;
@@ -635,6 +650,17 @@ void PutPlayerInServer(entity this)
 
        this.viewloc = NULL;
 
+       for(int slot = 0; slot < MAX_AXH; ++slot)
+       {
+               entity axh = this.(AuxiliaryXhair[slot]);
+               this.(AuxiliaryXhair[slot]) = NULL;
+
+               if(axh.owner == this && axh != NULL && !wasfreed(axh))
+                       delete(axh);
+       }
+
+       this.spawnpoint_targ = NULL;
+
        this.crouch = false;
        this.view_ofs = STAT(PL_VIEW_OFS, this);
        setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
@@ -645,9 +671,10 @@ void PutPlayerInServer(entity this)
        if(this.conveyor)
                IL_REMOVE(g_conveyed, this);
        this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
-       this.hud = HUD_NORMAL;
+       STAT(HUD, this) = HUD_NORMAL;
 
        this.event_damage = PlayerDamage;
+       this.event_heal = PlayerHeal;
 
        if(!this.bot_attack)
                IL_PUSH(g_bot_targets, this);
@@ -727,6 +754,12 @@ void PutPlayerInServer(entity this)
 
        MUTATOR_CALLHOOK(PlayerWeaponSelect, this);
 
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               W_WeaponFrame(this, weaponentity);
+       }
+
        if (!warmup_stage && !this.alivetime)
                this.alivetime = time;
 
@@ -761,8 +794,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)
@@ -903,7 +934,7 @@ void ClientKill_Now(entity this)
            if(!this.killindicator_teamchange)
            {
             this.vehicle_health = -1;
-            Damage(this, this, this, 1 , DEATH_KILL.m_id, this.origin, '0 0 0');
+            Damage(this, this, this, 1 , DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
            }
        }
 
@@ -917,7 +948,7 @@ void ClientKill_Now(entity this)
 
        if (!IS_SPEC(this) && !IS_OBSERVER(this) && MUTATOR_CALLHOOK(ClientKill_Now, this) == false)
        {
-               Damage(this, this, this, 100000, DEATH_KILL.m_id, this.origin, '0 0 0');
+               Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
        }
 
        // now I am sure the player IS dead
@@ -943,7 +974,7 @@ void KillIndicator_Think(entity this)
                ClientKill_Now(this.owner);
                return;
        }
-    else if(this.health == 1) // health == 1 means that it's silent
+    else if(this.count == 1) // count == 1 means that it's silent
     {
         this.nextthink = time + 1;
         this.cnt -= 1;
@@ -1058,6 +1089,8 @@ void ClientKill_TeamChange (entity this, float targetteam) // 0 = don't change,
 
 void ClientKill (entity this)
 {
+       // TODO: once .health is removed, will need to check it here for the "already dead" message!
+
        if(game_stopped) return;
        if(this.player_blocked) return;
        if(STAT(FROZEN, this)) return;
@@ -1077,6 +1110,8 @@ void FixClientCvars(entity e)
        stuffcmd(e, sprintf("\ncl_jumpspeedcap_min \"%s\"\n", autocvar_sv_jumpspeedcap_min));
        stuffcmd(e, sprintf("\ncl_jumpspeedcap_max \"%s\"\n", autocvar_sv_jumpspeedcap_max));
 
+       stuffcmd(e, sprintf("\ncl_shootfromfixedorigin \"%s\"\n", autocvar_g_shootfromfixedorigin));
+
        MUTATOR_CALLHOOK(FixClientCvars, e);
 }
 
@@ -1196,16 +1231,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));
 
@@ -1309,7 +1335,6 @@ Called when a client disconnects from the server
 =============
 */
 .entity chatbubbleentity;
-void ReadyCount();
 void ClientDisconnect(entity this)
 {
        assert(IS_CLIENT(this), return);
@@ -1329,7 +1354,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!
+       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);
@@ -1349,8 +1375,7 @@ void ClientDisconnect(entity this)
 
        bot_relinkplayerlist();
 
-       if (this.clientstatus) strunzone(this.clientstatus);
-       if (this.weaponorder_byimpulse) strunzone(this.weaponorder_byimpulse);
+       strfree(this.clientstatus);
        if (this.personal) delete(this.personal);
 
        this.playerid = 0;
@@ -1446,6 +1471,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);
@@ -1473,7 +1546,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)
                {
@@ -1519,7 +1592,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);
@@ -1536,13 +1609,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))
                        {
@@ -1554,7 +1627,7 @@ void player_powerups(entity this)
                        else
                        {
                                this.superweapons_finished = 0;
-                               this.weapons &= ~WEPSET_SUPERWEAPONS;
+                               STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
                        }
                }
                else
@@ -1659,18 +1732,22 @@ void player_regen(entity this)
                limith = limith * limit_mod;
                limita = limita * limit_mod;
 
-               this.armorvalue = CalcRotRegen(this.armorvalue, mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, regen_mod * frametime * (time > this.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear, rot_mod * frametime * (time > this.pauserotarmor_finished), limita);
-               this.health = CalcRotRegen(this.health, regen_health_stable, regen_health, regen_health_linear, regen_mod * frametime * (time > this.pauseregen_finished), regen_health_rotstable, regen_health_rot, regen_health_rotlinear, rot_mod * frametime * (time > this.pauserothealth_finished), limith);
+               SetResourceAmount(this, RESOURCE_ARMOR, CalcRotRegen(GetResourceAmount(this, RESOURCE_ARMOR), mina, autocvar_g_balance_armor_regen, autocvar_g_balance_armor_regenlinear, 
+                                                                       regen_mod * frametime * (time > this.pauseregen_finished), maxa, autocvar_g_balance_armor_rot, autocvar_g_balance_armor_rotlinear,
+                                                                       rot_mod * frametime * (time > this.pauserotarmor_finished), limita));
+               SetResourceAmount(this, RESOURCE_HEALTH, CalcRotRegen(GetResourceAmount(this, RESOURCE_HEALTH), regen_health_stable, regen_health, regen_health_linear,
+                                                                       regen_mod * frametime * (time > this.pauseregen_finished), regen_health_rotstable, regen_health_rot, regen_health_rotlinear,
+                                                                       rot_mod * frametime * (time > this.pauserothealth_finished), limith));
        }
 
        // if player rotted to death...  die!
        // check this outside above checks, as player may still be able to rot to death
-       if(this.health < 1)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 1)
        {
                if(this.vehicle)
                        vehicles_exit(this.vehicle, VHEF_RELEASE);
                if(this.event_damage)
-                       this.event_damage(this, this, this, 1, DEATH_ROT.m_id, this.origin, '0 0 0');
+                       this.event_damage(this, this, this, 1, DEATH_ROT.m_id, DMG_NOWEP, this.origin, '0 0 0');
        }
 
        if (!(this.items & IT_UNLIMITED_WEAPON_AMMO))
@@ -1681,20 +1758,10 @@ void player_regen(entity this)
                minf = autocvar_g_balance_fuel_regenstable;
                limitf = GetResourceLimit(this, RESOURCE_FUEL);
 
-               this.ammo_fuel = CalcRotRegen(this.ammo_fuel, minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, frametime * (time > this.pauseregen_finished) * ((this.items & ITEM_JetpackRegen.m_itemid) != 0), maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > this.pauserotfuel_finished), limitf);
+               SetResourceAmount(this, RESOURCE_FUEL, CalcRotRegen(GetResourceAmount(this, RESOURCE_FUEL), minf, autocvar_g_balance_fuel_regen, autocvar_g_balance_fuel_regenlinear, 
+                                                                               frametime * (time > this.pauseregen_finished) * ((this.items & ITEM_JetpackRegen.m_itemid) != 0),
+                                                                               maxf, autocvar_g_balance_fuel_rot, autocvar_g_balance_fuel_rotlinear, frametime * (time > this.pauserotfuel_finished), limitf));
        }
-       // Ugly hack to make sure the health and armor don't go beyond hard limit.
-       // TODO: Remove this hack when all code uses GivePlayerHealth and
-       // GivePlayerArmor.
-       if (this.health > RESOURCE_AMOUNT_HARD_LIMIT)
-       {
-               this.health = RESOURCE_AMOUNT_HARD_LIMIT;
-       }
-       if (this.armorvalue > RESOURCE_AMOUNT_HARD_LIMIT)
-       {
-               this.armorvalue = RESOURCE_AMOUNT_HARD_LIMIT;
-       }
-       // End hack.
 }
 
 bool zoomstate_set;
@@ -1739,31 +1806,24 @@ void SpectateCopy(entity this, entity spectatee)
        MUTATOR_CALLHOOK(SpectateCopy, spectatee, this);
        PS(this) = PS(spectatee);
        this.armortype = spectatee.armortype;
-       this.armorvalue = spectatee.armorvalue;
-       this.ammo_cells = spectatee.ammo_cells;
-       this.ammo_plasma = spectatee.ammo_plasma;
-       this.ammo_shells = spectatee.ammo_shells;
-       this.ammo_nails = spectatee.ammo_nails;
-       this.ammo_rockets = spectatee.ammo_rockets;
-       this.ammo_fuel = spectatee.ammo_fuel;
-       this.clip_load = spectatee.clip_load;
-       this.clip_size = spectatee.clip_size;
+       SetResourceAmountExplicit(this, RESOURCE_ARMOR, GetResourceAmount(spectatee, RESOURCE_ARMOR));
+       SetResourceAmountExplicit(this, RESOURCE_CELLS, GetResourceAmount(spectatee, RESOURCE_CELLS));
+       SetResourceAmountExplicit(this, RESOURCE_PLASMA, GetResourceAmount(spectatee, RESOURCE_PLASMA));
+       SetResourceAmountExplicit(this, RESOURCE_SHELLS, GetResourceAmount(spectatee, RESOURCE_SHELLS));
+       SetResourceAmountExplicit(this, RESOURCE_BULLETS, GetResourceAmount(spectatee, RESOURCE_BULLETS));
+       SetResourceAmountExplicit(this, RESOURCE_ROCKETS, GetResourceAmount(spectatee, RESOURCE_ROCKETS));
+       SetResourceAmountExplicit(this, RESOURCE_FUEL, GetResourceAmount(spectatee, RESOURCE_FUEL));
        this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
-       this.health = spectatee.health;
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, GetResourceAmount(spectatee, RESOURCE_HEALTH));
        CS(this).impulse = 0;
        this.items = spectatee.items;
-       this.last_pickup = spectatee.last_pickup;
-       this.hit_time = spectatee.hit_time;
+       STAT(LAST_PICKUP, this) = STAT(LAST_PICKUP, spectatee);
+       STAT(HIT_TIME, this) = STAT(HIT_TIME, spectatee);
        this.strength_finished = spectatee.strength_finished;
        this.invincible_finished = spectatee.invincible_finished;
        this.superweapons_finished = spectatee.superweapons_finished;
        STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
-       this.weapons = spectatee.weapons;
-       this.vortex_charge = spectatee.vortex_charge;
-       this.vortex_chargepool_ammo = spectatee.vortex_chargepool_ammo;
-       this.hagar_load = spectatee.hagar_load;
-       this.arc_heat_percent = spectatee.arc_heat_percent;
-       this.minelayer_mines = spectatee.minelayer_mines;
+       STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
        this.punchangle = spectatee.punchangle;
        this.view_ofs = spectatee.view_ofs;
        this.velocity = spectatee.velocity;
@@ -1773,7 +1833,7 @@ void SpectateCopy(entity this, entity spectatee)
        this.v_angle = spectatee.v_angle;
        this.angles = spectatee.v_angle;
        STAT(FROZEN, this) = STAT(FROZEN, spectatee);
-       this.revive_progress = spectatee.revive_progress;
+       STAT(REVIVE_PROGRESS, this) = STAT(REVIVE_PROGRESS, spectatee);
        this.viewloc = spectatee.viewloc;
        if(!PHYS_INPUT_BUTTON_USE(this) && STAT(CAMERA_SPECTATOR, this) != 2)
                this.fixangle = true;
@@ -1781,19 +1841,8 @@ void SpectateCopy(entity this, entity spectatee)
        setsize(this, spectatee.mins, spectatee.maxs);
        SetZoomState(this, CS(spectatee).zoomstate);
 
-       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-       {
-               .entity weaponentity = weaponentities[slot];
-               this.(weaponentity) = spectatee.(weaponentity);
-       }
-
-       for(int slot = 0; slot < MAX_AXH; ++slot)
-       {
-               this.(AuxiliaryXhair[slot]) = spectatee.(AuxiliaryXhair[slot]);
-       }
-
     anticheat_spectatecopy(this, spectatee);
-       this.hud = spectatee.hud;
+       STAT(HUD, this) = STAT(HUD, spectatee);
        if(spectatee.vehicle)
     {
        this.angles = spectatee.v_angle;
@@ -2134,17 +2183,20 @@ 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;
 }
 
 .int items_added;
+.string shootfromfixedorigin;
 bool PlayerThink(entity this)
 {
        if (game_stopped || intermission_running) {
@@ -2240,45 +2292,13 @@ 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;
-    }
+       FixPlayermodel(this);
 
-       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));
-        }
+       if (this.shootfromfixedorigin != autocvar_g_shootfromfixedorigin) {
+               this.shootfromfixedorigin = autocvar_g_shootfromfixedorigin;
+               stuffcmd(this, sprintf("\ncl_shootfromfixedorigin \"%s\"\n", autocvar_g_shootfromfixedorigin));
        }
 
-       FixPlayermodel(this);
-
        // LordHavoc: allow firing on move frames (sub-ticrate), this gives better timing on slow servers
        //if(frametime)
        {
@@ -2288,16 +2308,10 @@ bool PlayerThink(entity this)
                {
                        .entity weaponentity = weaponentities[slot];
                        W_WeaponFrame(this, weaponentity);
-
-                       if(slot == 0)
-                       {
-                               this.clip_load = this.(weaponentity).clip_load;
-                               this.clip_size = this.(weaponentity).clip_size;
-                       }
                }
 
                this.items_added = 0;
-               if ((this.items & ITEM_Jetpack.m_itemid) && ((this.items & ITEM_JetpackRegen.m_itemid) || this.ammo_fuel >= 0.01))
+               if ((this.items & ITEM_Jetpack.m_itemid) && ((this.items & ITEM_JetpackRegen.m_itemid) || GetResourceAmount(this, RESOURCE_FUEL) >= 0.01))
             this.items_added |= IT_FUEL;
 
                this.items |= this.items_added;
@@ -2327,6 +2341,7 @@ bool PlayerThink(entity this)
        return true;
 }
 
+.bool would_spectate;
 void ObserverThink(entity this)
 {
        if ( CS(this).impulse )
@@ -2339,7 +2354,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);
@@ -2399,12 +2414,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))) {
@@ -2423,7 +2445,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))
@@ -2513,8 +2534,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
@@ -2546,26 +2566,26 @@ void PlayerPreThink (entity this)
        {
                if (STAT(FROZEN, this) == 2)
                {
-                       this.revive_progress = bound(0, this.revive_progress + frametime * this.revive_speed, 1);
-                       this.health = max(1, this.revive_progress * start_health);
-                       this.iceblock.alpha = bound(0.2, 1 - this.revive_progress, 1);
+                       STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) + frametime * this.revive_speed, 1);
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, this) * start_health));
+                       this.iceblock.alpha = bound(0.2, 1 - STAT(REVIVE_PROGRESS, this), 1);
 
-                       if (this.revive_progress >= 1)
+                       if (STAT(REVIVE_PROGRESS, this) >= 1)
                                Unfreeze(this);
                }
                else if (STAT(FROZEN, this) == 3)
                {
-                       this.revive_progress = bound(0, this.revive_progress - frametime * this.revive_speed, 1);
-                       this.health = max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * this.revive_progress );
+                       STAT(REVIVE_PROGRESS, this) = bound(0, STAT(REVIVE_PROGRESS, this) - frametime * this.revive_speed, 1);
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, max(0, autocvar_g_nades_ice_health + (start_health-autocvar_g_nades_ice_health) * STAT(REVIVE_PROGRESS, this)));
 
-                       if (this.health < 1)
+                       if (GetResourceAmount(this, RESOURCE_HEALTH) < 1)
                        {
                                if (this.vehicle)
                                        vehicles_exit(this.vehicle, VHEF_RELEASE);
                                if(this.event_damage)
-                                       this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, this.origin, '0 0 0');
+                                       this.event_damage(this, this, this.frozen_by, 1, DEATH_NADE_ICE_FREEZE.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        }
-                       else if (this.revive_progress <= 0)
+                       else if (STAT(REVIVE_PROGRESS, this) <= 0)
                                Unfreeze(this);
                }
        }
@@ -2605,6 +2625,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;
        }
@@ -2613,6 +2635,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);
        }
@@ -2676,7 +2712,7 @@ void DrownPlayer(entity this)
        {       // drown!
                if (this.pain_finished < time)
                {
-                       Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_drowning * autocvar_g_balance_contents_damagerate, DEATH_DROWN.m_id, this.origin, '0 0 0');
+                       Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_drowning * autocvar_g_balance_contents_damagerate, DEATH_DROWN.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        this.pain_finished = time + 0.5;
                }
        }
@@ -2765,6 +2801,13 @@ void PlayerPostThink (entity this)
        }
 
        if (IS_PLAYER(this)) {
+               if(this.death_time == time && IS_DEAD(this))
+               {
+                       // player's bbox gets resized now, instead of in the damage event that killed the player,
+                       // once all the damage events of this frame have been processed with normal size
+                       this.maxs.z = 5;
+                       setsize(this, this.mins, this.maxs);
+               }
                DrownPlayer(this);
                UpdateChatBubble(this);
                if (CS(this).impulse) ImpulseCommands(this);
@@ -2777,12 +2820,10 @@ void PlayerPostThink (entity this)
        }
 
        if (this.waypointsprite_attachedforcarrier) {
-           vector v = healtharmor_maxdamage(this.health, this.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id);
+           vector v = healtharmor_maxdamage(GetResourceAmount(this, RESOURCE_HEALTH), GetResourceAmount(this, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id);
                WaypointSprite_UpdateHealth(this.waypointsprite_attachedforcarrier, '1 0 0' * v);
     }
 
-       playerdemo_write(this);
-
        CSQCMODEL_AUTOUPDATE(this);
 }
 
@@ -2793,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;
@@ -2823,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 42d7d9560b4e92359242e19428f242d146cbff0a..2d3a099b3988bc715589d9f5018fd310be1fc7f6 100644 (file)
@@ -113,6 +113,8 @@ CLASS(Client, Object)
     ATTRIB(Client, cmd_floodcount, int, this.cmd_floodcount);
     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
 
@@ -224,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 09a308ad5c64d6a1001fb31754d2a8d0721f89e0..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)
@@ -239,21 +237,23 @@ void ClientCommand_ready(entity caller, float request)  // todo: anti-spam for t
                {
                        if (IS_CLIENT(caller))
                        {
-                               if (warmup_stage || autocvar_sv_ready_restart || g_race_qualifying == 2)
+                               if (warmup_stage || sv_ready_restart || g_race_qualifying == 2)
                                {
-                                       if (!readyrestart_happened || autocvar_sv_ready_restart_repeatable)
+                                       if (!readyrestart_happened || sv_ready_restart_repeatable)
                                        {
                                                if (time < game_starttime) // game is already restarting
                                                        return;
                                                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 46d1d2b6f86fd1c888b3b730593179552625f2d3..cb8ab239fbebd1ac74b4781982d3d93ed14f43ac 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);
@@ -405,7 +405,7 @@ void CommonCommand_editmob(int request, entity caller, int argc)
                                        if (mon.realowner != caller && autocvar_g_monsters_edit < 2) { print_to(caller, "This monster does not belong to you"); return; }
                                        if (!is_visible) { print_to(caller, "You must look at your monster to edit it"); return; }
 
-                                       Damage(mon, NULL, NULL, mon.health + mon.max_health + 200, DEATH_KILL.m_id, mon.origin, '0 0 0');
+                                       Damage(mon, NULL, NULL, GetResourceAmount(mon, RESOURCE_HEALTH) + mon.max_health + 200, DEATH_KILL.m_id, DMG_NOWEP, mon.origin, '0 0 0');
                                        print_to(caller, strcat("Your pet '", mon.monster_name, "' has been brutally mutilated"));
                                        return;
                                }
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..1076225d82acaf1e89a00432927c4c95b8593c34 100644 (file)
 #include "../player.qh"
 #include "../g_world.qh"
 #include "../ipban.qh"
-#include "../playerdemo.qh"
 #include "../teamplay.qh"
 
 #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)
 {
@@ -1172,86 +1165,6 @@ void GameCommand_nospectators(float request)
        }
 }
 
-void GameCommand_playerdemo(float request, float argc)
-{
-       switch (request)
-       {
-               case CMD_REQUEST_COMMAND:
-               {
-                       if (argv(2) && argv(3))
-                       {
-                               entity client;
-                               float i, n, accepted;
-
-                               switch (argv(1))
-                               {
-                                       case "read":
-                                       {
-                                               client = GetIndexedEntity(argc, 2);
-                                               accepted = VerifyClientEntity(client, false, true);
-
-                                               if (accepted <= 0)
-                                               {
-                                                       LOG_INFO("playerdemo: read: ", GetClientErrorString(accepted, argv(2)), ".");
-                                                       return;
-                                               }
-
-                                               playerdemo_open_read(client, argv(next_token));
-                                               return;
-                                       }
-
-                                       case "write":
-                                       {
-                                               client = GetIndexedEntity(argc, 2);
-                                               accepted = VerifyClientEntity(client, false, false);
-
-                                               if (accepted <= 0)
-                                               {
-                                                       LOG_INFO("playerdemo: write: ", GetClientErrorString(accepted, argv(2)), ".");
-                                                       return;
-                                               }
-
-                                               playerdemo_open_write(client, argv(next_token));
-                                               return;
-                                       }
-
-                                       case "auto_read_and_write":
-                                       {
-                                               n = GetFilteredNumber(argv(3));
-                                               cvar_set("bot_number", ftos(n));
-
-                                               localcmd("wait; wait; wait\n");
-                                               for (i = 0; i < n; ++i)
-                                                       localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
-                                               localcmd("sv_cmd playerdemo write 1 ", ftos(n + 1), "\n");
-                                               return;
-                                       }
-
-                                       case "auto_read":
-                                       {
-                                               n = GetFilteredNumber(argv(3));
-                                               cvar_set("bot_number", ftos(n));
-
-                                               localcmd("wait; wait; wait\n");
-                                               for (i = 0; i < n; ++i)
-                                                       localcmd("sv_cmd playerdemo read ", ftos(i + 2), " ", argv(2), ftos(i + 1), "\n");
-                                               return;
-                                       }
-                               }
-                       }
-               }
-
-               default:
-                       LOG_INFO("Incorrect parameters for ^2playerdemo^7");
-               case CMD_REQUEST_USAGE:
-               {
-                       LOG_INFO("Usage:^3 sv_cmd playerdemo command (entitynumber filename | entitynumber botnumber)");
-                       LOG_INFO("  Full list of commands here: \"read, write, auto_read_and_write, auto_read.\"");
-                       return;
-               }
-       }
-}
-
 void GameCommand_printstats(float request)
 {
        switch (request)
@@ -1577,10 +1490,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;
                                        }
                                }
@@ -1732,7 +1648,6 @@ SERVER_COMMAND(lockteams, "Disable the ability for players to switch or enter te
 SERVER_COMMAND(make_mapinfo, "Automatically rebuild mapinfo files") { GameCommand_make_mapinfo(request); }
 SERVER_COMMAND(moveplayer, "Change the team/status of a player") { GameCommand_moveplayer(request, arguments); }
 SERVER_COMMAND(nospectators, "Automatically remove spectators from a match") { GameCommand_nospectators(request); }
-SERVER_COMMAND(playerdemo, "Control the ability to save demos of players") { GameCommand_playerdemo(request, arguments); }
 SERVER_COMMAND(printstats, "Dump eventlog player stats and other score information") { GameCommand_printstats(request); }
 SERVER_COMMAND(radarmap, "Generate a radar image of the map") { GameCommand_radarmap(request, arguments); }
 SERVER_COMMAND(reducematchtime, "Decrease the timelimit value incrementally") { GameCommand_reducematchtime(request); }
index 1a826c6f142daf0164d83a7a27f59b37c09d9820..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;
 
@@ -452,7 +449,7 @@ void ReadyRestart_force()
        }
 
        // initiate the restart-countdown-announcer entity
-       if (autocvar_sv_ready_restart_after_countdown)
+       if (sv_ready_restart_after_countdown)
        {
                entity restart_timer = new_pure(restart_timer);
                setthink(restart_timer, ReadyRestart_think);
@@ -464,8 +461,8 @@ void ReadyRestart_force()
        {
                FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { CS(it).allowed_timeouts = autocvar_sv_timeout_number; });
        }
-    // reset map immediately if this cvar is not set
-    if (!autocvar_sv_ready_restart_after_countdown) reset_map(true);
+
+       if (!sv_ready_restart_after_countdown) reset_map(true);
        if (autocvar_sv_eventlog) GameLogEcho(":restart");
 }
 
@@ -476,7 +473,7 @@ void ReadyRestart()
 
        // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
        // Otherwise scores could be manipulated during the countdown.
-       if (!autocvar_sv_ready_restart_after_countdown) Score_ClearAll();
+       if (!sv_ready_restart_after_countdown) Score_ClearAll();
        ReadyRestart_force();
 }
 
@@ -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":
@@ -698,6 +703,16 @@ int VoteCommand_parse(entity caller, string vote_command, string vote_list, floa
                        break;
                }
 
+               case "nextmap": // TODO: replicate the old behaviour of being able to vote for maps from different modes on multimode servers (possibly support it in gotomap too), maybe fallback instead of aborting if map name is invalid?
+               {
+                       vote_command = ValidateMap(argv(startpos + 1), caller);
+                       if (!vote_command)  return -1;
+                       vote_parsed_command = strcat("nextmap ", vote_command);
+                       vote_parsed_display = strzone(strcat("^1", vote_parsed_command));
+
+                       break;
+               }
+
                default:
                {
                        vote_parsed_command = vote_command;
@@ -1128,6 +1143,12 @@ void VoteCommand_macro_help(entity caller, float argc)
 
                VOTE_COMMANDS(CMD_REQUEST_USAGE, caller, argc, "");
 #undef VOTE_COMMAND
+
+               string cvarname = strcat("sv_vote_command_help_", argv(2));
+               if(cvar_type(cvarname) & CVAR_TYPEFLAG_EXISTS)
+                       wordwrap_sprint(caller, cvar_string(cvarname), 1000);
+               else
+                       print_to(caller, "No documentation exists for this vote");
        }
 }
 
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 6a7f21aa674d319bad7ece6abeb908b28b764d60..4511100581b7d74a89f45e955292f74ce45d04a7 100644 (file)
@@ -3,10 +3,11 @@
 #include <server/defs.qh>
 #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
 //***********************
@@ -82,11 +83,55 @@ void target_init_verify(entity this)
                        }
 }
 
+void target_init_use(entity this, entity actor, entity trigger)
+{
+       if (!(this.spawnflags & 1))
+       {
+               SetResourceAmount(actor, RESOURCE_ARMOR, start_armorvalue);
+               actor.pauserotarmor_finished = time + autocvar_g_balance_pause_armor_rot;
+       }
+
+       if (!(this.spawnflags & 2))
+       {
+               SetResourceAmount(actor, RESOURCE_HEALTH, start_health);
+               actor.pauserothealth_finished = time + autocvar_g_balance_pause_health_rot;
+               actor.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+       }
+
+       if (!(this.spawnflags & 4))
+       {
+               SetResourceAmount(actor, RESOURCE_SHELLS, start_ammo_shells);
+               SetResourceAmount(actor, RESOURCE_BULLETS, start_ammo_nails);
+               SetResourceAmount(actor, RESOURCE_ROCKETS, start_ammo_rockets);
+               SetResourceAmount(actor, RESOURCE_CELLS, start_ammo_cells);
+               SetResourceAmount(actor, RESOURCE_PLASMA, start_ammo_plasma);
+               SetResourceAmount(actor, RESOURCE_FUEL, start_ammo_fuel);
+
+               STAT(WEAPONS, actor) = start_weapons;
+               if (this.spawnflags & 32)
+               {
+                       // TODO
+               }
+       }
+
+       if (!(this.spawnflags & 8))
+       {
+               actor.strength_finished = 0;
+               actor.invincible_finished = 0;
+               STAT(BUFFS, actor) = 0;
+       }
+
+       if (!(this.spawnflags & 16))
+       {
+               // We don't have holdables.
+       }
+
+       SUB_UseTargets(this, actor, trigger);
+}
+
 spawnfunc(target_init)
 {
-       this.spawnflags = 0; // remove all weapons except the ones listed below
-       this.netname = "shotgun"; // keep these weapons through the remove trigger
-       spawnfunc_target_items(this);
+       this.use = target_init_use;
        InitializeEntity(this, target_init_verify, INITPRIO_FINDTARGET);
 }
 
@@ -96,33 +141,33 @@ void target_give_init(entity this)
        IL_EACH(g_items, it.targetname == this.target,
        {
                if (it.classname == "weapon_devastator") {
-                       this.ammo_rockets += it.count * WEP_CVAR(devastator, ammo);
+                       SetResourceAmountExplicit(this, RESOURCE_ROCKETS, GetResourceAmount(this, RESOURCE_ROCKETS) + it.count * WEP_CVAR_PRI(devastator, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "devastator");
                }
                else if (it.classname == "weapon_vortex") {
-                       this.ammo_cells += it.count * WEP_CVAR_PRI(vortex, ammo); // WEAPONTODO
+                       SetResourceAmountExplicit(this, RESOURCE_CELLS, GetResourceAmount(this, RESOURCE_CELLS) + it.count * WEP_CVAR_PRI(vortex, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "vortex");
                }
                else if (it.classname == "weapon_electro") {
-                       this.ammo_cells += it.count * WEP_CVAR_PRI(electro, ammo); // WEAPONTODO
+                       SetResourceAmountExplicit(this, RESOURCE_CELLS, GetResourceAmount(this, RESOURCE_CELLS) + it.count * WEP_CVAR_PRI(electro, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "electro");
                }
                else if (it.classname == "weapon_hagar") {
-                       this.ammo_rockets += it.count * WEP_CVAR_PRI(hagar, ammo); // WEAPONTODO
+                       SetResourceAmountExplicit(this, RESOURCE_ROCKETS, GetResourceAmount(this, RESOURCE_ROCKETS) + it.count * WEP_CVAR_PRI(hagar, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "hagar");
                }
                else if (it.classname == "weapon_crylink") {
-                       this.ammo_cells += it.count * WEP_CVAR_PRI(crylink, ammo);
+                       SetResourceAmountExplicit(this, RESOURCE_CELLS, GetResourceAmount(this, RESOURCE_CELLS) + it.count * WEP_CVAR_PRI(crylink, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "crylink");
                }
                else if (it.classname == "weapon_mortar") {
-                       this.ammo_rockets += it.count * WEP_CVAR_PRI(mortar, ammo); // WEAPONTODO
+                       SetResourceAmountExplicit(this, RESOURCE_ROCKETS, GetResourceAmount(this, RESOURCE_ROCKETS) + it.count * WEP_CVAR_PRI(mortar, ammo)); // WEAPONTODO
                        this.netname = cons(this.netname, "mortar");
                }
                else if (it.classname == "item_armor_mega")
-                       this.armorvalue = 100;
+                       SetResourceAmountExplicit(this, RESOURCE_ARMOR, 100);
                else if (it.classname == "item_health_mega")
-                       this.health = 200;
+                       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 200);
                //remove(it); // removing ents in init functions causes havoc, workaround:
         setthink(it, SUB_Remove);
         it.nextthink = time;
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 e9cf6ee286a7d8831806504435737977436d8e08..4c23aaeb3b956f6706b8dcea57db48f1c4231f01 100644 (file)
@@ -7,12 +7,16 @@
 
 // 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;
 float g_jetpack;
 
+bool sv_ready_restart;
+bool sv_ready_restart_after_countdown;
+bool sv_ready_restart_repeatable;
+
 float sv_clones;
 float sv_foginterval;
 
@@ -30,7 +34,9 @@ float server_is_dedicated;
 
 // Fields
 
-.void(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force) event_damage;
+.void(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force) event_damage;
+
+.bool(entity targ, entity inflictor, float amount, float limit) event_heal;
 
 //.string      wad;
 //.string      map;
@@ -178,8 +184,6 @@ float default_weapon_alpha;
 
 string gamemode_name;
 
-float startitem_failed;
-
 string W_Apply_Weaponreplace(string in);
 
 void FixIntermissionClient(entity e);
@@ -188,8 +192,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;
@@ -224,7 +226,10 @@ int have_team_spawns_forteams; // if Xth bit is 1 then team X has spawns else it
 
 .bool canteamdamage;
 
-void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
+
+// WEAPONTODO
+#define DMG_NOWEP (weaponentities[0])
 
 float lockteams;
 
@@ -274,9 +279,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)
 
@@ -299,18 +301,8 @@ float servertime, serverprevtime, serverframetime;
 .float floodcontrol_voice;
 .float floodcontrol_voiceteam;
 
-.float stat_shotorg = _STAT(SHOTORG); // networked stat for trueaim HUD
-
 string matchid;
 
-.float last_pickup = _STAT(LAST_PICKUP);
-
-.float hit_time = _STAT(HIT_TIME);
-.float typehit_time = _STAT(TYPEHIT_TIME);
-.float kill_time = _STAT(KILL_TIME);
-
-.float damage_dealt_total = _STAT(DAMAGE_DEALT_TOTAL);
-
 bool radar_showennemies;
 
 #ifdef PROFILING
@@ -320,15 +312,18 @@ float client_cefc_accumulatortime;
 
 .float weapon_load[Weapons_MAX];
 .int ammo_none; // used by the reloading system, must always be 0
-.float clip_load = _STAT(WEAPON_CLIPLOAD);
+.float clip_load;
 .float old_clip_load;
-.float clip_size = _STAT(WEAPON_CLIPSIZE);
+.float clip_size;
 
-.float minelayer_mines = _STAT(LAYED_MINES);
-.float vortex_charge = _STAT(VORTEX_CHARGE);
+.int minelayer_mines;
+.float vortex_charge;
 .float vortex_charge_rottime;
-.float vortex_chargepool_ammo = _STAT(VORTEX_CHARGEPOOL);
-.float hagar_load = _STAT(HAGAR_LOAD);
+.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
 
@@ -367,17 +362,15 @@ const float ACTIVE_TOGGLE         = 3;
 
 .float player_blocked;
 
-.float revive_progress = _STAT(REVIVE_PROGRESS);
 .float revival_time; // time at which player was last revived
 .float revive_speed; // NOTE: multiplier (anything above 1 is instaheal)
+.float freeze_time;
 .entity iceblock;
 .entity frozen_by; // for ice fields
 
 .entity muzzle_flash;
 .float misc_bulletcounter;     // replaces uzi & hlac bullet counter.
 
-.float stat_respawn_time = _STAT(RESPAWN_TIME); // shows respawn time, and is negative when awaiting respawn
-
 .int killindicator_teamchange;
 
 void PlayerUseKey(entity this);
@@ -413,67 +406,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 029660c2bf05c2e98975f609e8c35d943d4f168d..38284c30decd8a5b3adae3fbebe9039ef7e560ef 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"
@@ -32,7 +35,7 @@ void UpdateFrags(entity player, int f)
        GameRules_scoring_add_team(player, SCORE, f);
 }
 
-void GiveFrags (entity attacker, entity targ, float f, int deathtype)
+void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity)
 {
        // TODO route through PlayerScores instead
        if(game_stopped) return;
@@ -60,53 +63,8 @@ void GiveFrags (entity attacker, entity targ, float f, int deathtype)
 
        GameRules_scoring_add(targ, DEATHS, 1);
 
-       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
-
-       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;
@@ -264,9 +222,7 @@ 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);
 }
 
-.int buffs = _STAT(BUFFS); // TODO: remove
-entity buff_FirstFromFlags(int _buffs);
-void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity)
 {
        // Sanity check
        if (!IS_PLAYER(targ)) { backtrace("Obituary called on non-player?!\n"); return; }
@@ -328,7 +284,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                }
                LogDeath("suicide", deathtype, targ, targ);
                if(deathtype != DEATH_AUTOTEAMCHANGE.m_id) // special case: don't negate frags if auto switched
-                       GiveFrags(attacker, targ, -1, deathtype);
+                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
        }
 
        // ======
@@ -339,7 +295,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                if(SAME_TEAM(attacker, targ))
                {
                        LogDeath("tk", deathtype, attacker, targ);
-                       GiveFrags(attacker, targ, -1, deathtype);
+                       GiveFrags(attacker, targ, -1, deathtype, weaponentity);
 
                        CS(attacker).killcount = 0;
 
@@ -353,7 +309,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                else
                {
                        LogDeath("frag", deathtype, attacker, targ);
-                       GiveFrags(attacker, targ, 1, deathtype);
+                       GiveFrags(attacker, targ, 1, deathtype, weaponentity);
 
                        CS(attacker).taunt_soundtime = time + 1;
                        CS(attacker).killcount = CS(attacker).killcount + 1;
@@ -445,7 +401,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
 
                        int f3 = 0;
                        if(deathtype == DEATH_BUFF.m_id)
-                               f3 = buff_FirstFromFlags(attacker.buffs).m_id;
+                               f3 = buff_FirstFromFlags(STAT(BUFFS, attacker)).m_id;
 
                        if (!Obituary_WeaponDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, CS(targ).killcount, kill_count_to_attacker))
                                Obituary_SpecialDeath(targ, true, deathtype, targ.netname, attacker.netname, deathlocation, CS(targ).killcount, kill_count_to_attacker, f3);
@@ -494,7 +450,7 @@ void Obituary(entity attacker, entity inflictor, entity targ, int deathtype)
                }
 
                LogDeath("accident", deathtype, targ, targ);
-               GiveFrags(targ, targ, -1, deathtype);
+               GiveFrags(targ, targ, -1, deathtype, weaponentity);
 
                if(GameRules_scoring_add(targ, SCORE, 0) == -5)
                {
@@ -521,9 +477,9 @@ void Ice_Think(entity this)
        this.nextthink = time;
 }
 
-void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint)
+void Freeze(entity targ, float revivespeed, int frozen_type, bool show_waypoint)
 {
-       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // only specified entities can be freezed
+       if(!IS_PLAYER(targ) && !IS_MONSTER(targ)) // TODO: only specified entities can be freezed
                return;
 
        if(STAT(FROZEN, targ))
@@ -532,12 +488,13 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
        float targ_maxhealth = ((IS_MONSTER(targ)) ? targ.max_health : start_health);
 
        STAT(FROZEN, targ) = frozen_type;
-       targ.revive_progress = ((frozen_type == 3) ? 1 : 0);
+       STAT(REVIVE_PROGRESS, targ) = ((frozen_type == 3) ? 1 : 0);
        SetResourceAmount(targ, RESOURCE_HEALTH, ((frozen_type == 3) ? targ_maxhealth : 1));
-       targ.revive_speed = freeze_time;
+       targ.revive_speed = revivespeed;
        if(targ.bot_attack)
                IL_REMOVE(g_bot_targets, targ);
        targ.bot_attack = false;
+       targ.freeze_time = time;
 
        entity ice = new(ice);
        ice.owner = targ;
@@ -567,11 +524,11 @@ void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypo
        });
 
        // add waypoint
-       if(show_waypoint)
+       if(MUTATOR_CALLHOOK(Freeze, targ, revivespeed, frozen_type) || show_waypoint)
                WaypointSprite_Spawn(WP_Frozen, 0, 0, targ, '0 0 64', NULL, targ.team, targ, waypointsprite_attached, true, RADARICON_WAYPOINT);
 }
 
-void Unfreeze (entity targ)
+void Unfreeze(entity targ)
 {
        if(!STAT(FROZEN, targ))
                return;
@@ -583,7 +540,7 @@ void Unfreeze (entity targ)
        }
 
        STAT(FROZEN, targ) = 0;
-       targ.revive_progress = 0;
+       STAT(REVIVE_PROGRESS, targ) = 0;
        targ.revival_time = time;
        if(!targ.bot_attack)
                IL_PUSH(g_bot_targets, targ);
@@ -605,9 +562,11 @@ void Unfreeze (entity targ)
        if(targ.iceblock)
                delete(targ.iceblock);
        targ.iceblock = NULL;
+
+       MUTATOR_CALLHOOK(Unfreeze, targ);
 }
 
-void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        float complainteamdamage = 0;
        float mirrordamage = 0;
@@ -636,9 +595,9 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                // These are ALWAYS lethal
                // No damage modification here
                // Instead, prepare the victim for his death...
-               SetResourceAmount(targ, RESOURCE_ARMOR, 0);
+               SetResourceAmountExplicit(targ, RESOURCE_ARMOR, 0);
                targ.spawnshieldtime = 0;
-               SetResourceAmount(targ, RESOURCE_HEALTH, 0.9); // this is < 1
+               SetResourceAmountExplicit(targ, RESOURCE_HEALTH, 0.9); // this is < 1
                targ.flags -= targ.flags & FL_GODMODE;
                damage = 100000;
        }
@@ -679,7 +638,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
 
                                                        if(autocvar_g_mirrordamage_virtual)
                                                        {
-                                                               vector v  = healtharmor_applydamage(attacker.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
+                                                               vector v  = healtharmor_applydamage(GetResourceAmount(attacker, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, mirrordamage);
                                                                attacker.dmg_take += v.x;
                                                                attacker.dmg_save += v.y;
                                                                attacker.dmg_inflictor = inflictor;
@@ -689,7 +648,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
 
                                                        if(autocvar_g_friendlyfire_virtual)
                                                        {
-                                                               vector v = healtharmor_applydamage(targ.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
+                                                               vector v = healtharmor_applydamage(GetResourceAmount(targ, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
                                                                targ.dmg_take += v.x;
                                                                targ.dmg_save += v.y;
                                                                targ.dmg_inflictor = inflictor;
@@ -715,7 +674,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                }
 
                // 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);
@@ -724,9 +683,9 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                {
                        for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                    {
-                       .entity weaponentity = weaponentities[slot];
-                       if(targ.(weaponentity).hook && targ.(weaponentity).hook.aiment == attacker)
-                               RemoveHook(targ.(weaponentity).hook);
+                       .entity went = weaponentities[slot];
+                       if(targ.(went).hook && targ.(went).hook.aiment == attacker)
+                               RemoveHook(targ.(went).hook);
                    }
                }
 
@@ -781,7 +740,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                        }
                }
 
-               if(!g_instagib)
+               if(!MUTATOR_IS_ENABLED(mutator_instagib))
                {
                        // apply strength multiplier
                        if (attacker.items & ITEM_Strength.m_itemid)
@@ -800,7 +759,13 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
 
                        // apply invincibility multiplier
                        if (targ.items & ITEM_Shield.m_itemid)
+                       {
                                damage = damage * autocvar_g_balance_powerup_invincible_takedamage;
+                               if (targ != attacker)
+                               {
+                                       force = force * autocvar_g_balance_powerup_invincible_takeforce;
+                               }
+                       }
                }
 
                if (targ == attacker)
@@ -890,7 +855,7 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
        // apply damage
        if (damage != 0 || (targ.damageforcescale && force))
        if (targ.event_damage)
-               targ.event_damage (targ, inflictor, attacker, damage, deathtype, hitloc, force);
+               targ.event_damage (targ, inflictor, attacker, damage, deathtype, weaponentity, hitloc, force);
 
        // apply mirror damage if any
        if(!autocvar_g_mirrordamage_onlyweapons || DEATH_WEAPONOF(deathtype) != WEP_Null)
@@ -899,11 +864,12 @@ void Damage (entity targ, entity inflictor, entity attacker, float damage, int d
                attacker = attacker_save;
 
                force = normalize(attacker.origin + attacker.view_ofs - hitloc) * mirrorforce;
-               Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE.m_id, attacker.origin, force);
+               Damage(attacker, inflictor, attacker, mirrordamage, DEATH_MIRRORDAMAGE.m_id, weaponentity, attacker.origin, force);
        }
 }
 
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, int deathtype, entity directhitentity)
+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
 {
        entity  targ;
@@ -1074,9 +1040,9 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
                                                }
 
                                                if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
-                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype, nearest, force);
+                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype, weaponentity, nearest, force);
                                                else
-                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, nearest, force);
+                                                       Damage (targ, inflictor, attacker, finaldmg, deathtype | HITTYPE_SPLASH, weaponentity, nearest, force);
                                        }
                                }
                        }
@@ -1092,9 +1058,23 @@ float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector in
        return total_damage_to_creatures;
 }
 
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, entity directhitentity)
+float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
 {
-       return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, directhitentity);
+       return RadiusDamageForSource (inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
+}
+
+bool Heal(entity targ, entity inflictor, float amount, float limit)
+{
+       if(game_stopped || (IS_CLIENT(targ) && CS(targ).killcount == FRAGS_SPECTATOR) || STAT(FROZEN, targ) || IS_DEAD(targ))
+               return false;
+
+       bool healed = false;
+       if(targ.event_heal)
+               healed = targ.event_heal(targ, inflictor, amount, limit);
+       // TODO: additional handling? what if the healing kills them? should this abort if healing would do so etc
+       // TODO: healing fx!
+       // TODO: armor healing?
+       return healed;
 }
 
 float Fire_IsBurning(entity e)
@@ -1247,7 +1227,7 @@ void Fire_ApplyDamage(entity e)
 
        hi = e.fire_owner.damage_dealt;
        ty = e.fire_owner.typehitsound;
-       Damage(e, e, e.fire_owner, d, e.fire_deathtype, e.origin, '0 0 0');
+       Damage(e, e, e.fire_owner, d, e.fire_deathtype, DMG_NOWEP, e.origin, '0 0 0');
        if(e.fire_hitsound && e.fire_owner)
        {
                e.fire_owner.damage_dealt = hi;
index aee4a93df80da7cecde86899592331cd79b55777..0af110c9e890f29925db0803eedcd8d29f4eba04 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,8 +58,7 @@ 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);
+void GiveFrags (entity attacker, entity targ, float f, int deathtype, .entity weaponentity);
 
 string AppendItemcodes(string s, entity player);
 
@@ -80,21 +79,26 @@ float Obituary_WeaponDeath(
        string s1, string s2, string s3,
        float f1, float f2);
 
-void Obituary(entity attacker, entity inflictor, entity targ, int deathtype);
+void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity);
 
 void Ice_Think(entity this);
 
-void Freeze (entity targ, float freeze_time, float frozen_type, float show_waypoint);
+void Freeze(entity targ, float freeze_time, int frozen_type, bool show_waypoint);
 
 void Unfreeze (entity targ);
 
-void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+// NOTE: the .weaponentity parameter can be set to DMG_NOWEP if the attack wasn't caused by a weapon or player
+void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
 
 float RadiusDamage_running;
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, int deathtype, entity directhitentity);
+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
 
-float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, entity directhitentity);
+float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity);
+
+// Calls .event_heal on the target so that they can handle healing themselves
+// a limit of RESOURCE_LIMIT_NONE should be handled by the entity as its max health (if applicable)
+bool Heal(entity targ, entity inflictor, float amount, float limit);
 
 .float fire_damagepersec;
 .float fire_endtime;
index 0fc60b2cdc1ffef3f4a2bac6832822e2a0c91db3..68aa7154ecdc3928261ea584bd251be2c86d2c03 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);
@@ -140,15 +139,11 @@ bool GrapplingHookSend(entity this, entity to, int sf)
        }
        if(sf & 2)
        {
-               WriteCoord(MSG_ENTITY, this.hook_start.x);
-               WriteCoord(MSG_ENTITY, this.hook_start.y);
-               WriteCoord(MSG_ENTITY, this.hook_start.z);
+               WriteVector(MSG_ENTITY, this.hook_start);
        }
        if(sf & 4)
        {
-               WriteCoord(MSG_ENTITY, this.hook_end.x);
-               WriteCoord(MSG_ENTITY, this.hook_end.y);
-               WriteCoord(MSG_ENTITY, this.hook_end.z);
+               WriteVector(MSG_ENTITY, this.hook_end);
        }
        return true;
 }
@@ -332,7 +327,7 @@ void GrapplingHookTouch(entity this, entity toucher)
        GrapplingHook_Stop(this);
 
        if(toucher)
-               if(toucher.move_movetype != MOVETYPE_NONE)
+               //if(toucher.move_movetype != MOVETYPE_NONE)
                {
                        SetMovetypeFollow(this, toucher);
                        WarpZone_RefSys_BeginAddingIncrementally(this, this.aiment);
@@ -341,17 +336,17 @@ void GrapplingHookTouch(entity this, entity toucher)
        //this.realowner.disableclientprediction = true;
 }
 
-void GrapplingHook_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void GrapplingHook_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
-       if(this.health <= 0)
+       if(GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
                return;
 
        if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
                return; // g_balance_projectiledamage says to halt
 
-       this.health = this.health - damage;
+       TakeResource(this, RESOURCE_HEALTH, damage);
 
-       if (this.health <= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
        {
                if(attacker != this.realowner)
                {
@@ -368,19 +363,9 @@ void FireGrapplingHook(entity actor, .entity weaponentity)
        if(forbidWeaponUse(actor)) return;
        if(actor.vehicle) return;
 
-       makevectors(actor.v_angle);
-
-       int s = W_GunAlign(actor.(weaponentity), STAT(GUNALIGN, actor)) - 1;
-       vector vs = hook_shotorigin[s];
-
-       // UGLY WORKAROUND: play this on CH_WEAPON_B so it can't cut off fire sounds
-       sound (actor, CH_WEAPON_B, SND_HOOK_FIRE, VOL_BASE, ATTEN_NORM);
-       vector org = actor.origin + actor.view_ofs + v_forward * vs.x + v_right * -vs.y + v_up * vs.z;
-
-       tracebox(actor.origin + actor.view_ofs, '-3 -3 -3', '3 3 3', org, MOVE_NORMAL, actor);
-       org = trace_endpos;
-
-       Send_Effect(EFFECT_HOOK_MUZZLEFLASH, org, '0 0 0', 1);
+       // TODO: offhand hook shoots from eye
+       W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', true, 0, SND_HOOK_FIRE, CH_WEAPON_B, 0, WEP_HOOK.m_id);
+       Send_Effect(EFFECT_HOOK_MUZZLEFLASH, w_shotorg, '0 0 0', 1);
 
        entity missile = WarpZone_RefSys_SpawnSameRefSys(actor);
        missile.owner = missile.realowner = actor;
@@ -397,11 +382,11 @@ void FireGrapplingHook(entity actor, .entity weaponentity)
 
        //setmodel (missile, MDL_HOOK); // precision set below
        setsize (missile, '-3 -3 -3', '3 3 3');
-       setorigin(missile, org);
+       setorigin(missile, w_shotorg);
 
        missile.state = 0; // not latched onto anything
 
-       W_SetupProjVelocity_Explicit(missile, v_forward, v_up, autocvar_g_balance_grapplehook_speed_fly, 0, 0, 0, false);
+       W_SetupProjVelocity_Explicit(missile, w_shotdir, v_up, autocvar_g_balance_grapplehook_speed_fly, 0, 0, 0, false);
 
        missile.angles = vectoangles (missile.velocity);
        //missile.glow_color = 250; // 244, 250
@@ -412,7 +397,7 @@ void FireGrapplingHook(entity actor, .entity weaponentity)
 
        missile.effects = /*EF_FULLBRIGHT | EF_ADDITIVE |*/ EF_LOWPRECISION;
 
-       missile.health = autocvar_g_balance_grapplehook_health;//120
+       SetResourceAmountExplicit(missile, RESOURCE_HEALTH, autocvar_g_balance_grapplehook_health);
        missile.event_damage = GrapplingHook_Damage;
        missile.takedamage = DAMAGE_AIM;
        missile.damageforcescale = 0;
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 539522f..0000000
+++ /dev/null
@@ -1,202 +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))
-       {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
-       }
-
-       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)
-               {
-                       WriteCoord(MSG_ENTITY, this.mins.x);
-                       WriteCoord(MSG_ENTITY, this.mins.y);
-                       WriteCoord(MSG_ENTITY, this.mins.z);
-                       WriteCoord(MSG_ENTITY, this.maxs.x);
-                       WriteCoord(MSG_ENTITY, this.maxs.y);
-                       WriteCoord(MSG_ENTITY, this.maxs.z);
-               }
-               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));
-                       WriteCoord(MSG_ENTITY, this.movedir.x);
-                       WriteCoord(MSG_ENTITY, this.movedir.y);
-                       WriteCoord(MSG_ENTITY, this.movedir.z);
-                       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 2eda8584ef5d82eeb9f346cb131aa9a049a58488..26a4cfb08685c3d16f58f8acd5416d693ed65b18 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");
 
@@ -361,10 +356,12 @@ void cvar_changes_init()
                BADCVAR("sv_stepheight");
                BADCVAR("sv_timeout");
                BADCVAR("sv_weapons_modeloverride");
+               BADCVAR("w_prop_interval");
                BADPREFIX("crypto_");
                BADPREFIX("gameversion_");
                BADPREFIX("g_chat_");
                BADPREFIX("g_ctf_captimerecord_");
+               BADPREFIX("g_hats_");
                BADPREFIX("g_maplist_");
                BADPREFIX("g_mod_");
                BADPREFIX("g_respawn_");
@@ -508,38 +505,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 +578,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 +832,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());
@@ -990,45 +948,43 @@ float GetMaplistPosition()
        return idx;
 }
 
-float MapHasRightSize(string map)
+bool MapHasRightSize(string map)
 {
-       float fh;
        if(currentbots || autocvar_bot_number || player_count < autocvar_minplayers)
        if(autocvar_g_maplist_check_waypoints)
        {
-               LOG_TRACE("checkwp "); LOG_TRACE(map);
+               string checkwp_msg = strcat("checkwp ", map);
                if(!fexists(strcat("maps/", map, ".waypoints")))
                {
-                       LOG_TRACE(": no waypoints");
+                       LOG_TRACE(checkwp_msg, ": no waypoints");
                        return false;
                }
-               LOG_TRACE(": has waypoints");
+               LOG_TRACE(checkwp_msg, ": has waypoints");
        }
 
        // open map size restriction file
-       LOG_TRACE("opensize "); LOG_TRACE(map);
-       fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ);
+       string opensize_msg = strcat("opensize ", map);
+       float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ);
        if(fh >= 0)
        {
-               float mapmin, mapmax;
-               LOG_TRACE(": ok, ");
-               mapmin = stof(fgets(fh));
-               mapmax = stof(fgets(fh));
+               opensize_msg = strcat(opensize_msg, ": ok, ");
+               int mapmin = stoi(fgets(fh));
+               int mapmax = stoi(fgets(fh));
                fclose(fh);
                if(player_count < mapmin)
                {
-                       LOG_TRACE("not enough");
+                       LOG_TRACE(opensize_msg, "not enough");
                        return false;
                }
-               if(player_count > mapmax)
+               if(mapmax && player_count > mapmax)
                {
-                       LOG_TRACE("too many");
+                       LOG_TRACE(opensize_msg, "too many");
                        return false;
                }
-               LOG_TRACE("right size");
+               LOG_TRACE(opensize_msg, "right size");
                return true;
        }
-       LOG_TRACE(": not found");
+       LOG_TRACE(opensize_msg, ": not found");
        return true;
 }
 
@@ -1096,7 +1052,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;
 
@@ -1115,7 +1071,7 @@ float() MaplistMethod_Iterate = // usual method
        return -1;
 }
 
-float() MaplistMethod_Repeat = // fallback method
+float MaplistMethod_Repeat() // fallback method
 {
        LOG_TRACE("Trying MaplistMethod_Repeat");
 
@@ -1124,7 +1080,7 @@ float() MaplistMethod_Repeat = // fallback method
        return -2;
 }
 
-float() MaplistMethod_Random = // random map selection
+float MaplistMethod_Random() // random map selection
 {
        float i, imax;
 
@@ -1142,7 +1098,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
 {
@@ -1201,9 +1157,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
 }
@@ -1513,7 +1467,7 @@ void FixIntermissionClient(entity e)
        if(!e.autoscreenshot) // initial call
        {
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
-               e.health = -2342;
+               SetResourceAmountExplicit(e, RESOURCE_HEALTH, -2342);
                // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
                for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
@@ -2069,12 +2023,12 @@ void EndFrame()
        FOREACH_CLIENT(IS_REAL_CLIENT(it), {
                entity e = IS_SPEC(it) ? it.enemy : it;
                if (e.typehitsound) {
-                       it.typehit_time = time;
+                       STAT(TYPEHIT_TIME, it) = time;
                } else if (e.killsound) {
-                       it.kill_time = time;
+                       STAT(KILL_TIME, it) = time;
                } else if (e.damage_dealt) {
-                       it.hit_time = time;
-                       it.damage_dealt_total += ceil(e.damage_dealt);
+                       STAT(HIT_TIME, it) = time;
+                       STAT(DAMAGE_DEALT_TOTAL, it) += ceil(e.damage_dealt);
                }
        });
        // add 1 frametime because after this, engine SV_Physics
@@ -2149,7 +2103,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..5c564d56db45fc7baeabeb9c6fd22240cc4263df 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]);
        }
 }
 
@@ -599,9 +591,9 @@ void MapVote_Tick()
        int totalvotes = 0;
        FOREACH_CLIENT(IS_REAL_CLIENT(it), {
                // hide scoreboard again
-               if(it.health != 2342)
+               if(GetResourceAmount(it, RESOURCE_HEALTH) != 2342)
                {
-                       it.health = 2342;
+                       SetResourceAmountExplicit(it, RESOURCE_HEALTH, 2342);
                        CS(it).impulse = 0;
 
                        msg_entity = it;
index 8b4204b126dfa1d1b44306a0abc51222391bc837..319b6f16ff7e3c7c333d8fb3a67e2b360eefbde8 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;
@@ -260,13 +266,13 @@ string formatmessage(entity this, string msg)
                        case "%": replacement = "%"; break;
                        case "\\":replacement = "\\"; break;
                        case "n": replacement = "\n"; break;
-                       case "a": replacement = ftos(floor(this.armorvalue)); break;
-                       case "h": replacement = ftos(floor(this.health)); break;
+                       case "a": replacement = ftos(floor(GetResourceAmount(this, RESOURCE_ARMOR))); break;
+                       case "h": replacement = ftos(floor(GetResourceAmount(this, RESOURCE_HEALTH))); break;
                        case "l": replacement = NearestLocation(this.origin); break;
                        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(this.weaponorder_byimpulse)
-       {
-               strunzone(this.weaponorder_byimpulse);
-               this.weaponorder_byimpulse = string_null;
-       }
-       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
@@ -1071,7 +1060,7 @@ bool SUB_NoImpactCheck(entity this, entity toucher)
        if(trace_dphitcontents == 0)
        {
                LOG_TRACEF("A hit from a projectile happened with no hit contents! DEBUG THIS, this should never happen for projectiles! Projectile will self-destruct. (edict: %i, classname: %s, origin: %v)", this, this.classname, this.origin);
-               checkclient(this);
+               checkclient(this); // TODO: .health is checked in the engine with this, possibly replace with a QC function?
        }
     if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
         return true;
@@ -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 1dd3526dd48c435eaa00ade8bc1a0047b767079a..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");
@@ -235,6 +234,9 @@ void readlevelcvars()
        sv_maxidle_slots_countbots = cvar("sv_maxidle_slots_countbots");
        sv_autotaunt = cvar("sv_autotaunt");
        sv_taunt = cvar("sv_taunt");
+       sv_ready_restart = cvar("sv_ready_restart");
+       sv_ready_restart_after_countdown = cvar("sv_ready_restart_after_countdown");
+       sv_ready_restart_repeatable = cvar("sv_ready_restart_repeatable");
 
        warmup_stage = cvar("g_warmup");
        warmup_limit = cvar("g_warmup_limit");
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 fb452c3399b9bb4ab39721abb574ec32944ccff4..a4cf9df8ef30cc5e6554f4403112a28723a07e84 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,43 @@ 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 when some resource is being taken from an entity. See RESOURCE_* constants
+for resource types. Return true to forbid giving. */
+#define EV_TakeResource(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) \
+    /**/
+MUTATOR_HOOKABLE(TakeResource, EV_TakeResource);
+
+/** Called when some resource is being taken from an entity, with a limit. See
+RESOURCE_* constants for resource types. Return true to forbid giving. */
+#define EV_TakeResourceWithLimit(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(TakeResourceWithLimit, EV_TakeResourceWithLimit);
+
 /** called at when a player connect */
 #define EV_ClientConnect(i, o) \
     /** player */ i(entity, MUTATOR_ARGV_0_entity) \
@@ -1060,8 +1139,56 @@ 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) \
     /**/
 MUTATOR_HOOKABLE(HavocBot_Aim, EV_HavocBot_Aim);
+
+/** return true to skip respawn time calculations */
+#define EV_CalculateRespawnTime(i, o) \
+    /** 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)
+};
+
+/**
+ * Called when freezing an entity (monster or player), return true to force showing a waypoint
+ */
+#define EV_Freeze(i, o) \
+    /** targ */             i(entity, MUTATOR_ARGV_0_entity) \
+    /** revive speed */     i(float, MUTATOR_ARGV_1_float) \
+    /** frozen type */      i(int, MUTATOR_ARGV_2_int) \
+    /**/
+MUTATOR_HOOKABLE(Freeze, EV_Freeze);
+
+/**
+ * Called when an entity (monster or player) is defrosted
+ */
+#define EV_Unfreeze(i, o) \
+    /** targ */             i(entity, MUTATOR_ARGV_0_entity) \
+    /**/
+MUTATOR_HOOKABLE(Unfreeze, EV_Unfreeze);
diff --git a/qcsrc/server/mutators/gamemode.qh b/qcsrc/server/mutators/gamemode.qh
deleted file mode 100644 (file)
index 5de2a65..0000000
+++ /dev/null
@@ -1,112 +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;
-.float redalive_stat = _STAT(REDALIVE);
-.float bluealive_stat = _STAT(BLUEALIVE);
-.float yellowalive_stat = _STAT(YELLOWALIVE);
-.float pinkalive_stat = _STAT(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 50861c3..0000000
+++ /dev/null
@@ -1,616 +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)
-{
-       // no assault warmups
-       warmup_stage = 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 919df49..0000000
+++ /dev/null
@@ -1,481 +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), {
-               it.redalive_stat = redalive;
-               it.bluealive_stat = bluealive;
-               it.yellowalive_stat = yellowalive;
-               it.pinkalive_stat = 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, 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 3c714ad..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, 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, 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, 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.
-       player.ctf_flagstatus &= ~(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; player.ctf_flagstatus |= CTF_FLAG_NEUTRAL; }
-
-               switch(flag.ctf_status)
-               {
-                       case FLAG_PASSING:
-                       case FLAG_CARRY:
-                       {
-                               if((flag.owner == player) || (flag.pass_sender == player))
-                                       player.ctf_flagstatus |= t; // carrying: player is currently carrying the flag
-                               else
-                                       player.ctf_flagstatus |= t2; // taken: someone else is carrying the flag
-                               break;
-                       }
-                       case FLAG_DROPPED:
-                       {
-                               player.ctf_flagstatus |= 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)
-               player.ctf_flagstatus |= CTF_SHIELDED;
-
-       if(ctf_stalemate)
-               player.ctf_flagstatus |= 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);
-
-       client.ctf_flagstatus = spectatee.ctf_flagstatus;
-}
-
-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 33d64a0..0000000
+++ /dev/null
@@ -1,193 +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))
-
-// networked flag statuses
-.int ctf_flagstatus = _STAT(CTF_FLAGSTATUS);
-#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 5980cfb..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)
-{
-       e.dom_total_pps = total_pps;
-       e.dom_pps_red = pps_red;
-       e.dom_pps_blue = pps_blue;
-       if(domination_teams >= 3)
-               e.dom_pps_yellow = pps_yellow;
-       if(domination_teams >= 4)
-               e.dom_pps_pink = 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(this.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 cf5e54f..0000000
+++ /dev/null
@@ -1,58 +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 dom_total_pps = _STAT(DOM_TOTAL_PPS);
-.float dom_pps_red = _STAT(DOM_PPS_RED);
-.float dom_pps_blue = _STAT(DOM_PPS_BLUE);
-.float dom_pps_yellow = _STAT(DOM_PPS_YELLOW);
-.float dom_pps_pink = _STAT(DOM_PPS_PINK);
-float total_pps;
-float pps_red;
-float pps_blue;
-float pps_yellow;
-float pps_pink;
-
-// capture declarations
-.float enemy_playerid;
-.entity sprite;
-.float captime;
-
-// misc globals
-float domination_roundbased;
-float domination_teams;
-
-void AnimateDomPoint(entity this);
-
-IntrusiveList g_dompoints;
-STATIC_INIT(g_dompoints) { g_dompoints = IL_NEW(); }
diff --git a/qcsrc/server/mutators/mutator/gamemode_freezetag.qc b/qcsrc/server/mutators/mutator/gamemode_freezetag.qc
deleted file mode 100644 (file)
index 2ea70c1..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), {
-               it.redalive_stat = redalive;
-               it.bluealive_stat = bluealive;
-               it.yellowalive_stat = yellowalive;
-               it.pinkalive_stat = 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
-       {
-               player.revive_progress = bound(0, player.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               player.health = max(1, player.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
-
-               if(player.revive_progress >= 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, {
-                       it.revive_progress = player.revive_progress;
-                       it.reviving = false;
-               });
-       }
-       else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
-       {
-               player.revive_progress = bound(0, player.revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-               player.health = max(1, player.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
-       }
-       else if(!n && !STAT(FROZEN, player))
-       {
-               player.revive_progress = 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 badae12..0000000
+++ /dev/null
@@ -1,476 +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;
-}
-
-.float stat_sv_airspeedlimit_nonqw;
-.float stat_sv_maxspeed;
-
-MUTATOR_HOOKFUNCTION(ka, PlayerPhysics)
-{
-       entity player = M_ARGV(0, entity);
-
-       if(player.ballcarried)
-       {
-               player.stat_sv_airspeedlimit_nonqw *= autocvar_g_keepaway_ballcarrier_highspeed;
-               player.stat_sv_maxspeed *= 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 e6253b0..0000000
+++ /dev/null
@@ -1,1322 +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
-.int kh_state = _STAT(KH_KEYS);
-.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, { it.kh_state = s; });
-
-       FOR_EACH_KH_KEY(key)
-       {
-               if(key.owner)
-                       key.owner.kh_state |= (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, 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);
-
-       client.kh_state = spectatee.kh_state;
-}
-
-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 26fc9e659204d7bf6305a5d2483bf1b2b4ba9819..5bd4b59894e964fcd6b0850a3f67232c8f38a79c 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"
@@ -74,6 +74,7 @@ void CopyBody(entity this, float keepvelocity)
        clone.effects = this.effects;
        clone.glowmod = this.glowmod;
        clone.event_damage = this.event_damage;
+       clone.event_heal = this.event_heal;
        clone.anim_state = this.anim_state;
        clone.anim_time = this.anim_time;
        clone.anim_lower_action = this.anim_lower_action;
@@ -89,8 +90,8 @@ void CopyBody(entity this, float keepvelocity)
        clone.dphitcontentsmask = this.dphitcontentsmask;
        clone.death_time = this.death_time;
        clone.pain_finished = this.pain_finished;
-       clone.health = this.health;
-       clone.armorvalue = this.armorvalue;
+       SetResourceAmountExplicit(clone, RESOURCE_HEALTH, GetResourceAmount(this, RESOURCE_HEALTH));
+       SetResourceAmountExplicit(clone, RESOURCE_ARMOR, GetResourceAmount(this, RESOURCE_ARMOR));
        clone.armortype = this.armortype;
        clone.model = this.model;
        clone.modelindex = this.modelindex;
@@ -167,16 +168,13 @@ void player_anim(entity this)
        animdecide_setimplicitstate(this, IS_ONGROUND(this));
 }
 
-void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        float take, save;
        vector v;
        Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
-       // damage resistance (ignore most of the damage from a bullet or similar)
-       damage = max(damage - 5, 1);
-
-       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
+       v = healtharmor_applydamage(GetResourceAmount(this, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
        take = v.x;
        save = v.y;
 
@@ -195,8 +193,8 @@ void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float da
        if (take > 100)
                Violence_GibSplash_At(hitloc, force * -0.2, 3, 1, this, attacker);
 
-       this.armorvalue = this.armorvalue - save;
-       this.health = this.health - take;
+       TakeResource(this, RESOURCE_ARMOR, save);
+       TakeResource(this, RESOURCE_HEALTH, take);
        // pause regeneration for 5 seconds
        this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
 
@@ -204,7 +202,7 @@ void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float da
        this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
        this.dmg_inflictor = inflictor;
 
-       if (this.health <= -autocvar_sv_gibhealth && this.alpha >= 0)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) <= -autocvar_sv_gibhealth && this.alpha >= 0)
        {
                // don't use any animations as a gib
                this.frame = 0;
@@ -223,7 +221,7 @@ void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float da
 
 void calculate_player_respawn_time(entity this)
 {
-       if(g_ca)
+       if(MUTATOR_CALLHOOK(CalculateRespawnTime, this))
                return;
 
        float gametype_setting_tmp;
@@ -307,14 +305,14 @@ void calculate_player_respawn_time(entity this)
                this.respawn_flags = this.respawn_flags | RESPAWN_FORCE;
 }
 
-void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        float take, save, dh, da;
        vector v;
        float excess;
 
-       dh = max(this.health, 0);
-       da = max(this.armorvalue, 0);
+       dh = max(GetResourceAmount(this, RESOURCE_HEALTH), 0);
+       da = max(GetResourceAmount(this, RESOURCE_ARMOR), 0);
 
        if(!DEATH_ISSPECIAL(deathtype))
        {
@@ -362,7 +360,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        else
                Violence_GibSplash_At(hitloc, force, 2, bound(0, damage, 200) / 16, this, attacker);
 
-       v = healtharmor_applydamage(this.armorvalue, autocvar_g_balance_armor_blockpercent, deathtype, damage);
+       v = healtharmor_applydamage(GetResourceAmount(this, RESOURCE_ARMOR), autocvar_g_balance_armor_blockpercent, deathtype, damage);
        take = v.x;
        save = v.y;
 
@@ -391,8 +389,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        }
 
        MUTATOR_CALLHOOK(PlayerDamage_SplitHealthArmor, inflictor, attacker, this, force, take, save, deathtype, damage);
-       take = bound(0, M_ARGV(4, float), this.health);
-       save = bound(0, M_ARGV(5, float), this.armorvalue);
+       take = bound(0, M_ARGV(4, float), GetResourceAmount(this, RESOURCE_HEALTH));
+       save = bound(0, M_ARGV(5, float), GetResourceAmount(this, RESOURCE_ARMOR));
        excess = max(0, damage - take - save);
 
        if(sound_allowed(MSG_BROADCAST, attacker))
@@ -414,8 +412,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        {
                if (!(this.flags & FL_GODMODE))
                {
-                       this.armorvalue = this.armorvalue - save;
-                       this.health = this.health - take;
+                       TakeResource(this, RESOURCE_ARMOR, save);
+                       TakeResource(this, RESOURCE_HEALTH, take);
                        // pause regeneration for 5 seconds
                        if(take)
                                this.pauseregen_finished = max(this.pauseregen_finished, time + autocvar_g_balance_pause_health_regen);
@@ -435,19 +433,19 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                                                                animdecide_setaction(this, ANIMACTION_PAIN2, true);
                                                }
                                        }
-
+                                       float myhp = GetResourceAmount(this, RESOURCE_HEALTH);
+                                       if(myhp > 1)
+                                       if(myhp < 25 || !(DEATH_WEAPONOF(deathtype).spawnflags & WEP_FLAG_CANCLIMB) || take > 20 || attacker != this)
                                        if(sound_allowed(MSG_BROADCAST, attacker))
-                                       if(this.health < 25 || !(DEATH_WEAPONOF(deathtype).spawnflags & WEP_FLAG_CANCLIMB) || take > 20 || attacker != this)
-                                       if(this.health > 1)
                                        // exclude pain sounds for laserjumps as long as you aren't REALLY low on health and would die of the next two
                                        {
                                                if(deathtype == DEATH_FALL.m_id)
                                                        PlayerSound(this, playersound_fall, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 75)
+                                               else if(myhp > 75)
                                                        PlayerSound(this, playersound_pain100, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 50)
+                                               else if(myhp > 50)
                                                        PlayerSound(this, playersound_pain75, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
-                                               else if(this.health > 25)
+                                               else if(myhp > 25)
                                                        PlayerSound(this, playersound_pain50, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
                                                else
                                                        PlayerSound(this, playersound_pain25, CH_PAIN, VOL_BASE, VOICETYPE_PLAYERSOUND);
@@ -457,13 +455,23 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                        // throw off bot aim temporarily
                        float shake;
-                       if(IS_BOT_CLIENT(this) && this.health >= 1)
+                       if(IS_BOT_CLIENT(this) && GetResourceAmount(this, RESOURCE_HEALTH) >= 1)
                        {
                                shake = damage * 5 / (bound(0,skill,100) + 1);
                                this.v_angle_x = this.v_angle.x + (random() * 2 - 1) * shake;
                                this.v_angle_y = this.v_angle.y + (random() * 2 - 1) * shake;
                                this.v_angle_x = bound(-90, this.v_angle.x, 90);
                        }
+
+                       if (this != attacker) {
+                               float realdmg = damage - excess;
+                               if (IS_PLAYER(attacker)) {
+                                       GameRules_scoring_add(attacker, DMG, realdmg);
+                               }
+                               if (IS_PLAYER(this)) {
+                                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
+                               }
+                       }
                }
                else
                        this.max_armorvalue += (save + take);
@@ -472,22 +480,11 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        this.dmg_take = this.dmg_take + take;//max(take - 10, 0);
        this.dmg_inflictor = inflictor;
 
-       if (this != attacker) {
-               float realdmg = damage - excess;
-               if (IS_PLAYER(attacker)) {
-                       GameRules_scoring_add(attacker, DMG, realdmg);
-               }
-               if (IS_PLAYER(this)) {
-                       GameRules_scoring_add(this, DMGTAKEN, realdmg);
-               }
-       }
-
        bool abot = (IS_BOT_CLIENT(attacker));
        bool vbot = (IS_BOT_CLIENT(this));
 
        bool valid_damage_for_weaponstats = false;
        Weapon awep = WEP_Null;
-       .entity weaponentity = weaponentities[0]; // TODO: unhardcode
 
        if(vbot || IS_REAL_CLIENT(this))
        if(abot || IS_REAL_CLIENT(attacker))
@@ -501,8 +498,8 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                valid_damage_for_weaponstats = true;
        }
 
-       dh = dh - max(this.health, 0);
-       da = da - max(this.armorvalue, 0);
+       dh = dh - max(GetResourceAmount(this, RESOURCE_HEALTH), 0);
+       da = da - max(GetResourceAmount(this, RESOURCE_ARMOR), 0);
        if(valid_damage_for_weaponstats)
        {
                WeaponStats_LogDamage(awep.m_id, abot, this.(weaponentity).m_weapon.m_id, vbot, dh + da);
@@ -510,7 +507,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
        MUTATOR_CALLHOOK(PlayerDamaged, attacker, this, dh, da, hitloc, deathtype, damage);
 
-       if (this.health < 1)
+       if (GetResourceAmount(this, RESOURCE_HEALTH) < 1)
        {
                float defer_ClientKill_Now_TeamChange;
                defer_ClientKill_Now_TeamChange = false;
@@ -551,7 +548,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                // print an obituary message
                if(this.classname != "body")
-                       Obituary (attacker, inflictor, this, deathtype);
+                       Obituary (attacker, inflictor, this, deathtype, weaponentity);
 
         // increment frag counter for used weapon type
         Weapon w = DEATH_WEAPONOF(deathtype);
@@ -567,9 +564,9 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                        .entity went = weaponentities[slot];
-                       if(!this.(weaponentity))
+                       if(!this.(went))
                                continue; // TODO: clones have no weapon, but we don't want to have to check this all the time
-                       Weapon wep = this.(weaponentity).m_weapon;
+                       Weapon wep = this.(went).m_weapon;
                        wep.wr_playerdeath(wep, this, went);
                }
 
@@ -584,7 +581,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
 
                // player could have been miraculously resuscitated ;)
                // e.g. players in freezetag get frozen, they don't really die
-               if(this.health >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
+               if(GetResourceAmount(this, RESOURCE_HEALTH) >= 1 || !(IS_PLAYER(this) || this.classname == "body"))
                        return;
 
                if (!this.respawn_time) // can be set in the mutator hook PlayerDies
@@ -593,7 +590,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                // when we get here, player actually dies
 
                Unfreeze(this); // remove any icy remains
-               this.health = 0; // Unfreeze resets health, so we need to set it back
+               SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // Unfreeze resets health, so we need to set it back
 
                // clear waypoints
                WaypointSprite_PlayerDead(this);
@@ -630,15 +627,12 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                        animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD1, true);
                else
                        animdecide_setstate(this, this.anim_state | ANIMSTATE_DEAD2, true);
-               if (this.maxs.z > 5)
-               {
-                       this.maxs_z = 5;
-                       setsize(this, this.mins, this.maxs);
-               }
+
                // set damage function to corpse damage
                this.event_damage = PlayerCorpseDamage;
+               this.event_heal = func_null;
                // call the corpse damage function just in case it wants to gib
-               this.event_damage(this, inflictor, attacker, excess, deathtype, hitloc, force);
+               this.event_damage(this, inflictor, attacker, excess, deathtype, weaponentity, hitloc, force);
 
                // set up to fade out later
                SUB_SetFade (this, time + 6 + random (), 1);
@@ -653,7 +647,7 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
                if(autocvar_sv_gentle > 0 || autocvar_ekg || this.classname == "body") {
                        // remove corpse
                        // clones don't run any animation code any more, so we must gib them when they die :(
-                       PlayerCorpseDamage(this, inflictor, attacker, autocvar_sv_gibhealth+1.0, deathtype, hitloc, force);
+                       this.event_damage(this, inflictor, attacker, autocvar_sv_gibhealth + 1, deathtype, weaponentity, hitloc, force);
                }
 
                // reset fields the weapons may use just in case
@@ -672,6 +666,15 @@ void PlayerDamage(entity this, entity inflictor, entity attacker, float damage,
        }
 }
 
+bool PlayerHeal(entity targ, entity inflictor, float amount, float limit)
+{
+       if(GetResourceAmount(targ, RESOURCE_HEALTH) <= 0 || GetResourceAmount(targ, RESOURCE_HEALTH) >= limit)
+               return false;
+
+       GiveResourceWithLimit(targ, RESOURCE_HEALTH, amount, limit);
+       return true;
+}
+
 bool MoveToTeam(entity client, int team_colour, int type)
 {
        int lockteams_backup = lockteams;  // backup any team lock
@@ -681,66 +684,12 @@ bool MoveToTeam(entity client, int team_colour, int type)
        {
                return false;
        }
-       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, client.origin, '0 0 0');  // kill the player
+       Damage(client, client, client, 100000, DEATH_AUTOTEAMCHANGE.m_id, DMG_NOWEP, client.origin, '0 0 0');  // kill the player
        lockteams = lockteams_backup;  // restore the team lock
        LogTeamchange(client.playerid, client.team, type);
        return true;
 }
 
-/** 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:
@@ -977,7 +926,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 dfa485e5f11fddad33799689e9d354fae640e572..8c9bac9b62aaa8e94ea4a594e33f6b680f67d74c 100644 (file)
@@ -9,50 +9,11 @@
 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);
 
-void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void PlayerCorpseDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
 
 // g_<gametype>_str:
 // If 0, default is used.
@@ -76,6 +37,8 @@ void ClientKill_Now_TeamChange(entity this);
 /// \return True on success, false otherwise.
 bool MoveToTeam(entity client, float team_colour, float type);
 
-void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force);
+void PlayerDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
+
+bool PlayerHeal(entity targ, entity inflictor, float amount, float limit);
 
 int Say(entity source, float teamsay, entity privatesay, string msgin, float floodcontrol);
diff --git a/qcsrc/server/playerdemo.qc b/qcsrc/server/playerdemo.qc
deleted file mode 100644 (file)
index 411d826..0000000
+++ /dev/null
@@ -1,170 +0,0 @@
-#include "playerdemo.qh"
-#if defined(CSQC)
-#elif defined(MENUQC)
-#elif defined(SVQC)
-    #include "defs.qh"
-    #include "playerdemo.qh"
-       #include <common/state.qh>
-#endif
-
-.float playerdemo_fh;
-.float playerdemo_mode;
-.float playerdemo_starttime;
-.float playerdemo_time;
-const float PLAYERDEMO_MODE_OFF = 0;
-const float PLAYERDEMO_MODE_READING = 1;
-const float PLAYERDEMO_MODE_WRITING = 2;
-void playerdemo_init(entity this)
-{
-       this.playerdemo_mode = PLAYERDEMO_MODE_OFF;
-}
-void playerdemo_shutdown(entity this)
-{
-       if(this.playerdemo_mode != PLAYERDEMO_MODE_OFF)
-       {
-               LOG_INFO("playerdemo: ", this.netname, " closed");
-               fclose(this.playerdemo_fh);
-       }
-       this.playerdemo_mode = 0;
-}
-void playerdemo_open_read(entity this, string f)
-{
-       playerdemo_shutdown(this);
-       this.playerdemo_mode = PLAYERDEMO_MODE_READING;
-       this.playerdemo_fh = fopen(f, FILE_READ);
-       this.playerdemo_starttime = time - 1;
-       this.playerdemo_time = stof(fgets(this.playerdemo_fh));
-       this.playerdemo_time += this.playerdemo_starttime;
-       set_movetype(this, MOVETYPE_NONE);
-       LOG_INFO("playerdemo: ", this.netname, " reading from ", f);
-}
-void playerdemo_open_write(entity this, string f)
-{
-       playerdemo_shutdown(this);
-       this.playerdemo_mode = PLAYERDEMO_MODE_WRITING;
-       this.playerdemo_fh = fopen(f, FILE_WRITE);
-       this.playerdemo_starttime = time - 1;
-       LOG_INFO("playerdemo: ", this.netname, " writing to ", f);
-       LOG_INFO("WARNING: playerdemo file format is incomplete and not stable yet. DO NOT RELY ON IT!");
-}
-#define PLAYERDEMO_FIELD(ent,func,t,f) func##t(ent,f,#f);
-#define PLAYERDEMO_FIELDS(ent,func) \
-       PLAYERDEMO_FIELD(ent,func,originvector,origin) \
-       PLAYERDEMO_FIELD(ent,func,vector,angles) \
-       PLAYERDEMO_FIELD(ent,func,sizevector,mins) \
-       PLAYERDEMO_FIELD(ent,func,sizevector,maxs) \
-       PLAYERDEMO_FIELD(ent,func,vector,v_angle) \
-       PLAYERDEMO_FIELD(ent,func,modelstring,model) \
-       PLAYERDEMO_FIELD(ent,func,string,playermodel) \
-       PLAYERDEMO_FIELD(ent,func,float,skin) \
-       PLAYERDEMO_FIELD(ent,func,string,playerskin) \
-       PLAYERDEMO_FIELD(ent,func,float,frame) \
-       PLAYERDEMO_FIELD(ent,func,float,effects) \
-       /* PLAYERDEMO_FIELD(ent,func,float,switchweapon) */ \
-       PLAYERDEMO_FIELD(CS(ent),func,float,button0) /* TODO: PHYS_INPUT_BUTTON_ATCK */ \
-       PLAYERDEMO_FIELD(CS(ent),func,float,button3) /* TODO: PHYS_INPUT_BUTTON_ATCK2 */ \
-       PLAYERDEMO_FIELD(CS(ent),func,float,button5) /* TODO: PHYS_INPUT_BUTTON_CROUCH */ \
-       PLAYERDEMO_FIELD(CS(ent),func,float,button6) /* TODO: PHYS_INPUT_BUTTON_HOOK */ \
-       PLAYERDEMO_FIELD(CS(ent),func,float,buttonuse) /* TODO: PHYS_INPUT_BUTTON_USE */ \
-       PLAYERDEMO_FIELD(ent,func,float,flags) \
-       // end of list
-
-void playerdemo_write_originvector(entity this, .vector f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(vtos(this.(f)), "\n"));
-}
-void playerdemo_write_sizevector(entity this, .vector f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(vtos(this.(f)), "\n"));
-}
-void playerdemo_write_vector(entity this, .vector f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(vtos(this.(f)), "\n"));
-}
-void playerdemo_write_string(entity this, .string f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(this.(f), "\n"));
-}
-void playerdemo_write_modelstring(entity this, .string f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(this.(f), "\n"));
-}
-void playerdemo_write_float(entity this, .float f, string name)
-{
-       fputs(this.playerdemo_fh, strcat(ftos(this.(f)), "\n"));
-}
-void playerdemo_write(entity this)
-{
-       if(this.playerdemo_mode != PLAYERDEMO_MODE_WRITING)
-               return;
-       fputs(this.playerdemo_fh, strcat(ftos(time - this.playerdemo_starttime), "\n"));
-       PLAYERDEMO_FIELDS(this, playerdemo_write_)
-}
-void playerdemo_read_originvector(entity this, .vector f, string name)
-{
-       setorigin(this, stov(fgets(this.playerdemo_fh)));
-}
-void playerdemo_read_sizevector(entity this, .vector f, string name)
-{
-       this.(f) = stov(fgets(this.playerdemo_fh));
-       setsize(this, this.mins, this.maxs);
-}
-void playerdemo_read_vector(entity this, .vector f, string name)
-{
-       this.(f) = stov(fgets(this.playerdemo_fh));
-}
-void playerdemo_read_string(entity this, .string f, string name)
-{
-       string s = fgets(this.playerdemo_fh);
-       if (s != this.(f))
-       {
-               /*
-               if(this.f)
-                       strunzone(this.f);
-               */
-               this.(f) = strzone(s);
-       }
-}
-void playerdemo_read_modelstring(entity this, .string f, string name)
-{
-       string s = fgets(this.playerdemo_fh);
-       if (s != this.(f))
-               _setmodel(this, s);
-}
-void playerdemo_read_float(entity this, .float f, string name)
-{
-       this.(f) = stof(fgets(this.playerdemo_fh));
-}
-float playerdemo_read(entity this)
-{
-       if(this.playerdemo_mode != PLAYERDEMO_MODE_READING)
-               return 0;
-       if(this.playerdemo_time < 0)
-               return 1;
-       float t;
-       t = time;
-       while(time >= this.playerdemo_time)
-       {
-               PLAYERDEMO_FIELDS(this, playerdemo_read_)
-               {
-                       time = this.playerdemo_time;
-                       PlayerPreThink(this);
-                       // not running physics though... this is just so we can run weapon stuff
-                       PlayerPostThink(this);
-               }
-               this.playerdemo_time = stof(fgets(this.playerdemo_fh));
-               if(this.playerdemo_time == 0)
-               {
-                       this.playerdemo_time = -1;
-                       return 1;
-               }
-               this.playerdemo_time += this.playerdemo_starttime;
-       }
-       this.velocity = '0 0 0';
-       CS(this).movement = '0 0 0';
-       this.dmg_take = 0; // so screen doesn't stay blurry
-       this.dmg_save = 0;
-       this.dmg_inflictor = NULL;
-       time = t;
-       return 1;
-}
diff --git a/qcsrc/server/playerdemo.qh b/qcsrc/server/playerdemo.qh
deleted file mode 100644 (file)
index c2da2bc..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-#pragma once
-
-void playerdemo_init(entity this);
-void playerdemo_shutdown(entity this);
-void playerdemo_write(entity this);
-float playerdemo_read(entity this);
-
-void playerdemo_open_read(entity this, string f);
-void playerdemo_open_write(entity this, string f);
index 20039cfcc8205c83f784012c01a286cdfc531e50..162026a169e98843d259e2717228984fb06905b8 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"
@@ -199,8 +199,8 @@ float Portal_TeleportPlayer(entity teleporter, entity player)
        // reset fade counter
        teleporter.portal_wants_to_vanish = 0;
        teleporter.fade_time = time + autocvar_g_balance_portal_lifetime;
-       teleporter.health = autocvar_g_balance_portal_health;
-       teleporter.enemy.health = autocvar_g_balance_portal_health;
+       SetResourceAmountExplicit(teleporter, RESOURCE_HEALTH, autocvar_g_balance_portal_health);
+       SetResourceAmountExplicit(teleporter.enemy, RESOURCE_HEALTH, autocvar_g_balance_portal_health);
 
        return 1;
 }
@@ -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;
@@ -429,15 +428,15 @@ void Portal_Remove(entity portal, float killed)
        }
 }
 
-void Portal_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, vector hitloc, vector force)
+void Portal_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
 {
        if(deathtype == DEATH_TELEFRAG.m_id)
                return;
        if(attacker != this.aiment)
                if(IS_INDEPENDENT_PLAYER(attacker) || IS_INDEPENDENT_PLAYER(this.aiment))
                        return;
-       this.health -= damage;
-       if(this.health < 0)
+       TakeResource(this, RESOURCE_HEALTH, damage);
+       if(GetResourceAmount(this, RESOURCE_HEALTH) < 0)
                Portal_Remove(this, 1);
 }
 
@@ -640,7 +639,7 @@ entity Portal_Spawn(entity own, vector org, vector ang)
        portal.takedamage = DAMAGE_AIM;
        portal.event_damage = Portal_Damage;
        portal.fade_time = time + autocvar_g_balance_portal_lifetime;
-       portal.health = autocvar_g_balance_portal_health;
+       SetResourceAmountExplicit(portal, RESOURCE_HEALTH, autocvar_g_balance_portal_health);
        setmodel(portal, MDL_PORTAL);
        portal.savemodelindex = portal.modelindex;
        setcefc(portal, Portal_Customize);
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 6fc828dc9459ec85cd59d32ee04ac54656196da4..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); });
                                }
@@ -705,7 +705,7 @@ void checkpoint_passed(entity this, entity player)
        else
        {
                if(this.spawnflags & 4)
-                       Damage (player, this, this, 10000, DEATH_HURTTRIGGER.m_id, player.origin, '0 0 0');
+                       Damage (player, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, player.origin, '0 0 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..74a0c55788a71a2f19de6accaeaacba47f1c9c3b 100644 (file)
@@ -10,6 +10,9 @@
 
 float GetResourceLimit(entity e, int resource_type)
 {
+       if(!IS_PLAYER(e))
+               return RESOURCE_LIMIT_NONE; // no limits on non-players
+
        float limit;
        switch (resource_type)
        {
@@ -74,6 +77,17 @@ float GetResourceAmount(entity e, int resource_type)
        return e.(resource_field);
 }
 
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount)
+{
+       .float resource_field = GetResourceField(resource_type);
+       if (e.(resource_field) != amount)
+       {
+               e.(resource_field) = amount;
+               return true;
+       }
+       return false;
+}
+
 void SetResourceAmount(entity e, int resource_type, float amount)
 {
        bool forbid = MUTATOR_CALLHOOK(SetResourceAmount, e, resource_type, amount);
@@ -83,22 +97,28 @@ 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)
+       float max_amount = GetResourceLimit(e, resource_type); // TODO: should allow overriding these limits if cheats are enabled!
+       float amount_wasted = 0;
+       if (amount > max_amount && max_amount != RESOURCE_LIMIT_NONE)
        {
-               return;
+               amount_wasted = amount - max_amount;
+               amount = max_amount;
        }
-       float max_amount = GetResourceLimit(e, resource_type);
-       if (amount > max_amount)
+       bool changed = SetResourceAmountExplicit(e, resource_type, amount);
+       if (changed)
        {
-               amount = max_amount;
+               MUTATOR_CALLHOOK(ResourceAmountChanged, e, resource_type, amount);
        }
-       e.(resource_field) = amount;
+       if (amount_wasted == 0)
+       {
+               return;
+       }
+       MUTATOR_CALLHOOK(ResourceWasted, e, resource_type, amount_wasted);
 }
 
 void GiveResource(entity receiver, int resource_type, float amount)
 {
-       if (amount == 0)
+       if (amount <= 0)
        {
                return;
        }
@@ -144,18 +164,106 @@ void GiveResource(entity receiver, int resource_type, float amount)
 void GiveResourceWithLimit(entity receiver, int resource_type, float amount,
        float limit)
 {
-       if (amount == 0)
+       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;
        }
        float current_amount = GetResourceAmount(receiver, resource_type);
-       if (current_amount + amount > limit)
+       if (current_amount + amount > limit && limit != RESOURCE_LIMIT_NONE)
        {
                amount = limit - current_amount;
        }
        GiveResource(receiver, resource_type, amount);
 }
 
+void TakeResource(entity receiver, int resource_type, float amount)
+{
+       if (amount <= 0)
+       {
+               return;
+       }
+       bool forbid = MUTATOR_CALLHOOK(TakeResource, receiver, resource_type,
+               amount);
+       if (forbid)
+       {
+               return;
+       }
+       resource_type = M_ARGV(1, int);
+       amount = M_ARGV(2, float);
+       if (amount <= 0)
+       {
+               return;
+       }
+       SetResourceAmount(receiver, resource_type,
+               GetResourceAmount(receiver, resource_type) - amount);
+}
+
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit)
+{
+       if (amount <= 0)
+       {
+               return;
+       }
+       bool forbid = MUTATOR_CALLHOOK(TakeResourceWithLimit, 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;
+       }
+       float current_amount = GetResourceAmount(receiver, resource_type);
+       if (current_amount - amount < -limit)
+       {
+               amount = -limit + current_amount;
+       }
+       TakeResource(receiver, resource_type, amount);
+}
+
+void GiveOrTakeResource(entity receiver, int resource_type, float amount)
+{
+       if(amount < 0)
+       {
+               TakeResource(receiver, resource_type, amount * -1);
+       }
+       else
+       {
+               GiveResource(receiver, resource_type, amount);
+       }
+}
+
+void GiveOrTakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit)
+{
+       if(amount < 0)
+       {
+               TakeResourceWithLimit(receiver, resource_type, amount * -1, limit);
+       }
+       else
+       {
+               GiveResourceWithLimit(receiver, resource_type, amount, limit);
+       }
+}
+
 int GetResourceType(.float resource_field)
 {
        switch (resource_field)
index 6ff3cea67917973eab045526b76d0c6d97b05890..15433b264fde16ba7b34d98510743ead0accf3b8 100644 (file)
@@ -7,9 +7,6 @@
 
 #include <common/resources.qh>
 
-/// \brief Unconditional maximum amount of resources the entity can have.
-const int RESOURCE_AMOUNT_HARD_LIMIT = 999;
-
 // ============================ Public API ====================================
 
 /// \brief Returns the maximum amount of the given resource.
@@ -24,6 +21,13 @@ float GetResourceLimit(entity e, int resource_type);
 /// \return Current amount of resource the given entity has.
 float GetResourceAmount(entity e, int resource_type);
 
+/// \brief Sets the resource amount of an entity without calling any hooks.
+/// \param[in,out] e Entity to adjust.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to set.
+/// \return Boolean for whether the ammo amount was changed
+bool SetResourceAmountExplicit(entity e, int resource_type, float amount);
+
 /// \brief Sets the current amount of resource the given entity will have.
 /// \param[in,out] e Entity to adjust.
 /// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
@@ -47,6 +51,38 @@ void GiveResource(entity receiver, int resource_type, float amount);
 void GiveResourceWithLimit(entity receiver, int resource_type, float amount,
        float limit);
 
+/// \brief Takes an entity some resource.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \return No return.
+void TakeResource(entity receiver, int resource_type, float amount);
+
+/// \brief Takes an entity some resource but not less than a limit.
+/// \param[in,out] receiver Entity to take resource from.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to take.
+/// \param[in] limit Limit of resources to take.
+/// \return No return.
+void TakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit);
+
+/// \brief Gives to or takes from an entity resource.
+/// \param[in,out] receiver Entity to give or take resource.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to give or take.
+/// \return No return.
+void GiveOrTakeResource(entity receiver, int resource_type, float amount);
+
+/// \brief Gives to or takes from an entity resource but not more/less than a limit.
+/// \param[in,out] receiver Entity to give or take resource.
+/// \param[in] resource_type Type of the resource (a RESOURCE_* constant).
+/// \param[in] amount Amount of resource to give or take.
+/// \param[in] limit Limit of resources to give or take.
+/// \return No return.
+void GiveOrTakeResourceWithLimit(entity receiver, int resource_type, float amount,
+       float limit);
+
 // ===================== Legacy and/or internal API ===========================
 
 /// \brief Converts an entity field to resource type.
index c9948660efe1165c7ed8654dac1ba770e6763277..af2f4b574f43a57f0c098d19c47b5fe2754428ac 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;
@@ -373,7 +402,7 @@ float PlayerScore_Compare(entity t1, entity t2, float strict)
        });
 
        if (result.x == 0 && strict)
-               result.x = etof(t1.owner) - etof(t2.owner);
+               result.x = t1.owner.playerid - t2.owner.playerid;
 
        return result.x;
 }
@@ -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 cd393b64196a1cbab9f0128623f3ef8be7adc612..e0e33e4803c87445641359a8c76824cc821a19a8 100644 (file)
@@ -1,24 +1,25 @@
 #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/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)
 {
        WriteHeader(MSG_ENTITY, ENT_CLIENT_SPAWNPOINT);
 
        WriteByte(MSG_ENTITY, this.team);
-       WriteCoord(MSG_ENTITY, this.origin.x);
-       WriteCoord(MSG_ENTITY, this.origin.y);
-       WriteCoord(MSG_ENTITY, this.origin.z);
+       WriteVector(MSG_ENTITY, this.origin);
 
        return true;
 }
@@ -32,9 +33,7 @@ bool SpawnEvent_Send(entity this, entity to, int sf)
        if(autocvar_g_spawn_alloweffects)
        {
                WriteByte(MSG_ENTITY, etof(this.owner));
-               WriteCoord(MSG_ENTITY, this.owner.origin.x);
-               WriteCoord(MSG_ENTITY, this.owner.origin.y);
-               WriteCoord(MSG_ENTITY, this.owner.origin.z);
+               WriteVector(MSG_ENTITY, this.owner.origin);
                send = true;
        }
        else if((to == this.owner) || (IS_SPEC(to) && (to.enemy == this.owner)) )
@@ -216,11 +215,6 @@ spawnfunc(info_player_team4)
 //   _y: weight
 vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
 {
-       float shortest, thisdist;
-       float prio;
-
-       prio = 0;
-
        // filter out spots for the wrong team
        if(teamcheck >= 0)
                if(spot.team != teamcheck)
@@ -241,9 +235,10 @@ vector Spawn_Score(entity this, entity spot, float mindist, float teamcheck)
                        return '-1 0 0';
        }
 
-       shortest = vlen(world.maxs - world.mins);
+       float prio = 0;
+       float shortest = vlen(world.maxs - world.mins);
        FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               thisdist = vlen(it.origin - spot.origin);
+               float thisdist = vlen(it.origin - spot.origin);
                if (thisdist < shortest)
                        shortest = thisdist;
        });
@@ -332,14 +327,24 @@ SelectSpawnPoint
 Finds a point to respawn
 =============
 */
+bool testspawn_checked;
+entity testspawn_point;
 entity SelectSpawnPoint(entity this, bool anypoint)
 {
        float teamcheck;
-       entity spot, firstspot;
+       entity spot = NULL;
+
+       if(!testspawn_checked)
+       {
+               testspawn_point = find(NULL, classname, "testplayerstart");
+               testspawn_checked = true;
+       }
+
+       if(testspawn_point)
+               return testspawn_point;
 
-       spot = find(NULL, classname, "testplayerstart");
-       if (spot)
-               return spot;
+       if(this.spawnpoint_targ)
+               return this.spawnpoint_targ;
 
        if(anypoint || autocvar_g_spawn_useallspawns)
                teamcheck = -1;
@@ -367,7 +372,16 @@ entity SelectSpawnPoint(entity this, bool anypoint)
 
 
        // get the entire list of spots
-       firstspot = findchain(classname, "info_player_deathmatch");
+       //entity firstspot = findchain(classname, "info_player_deathmatch");
+       entity firstspot = IL_FIRST(g_spawnpoints);
+       entity prev = NULL;
+       IL_EACH(g_spawnpoints, true,
+       {
+               if(prev)
+                       prev.chain = it;
+               it.chain = NULL;
+               prev = it;
+       });
        // filter out the bad ones
        // (note this returns the original list if none survived)
        if(anypoint)
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 d2cc9b960b650dbcdab5fdeb39e616c7e44a3cb0..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"
@@ -37,9 +40,9 @@ void CreatureFrame_hotliquids(entity this)
                if (this.flags & FL_PROJECTILE)
                {
                        if (this.watertype == CONTENT_LAVA)
-                               Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        else if (this.watertype == CONTENT_SLIME)
-                               Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
                }
                else
                {
@@ -50,7 +53,7 @@ void CreatureFrame_hotliquids(entity this)
                                        this.watersound_finished = time + 0.5;
                                        sound (this, CH_PLAYER_SINGLE, SND_LAVA, VOL_BASE, ATTEN_NORM);
                                }
-                               Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
                                if(autocvar_g_balance_contents_playerdamage_lava_burn)
                                        Fire_AddDamage(this, NULL, autocvar_g_balance_contents_playerdamage_lava_burn * this.waterlevel, autocvar_g_balance_contents_playerdamage_lava_burn_time * this.waterlevel, DEATH_LAVA.m_id);
                        }
@@ -61,7 +64,7 @@ void CreatureFrame_hotliquids(entity this)
                                        this.watersound_finished = time + 0.5;
                                        sound (this, CH_PLAYER_SINGLE, SND_SLIME, VOL_BASE, ATTEN_NORM);
                                }
-                               Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
                        }
                }
        }
@@ -116,11 +119,11 @@ void CreatureFrame_FallDamage(entity this)
                        else
                                dm = min((dm - autocvar_g_balance_falldamage_minspeed) * autocvar_g_balance_falldamage_factor, autocvar_g_balance_falldamage_maxdamage);
                        if (dm > 0)
-                               Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, this.origin, '0 0 0');
+                               Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
                }
 
                if(autocvar_g_maxspeed > 0 && velocity_len > autocvar_g_maxspeed)
-                       Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, this.origin, '0 0 0');
+                       Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, DMG_NOWEP, this.origin, '0 0 0');
        }
 }
 
@@ -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 33ad8f8ed634f6123bf3a5c247eb83fad0dccf3d..b0d9e0992eb921c204451f24b48877010c082369 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");
        }
@@ -116,7 +116,7 @@ string getwelcomemessage(entity this)
        if(g_weapon_stay && !g_cts)
                modifications = strcat(modifications, ", Weapons stay");
        if(g_jetpack)
-               modifications = strcat(modifications, ", Jet pack");
+               modifications = strcat(modifications, ", Jetpack");
        if(autocvar_g_powerups == 0)
                modifications = strcat(modifications, ", No powerups");
        if(autocvar_g_powerups > 0)
@@ -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 != "") {
@@ -190,7 +186,7 @@ void KillPlayerForTeamChange(entity player)
        {
                return;
        }
-       Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, player.origin,
+       Damage(player, player, player, 100000, DEATH_TEAMCHANGE.m_id, DMG_NOWEP, player.origin,
                '0 0 0');
 }
 
index 50dc5a35bca7cd130b7732fe141819539bc64e01..e52d4fcf1111c67ddd6c17f53b95feed83d605b7 100644 (file)
@@ -2,7 +2,7 @@
 
 void test_weapons_hurt(entity this)
 {
-    EXPECT_NE(100, this.health);
+    EXPECT_NE(100, GetResourceAmount(this, RESOURCE_HEALTH));
     delete(this.enemy);
     delete(this);
 }
index 0d6ecf066f70637deeb0f94ef64e47c079204427..8cd7ab66c346f5bc2041c747f116c8d15b412664 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>
@@ -67,14 +67,15 @@ void accuracy_add(entity this, int w, int fired, int hit)
        entity a = CS(this).accuracy;
        if (!a) return;
        if (!hit && !fired) return;
+       if (w == WEP_Null.m_id) return;
        w -= WEP_FIRST;
        int b = accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]);
        if (hit)    a.accuracy_hit  [w] += hit;
        if (fired)  a.accuracy_fired[w] += fired;
 
-    if (hit && a.hit_time != time) { // only run this once per frame
+    if (hit && STAT(HIT_TIME, a) != time) { // only run this once per frame
         a.accuracy_cnt_hit[w] += 1;
-        a.hit_time = time;
+        STAT(HIT_TIME, a) = time;
     }
 
     if (fired && a.fired_time != time) { // only run this once per frame
@@ -93,8 +94,12 @@ bool accuracy_isgooddamage(entity attacker, entity targ)
        int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
 
        if (warmup_stage) return false;
-       if (IS_DEAD(targ)) return false;
-       if (STAT(FROZEN, targ)) return false;
+       if (game_stopped) return false;
+
+       // damage to dead/frozen players is good only if it happens in the frame they get killed / frozen
+       // so that stats for weapons that shoot multiple projectiles per shot are properly counted
+       if (IS_DEAD(targ) && time > targ.death_time) return false;
+       if (STAT(FROZEN, targ) && time > targ.freeze_time) return false;
        if (SAME_TEAM(attacker, targ)) return false;
 
        if (mutator_check == MUT_ACCADD_INVALID) return true;
index f69faa03a324de3e93d3136610a2835d9bbc781e..06615c4eac8575465aed85fe57cbe5181c423940 100644 (file)
 #include <common/state.qh>
 #include <common/util.qh>
 #include <common/weapons/_all.qh>
+#include <common/wepent.qh>
 #include <common/items/_mod.qh>
 
+bool W_DualWielding(entity player)
+{
+       int held_weapons = 0;
+       for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+       {
+               .entity weaponentity = weaponentities[slot];
+               if(player.(weaponentity) && player.(weaponentity).m_switchweapon != WEP_Null)
+                       ++held_weapons;
+       }
+
+       return held_weapons > 1;
+}
+
 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 363941b3a71210d24917f897f37c92c52f254d5b..1b4b179d2485d32f22fb06665f280f2014b3f22c 100644 (file)
@@ -1,5 +1,6 @@
 #pragma once
 
+bool W_DualWielding(entity player);
 void W_GiveWeapon (entity e, float wep);
 .float prevstrengthsound;
 .float prevstrengthsoundattempt;
index d426e2f610d3000c69c2b16cba9defb350adfb9f..5352b40cde1a8fa1afb3b6058d36a48a3ea0b6cf 100644 (file)
@@ -42,15 +42,11 @@ bool CSQCProjectile_SendEntity(entity this, entity to, int sf)
 
        if(sf & 1)
        {
-               WriteCoord(MSG_ENTITY, this.origin.x);
-               WriteCoord(MSG_ENTITY, this.origin.y);
-               WriteCoord(MSG_ENTITY, this.origin.z);
+               WriteVector(MSG_ENTITY, this.origin);
 
                if(sf & 0x80)
                {
-                       WriteCoord(MSG_ENTITY, this.velocity.x);
-                       WriteCoord(MSG_ENTITY, this.velocity.y);
-                       WriteCoord(MSG_ENTITY, this.velocity.z);
+                       WriteVector(MSG_ENTITY, this.velocity);
                        if(sf & 0x10)
                                WriteCoord(MSG_ENTITY, this.gravity);
                }
index fb13bd1b9e126201de97ef73bf439f4119a6a97e..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>
@@ -54,7 +53,7 @@ vector W_HitPlotNormalizedUntransform(vector org, entity targ, vector screenforw
        return ret;
 }
 
-void W_HitPlotAnalysis(entity player, .entity weaponentity, vector screenforward, vector screenright, vector screenup)
+void W_HitPlotAnalysis(entity player, entity wep, vector screenforward, vector screenright, vector screenup)
 {
        if(CS(player).hitplotfh >= 0)
        {
@@ -72,7 +71,7 @@ void W_HitPlotAnalysis(entity player, .entity weaponentity, vector screenforward
                        antilag_takeback(trace_ent, store, time - lag);
                        vector hitplot = W_HitPlotNormalizedUntransform(org, trace_ent, screenforward, screenright, screenup, trace_endpos);
                        antilag_restore(trace_ent, store);
-                       fputs(CS(player).hitplotfh, strcat(ftos(hitplot.x), " ", ftos(hitplot.y), " ", ftos(hitplot.z), " ", ftos(player.(weaponentity).m_switchweapon.m_id), "\n"));
+                       fputs(CS(player).hitplotfh, strcat(ftos(hitplot.x), " ", ftos(hitplot.y), " ", ftos(hitplot.z), " ", ftos(wep.m_id), "\n"));
                        //print(strcat(ftos(hitplot_x), " ", ftos(hitplot_y), " ", ftos(hitplot_z), "\n"));
                }
        }
index 89f7f50504d580c04f354fd971d61d56fddb7824..e9686783569db5945679959b9a50cc88c1ac9269 100644 (file)
@@ -2,6 +2,6 @@
 
 .float hitplotfh;
 
-void W_HitPlotAnalysis(entity player, .entity weaponentity, vector screenforward, vector screenright, vector screenup);
+void W_HitPlotAnalysis(entity player, entity wep, vector screenforward, vector screenright, vector screenup);
 void W_HitPlotOpen(entity player);
 void W_HitPlotClose(entity player);
index 693d5a240456323adab1c259b51dfb2551275386..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
        {
@@ -304,7 +304,7 @@ void W_NextWeapon(entity this, int list, .entity weaponentity)
        if(list == 0)
                W_CycleWeapon(this, weaponorder_byid, -1, weaponentity);
        else if(list == 1)
-               W_CycleWeapon(this, this.weaponorder_byimpulse, -1, weaponentity);
+               W_CycleWeapon(this, CS(this).weaponorder_byimpulse, -1, weaponentity);
        else if(list == 2)
                W_CycleWeapon(this, CS(this).cvar_cl_weaponpriority, -1, weaponentity);
 }
@@ -315,7 +315,7 @@ void W_PreviousWeapon(entity this, float list, .entity weaponentity)
        if(list == 0)
                W_CycleWeapon(this, weaponorder_byid, +1, weaponentity);
        else if(list == 1)
-               W_CycleWeapon(this, this.weaponorder_byimpulse, +1, weaponentity);
+               W_CycleWeapon(this, CS(this).weaponorder_byimpulse, +1, weaponentity);
        else if(list == 2)
                W_CycleWeapon(this, CS(this).cvar_cl_weaponpriority, +1, weaponentity);
 }
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 4be26497a628c480050d01b8a3bd60f732f34b7d..5d35166aa6167d27e4af3bf0e519b52221f4a222 100644 (file)
@@ -8,7 +8,6 @@
 #include "weaponsystem.qh"
 
 #include "../g_damage.qh"
-#include "../g_subs.qh"
 #include "../antilag.qh"
 
 #include <common/constants.qh>
 // this function calculates w_shotorg and w_shotdir based on the weapon model
 // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
 // make sure you call makevectors first (FIXME?)
-void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range)
+void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range, int deathtype)
 {
        TC(Sound, snd);
        float nudge = 1; // added to traceline target and subtracted from result  TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
        float oldsolid = ent.dphitcontentsmask;
+       Weapon wep = DEATH_WEAPONOF(deathtype);
        if(!IS_CLIENT(ent))
                antilag = false; // no antilag for non-clients!
-       if (IS_PLAYER(ent) && (ent.(weaponentity).m_weapon.spawnflags & WEP_FLAG_PENETRATEWALLS))
+       if (IS_PLAYER(ent) && (wep.spawnflags & WEP_FLAG_PENETRATEWALLS))
                ent.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_CORPSE;
        else
                ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE;
@@ -57,10 +57,10 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
 
        // track max damage
        if (IS_PLAYER(ent) && accuracy_canbegooddamage(ent))
-               accuracy_add(ent, ent.(weaponentity).m_weapon.m_id, maxdamage, 0);
+               accuracy_add(ent, wep.m_id, maxdamage, 0);
 
        if(IS_PLAYER(ent))
-               W_HitPlotAnalysis(ent, weaponentity, v_forward, v_right, v_up);
+               W_HitPlotAnalysis(ent, wep, v_forward, v_right, v_up);
 
        vector md = ent.(weaponentity).movedir;
        vector vecs = ((md.x > 0) ? md : '0 0 0');
@@ -80,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;
@@ -135,14 +138,7 @@ void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vect
                ent.punchangle_x = recoil * -1;
 
        if (snd != SND_Null) {
-               int held_weapons = 0; // HACK: muffle weapon sounds slightly while dual wielding!
-               for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
-               {
-                       .entity wep_ent = weaponentities[slot];
-                       if(ent.(wep_ent) && ent.(wep_ent).m_switchweapon != WEP_Null)
-                               ++held_weapons;
-               }
-               sound (ent, chan, snd, ((held_weapons > 1) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
+               sound (ent, chan, snd, (W_DualWielding(ent) ? VOL_BASE * 0.7 : VOL_BASE), ATTN_NORM);
                W_PlayStrengthSound(ent);
        }
 
@@ -310,7 +306,7 @@ void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector
 
                // apply the damage
                if (it.takedamage)
-                       Damage (it, this, this, bdamage * foff, deathtype, hitloc, it.railgunforce * ffs);
+                       Damage (it, this, this, bdamage * foff, deathtype, weaponentity, hitloc, it.railgunforce * ffs);
 
                // create a small explosion to throw gibs around (if applicable)
                //setorigin(explosion, hitloc);
@@ -417,10 +413,10 @@ void fireBullet(entity this, .entity weaponentity, vector start, vector dir, flo
                        yoda = 0;
                        MUTATOR_CALLHOOK(FireBullet_Hit, this, hit, start, end, damage, this.(weaponentity));
                        damage = M_ARGV(4, float);
-                       float g = accuracy_isgooddamage(this, hit);
-                       Damage(hit, this, this, damage * solid_penetration_left, dtype, start, force * dir * solid_penetration_left);
+                       bool gooddamage = accuracy_isgooddamage(this, hit);
+                       Damage(hit, this, this, damage * solid_penetration_left, dtype, weaponentity, start, force * dir * solid_penetration_left);
                        // calculate hits for ballistic weapons
-                       if(g)
+                       if(gooddamage)
                        {
                                // do not exceed 100%
                                float added_damage = min(damage - total_damage, damage * solid_penetration_left);
index e6c4a0041239a5123e750859bc84e79eaa982e96..37284ffc3d3a9d59112a55c4a17f0674dc183d6a 100644 (file)
@@ -10,13 +10,13 @@ vector w_shotend;
 // this function calculates w_shotorg and w_shotdir based on the weapon model
 // offset, trueaim and antilag, and won't put w_shotorg inside a wall.
 // make sure you call makevectors first (FIXME?)
-void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range);
+void W_SetupShot_Dir_ProjectileSize_Range(entity ent, .entity weaponentity, vector s_forward, vector mi, vector ma, float antilag, float recoil, Sound snd, float chan, float maxdamage, float range, int deathtype);
 
-#define W_SetupShot_Dir_ProjectileSize(ent,wepent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, max_shot_distance)
-#define W_SetupShot_ProjectileSize(ent,wepent,mi,ma,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot_Dir(ent,wepent,s_forward,antilag,recoil,snd,chan,maxdamage) W_SetupShot_Dir_ProjectileSize(ent, wepent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot(ent,wepent,antilag,recoil,snd,chan,maxdamage) W_SetupShot_ProjectileSize(ent, wepent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage)
-#define W_SetupShot_Range(ent,wepent,antilag,recoil,snd,chan,maxdamage,range) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range)
+#define W_SetupShot_Dir_ProjectileSize(ent,wepent,s_forward,mi,ma,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, s_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, max_shot_distance, deathtype)
+#define W_SetupShot_ProjectileSize(ent,wepent,mi,ma,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize(ent, wepent, v_forward, mi, ma, antilag, recoil, snd, chan, maxdamage, deathtype)
+#define W_SetupShot_Dir(ent,wepent,s_forward,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_Dir_ProjectileSize(ent, wepent, s_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, deathtype)
+#define W_SetupShot(ent,wepent,antilag,recoil,snd,chan,maxdamage,deathtype) W_SetupShot_ProjectileSize(ent, wepent, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, deathtype)
+#define W_SetupShot_Range(ent,wepent,antilag,recoil,snd,chan,maxdamage,range,deathtype) W_SetupShot_Dir_ProjectileSize_Range(ent, wepent, v_forward, '0 0 0', '0 0 0', antilag, recoil, snd, chan, maxdamage, range, deathtype)
 
 vector W_CalculateProjectileVelocity(entity actor, vector pvelocity, vector mvelocity, float forceAbsolute);
 
index 2f6fcb68d7213cbafc508343d377da932944ad0a..bf81f7044187d3ec532ea0f44ab968c328bf211f 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
@@ -418,7 +416,7 @@ void weapon_thinkf(entity actor, .entity weaponentity, WFRAME fr, float t, void(
 
 bool forbidWeaponUse(entity player)
 {
-       if (time < game_starttime && !autocvar_sv_ready_restart_after_countdown) return true;
+       if (time < game_starttime && !sv_ready_restart_after_countdown) return true;
        if (player.player_blocked) return true;
        if (game_stopped) return true;
        if (STAT(FROZEN, player)) return true;
@@ -435,7 +433,7 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
        entity this = actor.(weaponentity);
        if (frametime) this.weapon_frametime = frametime;
 
-       if (!this || actor.health < 1) return;  // Dead player can't use weapons and injure impulse commands
+       if (!this || GetResourceAmount(actor, RESOURCE_HEALTH) < 1) return;  // Dead player can't use weapons and injure impulse commands
 
        int button_atck = PHYS_INPUT_BUTTON_ATCK(actor);
        int button_atck2 = PHYS_INPUT_BUTTON_ATCK2(actor);
@@ -472,6 +470,8 @@ void W_WeaponFrame(Player actor, .entity weaponentity)
 
        if (this.m_switchweapon == WEP_Null)
        {
+               if (this.state != WS_CLEAR)
+                       w_ready(this.m_weapon, actor, weaponentity, button_atck | (button_atck2 << 1));
                this.m_weapon = WEP_Null;
                this.m_switchingweapon = WEP_Null;
                this.state = WS_CLEAR;
@@ -557,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;
@@ -574,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);
                        }
@@ -658,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
@@ -739,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."
diff --git a/ruleset-XDF.cfg b/ruleset-XDF.cfg
new file mode 100644 (file)
index 0000000..20740d9
--- /dev/null
@@ -0,0 +1,28 @@
+// ================
+//  Xonotic Defrag
+// ================
+
+exec xonotic-server.cfg
+exec balance-xdf.cfg
+exec physicsXDF.cfg
+
+// general gameplay
+// 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
+// g_playerclip_collisions 0 // do not check playerclips
+set g_powerups 0  // set to -1 or patch xonotic
+set g_spawnpoints_auto_move_out_of_solid 1
+set g_start_delay 3
+set g_use_ammunition 0 "if set to 0 all weapons have unlimited ammunition"
+set g_weapon_stay 1 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
+set teamplay_mode 2 // friendly fire and self damage
+set sv_vote_nospectators 1
+set timelimit_override 20
+set g_buffs_cooldown_respawn 0.1
+
+// game mode settings
+set g_cts_finish_kill_delay 2
+set g_cts_respawn_delay 0
+set g_cts_selfdamage 0
diff --git a/ruleset-XPM.cfg b/ruleset-XPM.cfg
new file mode 100644 (file)
index 0000000..eb682aa
--- /dev/null
@@ -0,0 +1,27 @@
+// ==================
+//  Xonotic Pro-Mode
+// ==================
+
+exec xonotic-server.cfg
+exec balance-xpm.cfg
+
+// general gameplay
+set g_norecoil 1
+set g_shootfromeye 1 // hit where you point at with the crosshair (promoders don't care about ugliness)
+set g_balance_kill_antispam 0
+set g_forced_respawn 1
+set teamplay_mode 2 // friendly fire and self damage
+set sv_vote_nospectators 1
+set g_chat_nospectators 2
+set g_warmup 1
+set g_balance_teams 0
+set g_spawnshieldtime 0
+set g_spawn_furthest 1
+set sv_autoscreenshot 1
+set sv_ready_restart 1
+set sv_ready_restart_after_countdown 1
+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
diff --git a/ruleset-overkill.cfg b/ruleset-overkill.cfg
new file mode 100644 (file)
index 0000000..cc512e0
--- /dev/null
@@ -0,0 +1,37 @@
+// ==============
+//  Overkill Mod
+// ==============
+
+exec xonotic-server.cfg
+exec balance-overkill.cfg
+exec physicsOverkill.cfg
+exec randomitems-overkill.cfg
+
+// general gameplay
+set g_overkill 1
+
+// hack - eventually, we should be able to choose overkill models in menu like for vanilla
+set sv_defaultcharacter 1
+set sv_defaultplayermodel "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+set sv_defaultplayermodel_red "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
+set sv_defaultplayermodel_blue "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+set sv_defaultplayermodel_yellow "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
+set sv_defaultplayermodel_pink "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+
+set g_respawn_ghosts 0
+
+set g_nades 1
+set g_nades_nade_small 1
+set g_nades_spread 0
+set g_nades_nade_refire 10
+set g_nades_nade_newton_style 2
+
+set g_dodging 1
+set sv_dodging_wall_dodging 1
+
+set g_spawn_near_teammate "!g_assault !g_freezetag"
+set g_spawn_near_teammate_ignore_spawnpoint 1
+set g_spawnshieldtime 0.5
+set g_respawn_delay_forced 2
+
+set g_lms_start_armor 100
diff --git a/ruleset-xonotic.cfg b/ruleset-xonotic.cfg
new file mode 100644 (file)
index 0000000..7915766
--- /dev/null
@@ -0,0 +1 @@
+exec xonotic-server.cfg
diff --git a/scripts/explosiveammo.shader b/scripts/explosiveammo.shader
new file mode 100644 (file)
index 0000000..d6c3a90
--- /dev/null
@@ -0,0 +1,20 @@
+explosive_ammo
+{
+       dpreflectcube cubemaps/default/sky
+       {
+               map textures/items/explosiveammo.tga
+               rgbgen lightingDiffuse
+       }
+}
+explosive_ammo_icons
+{
+       {
+       
+       animMap 2 textures/items/explosiveammo_icon_01.tga textures/items/explosiveammo_icon_01.tga textures/items/explosiveammo_icon_01.tga textures/items/explosiveammo_icon_blank.tga textures/items/explosiveammo_icon_02.tga textures/items/explosiveammo_icon_02.tga textures/items/explosiveammo_icon_02.tga textures/items/explosiveammo_icon_blank.tga textures/items/explosiveammo_icon_03.tga textures/items/explosiveammo_icon_03.tga textures/items/explosiveammo_icon_03.tga  textures/items/explosiveammo_icon_blank.tga 
+       blendFunc GL_ONE GL_ONE
+       rgbGen wave sawtooth 0 1 0 10
+       }
+
+}
+
+
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
diff --git a/textures/items/a_rocket_bottom.jpg b/textures/items/a_rocket_bottom.jpg
deleted file mode 100644 (file)
index b2db595..0000000
Binary files a/textures/items/a_rocket_bottom.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_box.jpg b/textures/items/a_rocket_box.jpg
deleted file mode 100644 (file)
index a29505b..0000000
Binary files a/textures/items/a_rocket_box.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_gre.jpg b/textures/items/a_rocket_gre.jpg
deleted file mode 100644 (file)
index 66fbc3c..0000000
Binary files a/textures/items/a_rocket_gre.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_gre_glow.jpg b/textures/items/a_rocket_gre_glow.jpg
deleted file mode 100644 (file)
index b26e87d..0000000
Binary files a/textures/items/a_rocket_gre_glow.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_roc.jpg b/textures/items/a_rocket_roc.jpg
deleted file mode 100644 (file)
index 300b2b9..0000000
Binary files a/textures/items/a_rocket_roc.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_roc_gloss.jpg b/textures/items/a_rocket_roc_gloss.jpg
deleted file mode 100644 (file)
index 0e6f937..0000000
Binary files a/textures/items/a_rocket_roc_gloss.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_roc_glow.jpg b/textures/items/a_rocket_roc_glow.jpg
deleted file mode 100644 (file)
index 2bb921a..0000000
Binary files a/textures/items/a_rocket_roc_glow.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_roc_norm.jpg b/textures/items/a_rocket_roc_norm.jpg
deleted file mode 100644 (file)
index 8073764..0000000
Binary files a/textures/items/a_rocket_roc_norm.jpg and /dev/null differ
diff --git a/textures/items/a_rocket_tag.jpg b/textures/items/a_rocket_tag.jpg
deleted file mode 100644 (file)
index 1314605..0000000
Binary files a/textures/items/a_rocket_tag.jpg and /dev/null differ
diff --git a/textures/items/explosiveammo.tga b/textures/items/explosiveammo.tga
new file mode 100644 (file)
index 0000000..45aa786
Binary files /dev/null and b/textures/items/explosiveammo.tga differ
diff --git a/textures/items/explosiveammo_gloss.tga b/textures/items/explosiveammo_gloss.tga
new file mode 100644 (file)
index 0000000..22d3f1e
Binary files /dev/null and b/textures/items/explosiveammo_gloss.tga differ
diff --git a/textures/items/explosiveammo_glow.tga b/textures/items/explosiveammo_glow.tga
new file mode 100644 (file)
index 0000000..0f1bdb1
Binary files /dev/null and b/textures/items/explosiveammo_glow.tga differ
diff --git a/textures/items/explosiveammo_icon_01.tga b/textures/items/explosiveammo_icon_01.tga
new file mode 100644 (file)
index 0000000..e368ea4
Binary files /dev/null and b/textures/items/explosiveammo_icon_01.tga differ
diff --git a/textures/items/explosiveammo_icon_01_glow.tga b/textures/items/explosiveammo_icon_01_glow.tga
new file mode 100644 (file)
index 0000000..22f1624
Binary files /dev/null and b/textures/items/explosiveammo_icon_01_glow.tga differ
diff --git a/textures/items/explosiveammo_icon_02.tga b/textures/items/explosiveammo_icon_02.tga
new file mode 100644 (file)
index 0000000..e368ea4
Binary files /dev/null and b/textures/items/explosiveammo_icon_02.tga differ
diff --git a/textures/items/explosiveammo_icon_02_glow.tga b/textures/items/explosiveammo_icon_02_glow.tga
new file mode 100644 (file)
index 0000000..d1dcd8b
Binary files /dev/null and b/textures/items/explosiveammo_icon_02_glow.tga differ
diff --git a/textures/items/explosiveammo_icon_03.tga b/textures/items/explosiveammo_icon_03.tga
new file mode 100644 (file)
index 0000000..e368ea4
Binary files /dev/null and b/textures/items/explosiveammo_icon_03.tga differ
diff --git a/textures/items/explosiveammo_icon_03_glow.tga b/textures/items/explosiveammo_icon_03_glow.tga
new file mode 100644 (file)
index 0000000..44a05dc
Binary files /dev/null and b/textures/items/explosiveammo_icon_03_glow.tga differ
diff --git a/textures/items/explosiveammo_icon_blank.tga b/textures/items/explosiveammo_icon_blank.tga
new file mode 100644 (file)
index 0000000..e368ea4
Binary files /dev/null and b/textures/items/explosiveammo_icon_blank.tga differ
diff --git a/textures/items/explosiveammo_norm.tga b/textures/items/explosiveammo_norm.tga
new file mode 100644 (file)
index 0000000..67c93ed
Binary files /dev/null and b/textures/items/explosiveammo_norm.tga differ
diff --git a/textures/items/explosiveammo_reflect.tga b/textures/items/explosiveammo_reflect.tga
new file mode 100644 (file)
index 0000000..6e2731b
Binary files /dev/null and b/textures/items/explosiveammo_reflect.tga differ
diff --git a/tx.sh b/tx.sh
index c2e9f3a5f5d00a5e41bbccd9db190182f785d70f..271f1cc75a82f1dbfbe48cbddd75a1c363fc8547 100644 (file)
--- a/tx.sh
+++ b/tx.sh
@@ -63,13 +63,15 @@ if $sync_po; then
                                cp "$tcurfile" "$gnewfile"
                        else
                                if ! diff -u "$goldfile" "$gnewfile" | patch "$tcurfile"; then
-                                       while :; do
-                                               vim -o "$tcurfile.rej" "$tcurfile"
-                                               echo "OK?"
-                                               read -r OK || exit 1
-                                               [ x"$OK" != x"y" ] || break
-                                       done
-                                       rm -f "$tcurfile.rej"
+                                       if [ -z "$BATCH" ]; then
+                                               while :; do
+                                                       vim -o "$tcurfile.rej" "$tcurfile"
+                                                       echo "OK?"
+                                                       read -r OK || exit 1
+                                                       [ x"$OK" != x"y" ] || break
+                                               done
+                                               rm -f "$tcurfile.rej"
+                                       fi
                                fi
                                msgmerge -N -F -U "$tcurfile" common.pot
                                cp "$tcurfile" "$gnewfile"
diff --git a/xonotic-client.cfg b/xonotic-client.cfg
new file mode 100644 (file)
index 0000000..5ac5a1e
--- /dev/null
@@ -0,0 +1,848 @@
+// this resets most client cvars and aliases to their defaults
+// if you want to reset your client to defaults, it's probably a better idea to delete (parts of) config.cfg and restart
+
+
+// changes a cvar and reports it to the server (for the menu to notify the
+// server about changes)
+alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
+
+seta cl_firststart "" "how many times the client has been run"
+seta cl_startcount 0 "how many times the client has been run"
+
+// other aliases
+alias +hook +button6
+alias -hook -button6
+alias +jetpack +button10
+alias -jetpack -button10
+alias +dodge +button11
+alias -dodge -button11
+alias use "impulse 21"
+
+// for backwards compatibility
+// TODO Remove after 0.8 release!
+cl_particles_forcetraileffects 1
+
+alias dropweapon "impulse 17"
+alias +show_info +button7
+alias -show_info -button7
+
+// merge lightmaps up to 2048x2048 textures
+mod_q3bsp_lightmapmergepower 4
+
+// player defaults
+_cl_color "112.211" // same effect as 112, but menuqc can detect this as the default and not intentionally set
+_cl_name ""
+seta _cl_gender 0 "storage cvar for current player gender (0 = undisclosed, 1 = male, 2 = female)"
+_cl_playerskin 0
+
+seta cl_reticle 1 "enable zoom reticles"
+seta cl_reticle_stretch 0 "stretch reticles so they fit the screen (breaks image proportions)"
+seta cl_reticle_normal 1 "draw an aiming reticle when zooming with the zoom button"
+seta cl_reticle_normal_alpha 1 "alpha of the normal reticle"
+seta cl_reticle_weapon 1 "draw custom aiming reticle when zooming with certain weapons"
+seta cl_reticle_weapon_alpha 1 "alpha of the custom reticle"
+
+fov 100
+seta cl_velocityzoom_enabled 0 "velocity based zooming of fov"
+seta cl_velocityzoom_factor 0 "factor of fov zooming (negative values zoom out)"
+seta cl_velocityzoom_type 3 "how to factor in speed, 1 = all velocity in all directions, 2 = velocity only in forward direction (can be negative), 3 = velocity only in forward direction (limited to forward only)"
+seta cl_velocityzoom_speed 1000 "target speed for fov factoring"
+seta cl_velocityzoom_time 0.2  "time value for averaging speed values"
+seta cl_spawnzoom 1 "zoom effect immediately when a player spawns"
+seta cl_spawnzoom_speed 1 "speed at which zooming occurs while spawning"
+seta cl_spawnzoom_factor 2 "factor of zoom while spawning"
+seta cl_zoomfactor 5   "how much +zoom will zoom (1-30)"
+seta cl_zoomspeed 8    "how fast it will zoom (0.5-16), negative values mean instant zoom"
+seta cl_zoomsensitivity 0      "how zoom changes sensitivity (0 = weakest, 1 = strongest)"
+
+seta cl_unpress_zoom_on_spawn 1 "automatically unpress zoom when you spawn"
+seta cl_unpress_zoom_on_death 1 "automatically unpress zoom when you die (and don't allow zoom again while dead)"
+seta cl_unpress_zoom_on_weapon_switch 1 "automatically unpress zoom when you switch a weapon"
+seta cl_unpress_attack_on_weapon_switch 0 "automatically unpress fire and fire1 attack buttons when you switch a weapon"
+
+seta cl_spawn_event_particles 1 "pointparticles effect whenever a player spawns"
+seta cl_spawn_event_sound 1 "sound effect whenever a player spawns"
+//seta cl_spawn_point_model 0 "place a model at all spawn points" // still needs a model
+seta cl_spawn_point_particles 1 "pointparticles effect at all spawn points" // managed by effects-.cfg files
+seta cl_spawn_point_dist_min 1200
+seta cl_spawn_point_dist_max 1600
+
+freelook 1
+sensitivity 6
+v_gamma 1
+viewsize 100
+bgmvolume 1
+volume 0.5
+// fullscreen 1024x768x32bit
+vid_bitsperpixel 32
+vid_fullscreen 1
+vid_width 1024
+vid_height 768
+vid_pixelheight 1
+vid_resizable 0 // cannot be turned on before it is sure it cannot cause a r_restart
+vid_desktopfullscreen 1
+prvm_language en
+set _menu_prvm_language ""
+set _menu_vid_width "$vid_width"
+set _menu_vid_height "$vid_height"
+set _menu_vid_pixelheight "$vid_pixelheight"
+set _menu_vid_desktopfullscreen "$vid_desktopfullscreen"
+seta menu_vid_scale 0
+seta menu_vid_allowdualscreenresolution 0
+// 2D resolution 800x600
+vid_conwidth 800
+vid_conheight 600
+// menu_conwidth, menu_conheight are set inside quake.rc
+v_deathtilt 0 // needed for spectators (who are dead to avoid prediction)
+
+// create a temporary empty alias for menu_sync so that execution of effects-normal.cfg, hud_luma.cfg
+// and sRGB-{disable,enable}.cfg on game start doesn't show an error message in the console
+alias menu_sync "" // will be re-aliased later
+
+// we want to use sRGB for our maps!
+exec sRGB-disable.cfg
+vid_sRGB_fallback 2
+r_hdr_glowintensity 1
+// #define Image_LinearFloatFromsRGBFloat(c) (((c) <= 0.04045f) ? (c) * (1.0f / 12.92f) : (float)pow(((c) + 0.055f)*(1.0f/1.055f), 2.4f))
+set rpn_sRGB_to_linear "dup 0.055 add 1.055 div 2.4 pow exch 12.92 div dup 0.0031308 gt when"
+// #define Image_sRGBFloatFromLinearFloat(c) (((c) < 0.0031308f) ? (c) * 12.92f : 1.055f * (float)pow((c), 1.0f/2.4f) - 0.055f)
+set rpn_linear_to_sRGB "dup 1.0 2.4 div pow 1.055 mul 0.055 sub exch 12.92 mul dup 0.04045 ge when"
+
+// -nosRGB to -sRGB sky shader conversion:
+//
+// q3map_sunExt 1 0.6875 0.375 340 25 47 0 16
+//                                    ^^ elevation
+//                             ^^^ sunlight
+// q3map_skylight 110 3
+//                ^^^ skylight
+//
+// With that, do (the last parameter is the ratio of skylight you assume hits
+// the surfaces, about 0.25 for inner surfaces near sky, about 1.00 on
+// terrain):
+// ]skybox_nosRGB_to_sRGB 340 47 110 0.25
+// rpn: still on stack: new_sunlight:
+// rpn: still on stack: 380.464142
+// rpn: still on stack: new_skylight:
+// rpn: still on stack: 9.32523632
+//
+// The equivalent -sRGB shader then will have:
+//
+// q3map_sunExt 1 0.6875 0.375 380.464142 25 47 0 16
+// q3map_skylight 9.32523632 3
+alias skybox_nosRGB_to_sRGB "rpn $3 402.123 $4 div div $rpn_sRGB_to_linear 402.123 $4 div mul /new_skylight: $3 402.123 $4 div div $1 256 div $2 0.017453 mul sin mul add $rpn_sRGB_to_linear $3 402.123 $4 div div $rpn_sRGB_to_linear sub 256 mul $2 0.017453 mul sin div /new_sunlight:"
+
+set cl_orthoview 0 "enable top-down view of the map- meant to be used for radar map images (note: orthoview sets cvars temporarily, requires restart to return them to normal)"
+set cl_orthoview_nofog 1 "disable fog while in orthoview-- note, should not be enabled on ALL maps, i.e. oilrig works fine with this disabled"
+
+// these settings determine how much the view is affected by movement/damage
+cl_smoothviewheight 0.05 // time of the averaging to the viewheight value so that it creates a smooth transition for crouching and such. 0 for instant transition
+cl_deathfade 0 // fade screen to dark red when dead, value represents how fast the fade is (higher is faster)
+cl_bobcycle 0.5 // how long the cycle of up/down view movement takes (only works if cl_bob is not 0), default is 0.6
+cl_bob 0 // how much view moves up/down when moving (does not move if cl_bobcycle is 0, but still enables cl_bobmodel), default is 0.02
+cl_bob2cycle 1 // how long the cycle of left/right view movement takes (only works if cl_bob2 is not 0), default is 0.6
+cl_bob2 0 // how much view moves left/right when moving (does not move if cl_bob2cycle is 0), default is 0.01
+cl_bobfall 0.05 "how much the view swings down when falling (influenced by the speed you hit the ground with)"
+cl_bobfallcycle 3 "speed of the bobfall swing"
+cl_bobfallspeed 200 "necessary amount of speed for bob-falling to occur"
+cl_bobmodel 1 // whether to have gun model move around on screen when moving (only works if cl_bob is not 0), default is 1
+cl_bobmodel_side 0.2 // amount the gun sways to the sides
+cl_bobmodel_speed 10 // rate at which the gun sways
+cl_bobmodel_up 0.1 // amount the gun sways up and down
+
+cl_followmodel 1 // enables weapon pushing / pulling effect when walking
+seta cl_followmodel_speed 0.3 "gun following speed"
+seta cl_followmodel_limit 135 "gun following limit"
+seta cl_followmodel_velocity_absolute 0 "make the effect ignore velocity direction changes (side effect: it causes a glitch when teleporting / passing through a warpzone)"
+seta cl_followmodel_velocity_lowpass 0.05 "gun following velocity lowpass averaging time"
+seta cl_followmodel_highpass 0.05 "gun following highpass averaging time"
+seta cl_followmodel_lowpass 0.03 "gun following lowpass averaging time"
+
+cl_leanmodel 1 // enables weapon leaning effect when looking around
+seta cl_leanmodel_speed 0.3 "gun leaning speed"
+seta cl_leanmodel_limit 30 "gun leaning limit"
+seta cl_leanmodel_highpass1 0.2 "gun leaning pre-highpass averaging time"
+seta cl_leanmodel_highpass 0.2 "gun leaning highpass averaging time"
+seta cl_leanmodel_lowpass 0.05 "gun leaning lowpass averaging time"
+
+cl_rollangle 0 // amount of view tilt when strafing, default is 2.0
+v_kicktime 0 // how long damage kicks of the view last, default is 0 seconds
+gl_polyblend 0 // whether to use screen tints, this has now been replaced by a better system in CSQC
+r_motionblur 0 // motion blur value, default is 0
+r_damageblur 0 // motion blur when damaged, default is 0 (removed in Xonotic)
+
+r_bloom_blur 4
+r_bloom_brighten 2
+r_bloom_colorexponent 1
+r_bloom_colorscale 1
+r_bloom_colorsubtract 0.125
+r_bloom_resolution 320
+r_bloom_scenebrightness 0.85
+
+seta vid_x11_display ""        "xonotic-linux-*.sh will use this to start xonotic on an other/new X display"
+// This can have three possible settings:
+//     ""              run as usual
+//     ":n"            use DISPLAY=:n, create it if needed
+//     ":n/layout"     use DISPLAY=:n, create it if needed with ServerLayout layout
+
+cl_autodemo_nameformat demos/%Y-%m-%d_%H-%M
+
+// taunts and voices
+seta cl_autotaunt 0 "automatically taunt enemies when fragging them"
+seta cl_voice_directional 1    "0 = all voices are non-directional, 1 = all voices are directional, 2 = only taunts are directional"
+seta cl_voice_directional_taunt_attenuation 0.5 "this defines the distance from which taunts can be heard"
+
+seta cl_hitsound 1 "play a hit notifier sound when you have hit an enemy, 1: same pitch 2: increase pitch with more damage 3: decrease pitch with more damage"
+set cl_hitsound_antispam_time 0.05 "don't play the hitsound more often than this"
+seta cl_hitsound_min_pitch 0.75 "minimum pitch of hit sound"
+seta cl_hitsound_max_pitch 1.5 "maximum pitch of hit sound"
+seta cl_hitsound_nom_damage 25 "damage amount at which hitsound bases pitch off"
+
+seta cl_eventchase_death 1 "camera goes into 3rd person mode when the player is dead; set to 2 to active the effect only when the corpse doesn't move anymore"
+seta cl_eventchase_frozen 0 "camera goes into 3rd person mode when the player is frozen"
+seta cl_eventchase_nexball 1 "camera goes into 3rd person mode when in nexball game-mode"
+seta cl_eventchase_distance 140 "final camera distance"
+seta cl_eventchase_generator_distance 400 "final camera distance while viewing generator explosion"
+seta cl_eventchase_speed 1.3 "how fast the camera slides back, 0 is instant"
+seta cl_eventchase_maxs "12 12 8" "max size of eventchase camera bbox"
+seta cl_eventchase_mins "-12 -12 -8" "min size of eventchase camera bbox"
+seta cl_eventchase_viewoffset "0 0 20" "viewoffset of eventchase camera"
+seta cl_eventchase_generator_viewoffset "0 0 80" "viewoffset of eventchase camera while viewing generator explosion"
+seta cl_eventchase_vehicle 1 "camera goes into 3rd person mode when inside a vehicle"
+seta cl_eventchase_vehicle_viewoffset "0 0 80"
+seta cl_eventchase_vehicle_distance 250
+
+set _vehicles_shownchasemessage 0
+
+seta cl_particles_oldvortexbeam 0 "Uses the old v2.3 Vortex beam instead of the new beam, only works if server allows it (g_allow_oldvortexbeam 1)"
+
+seta cl_damageeffect 1 "enable weapon damage effects: 1 enables the feature on skeletal models, 2 on any model"
+seta cl_damageeffect_ticrate 0.1 "particle spawn rate"
+seta cl_damageeffect_bones 5 "how many damages to allow on a rigged mesh at once (non-skeletal objects are limited to one)"
+seta cl_damageeffect_distribute 1 "divide particle intensity if multiple damages are present"
+seta cl_damageeffect_lifetime 0.1 "how much a damage effect lasts, based on damage amount"
+seta cl_damageeffect_lifetime_min 3 "minimum lifetime a damage effect may have"
+seta cl_damageeffect_lifetime_max 6 "maximum lifetime a damage effect may have"
+
+set cl_deathglow 0.8 "number of seconds during which dead bodies glow out"
+
+cl_movement 1
+cl_movement_track_canjump 0
+cl_stairsmoothspeed 200
+
+alias g_waypointeditor_spawn "impulse 103"
+alias g_waypointeditor_remove "impulse 104"
+alias g_waypointeditor_relinkall "impulse 105"
+alias g_waypointeditor_saveall "impulse 106"
+alias g_waypointeditor_unreachable "impulse 107"
+
+seta menu_sandbox_spawn_model ""
+seta menu_sandbox_attach_bone ""
+seta menu_sandbox_edit_skin 0
+seta menu_sandbox_edit_alpha 1
+seta menu_sandbox_edit_color_main "1 1 1"
+seta menu_sandbox_edit_color_glow "1 1 1"
+seta menu_sandbox_edit_frame 0
+seta menu_sandbox_edit_scale 1
+seta menu_sandbox_edit_solidity 1
+seta menu_sandbox_edit_physics 1
+seta menu_sandbox_edit_force 1
+seta menu_sandbox_edit_material ""
+
+seta menu_monsters_edit_spawn ""
+seta menu_monsters_edit_skin 0
+seta menu_monsters_edit_movetarget 1
+
+// effects
+r_glsl_vertextextureblend_usebothalphas 1 // allows to abuse texture blending as detail texture
+mod_q3shader_force_terrain_alphaflag 1 // supposedly now required for r_glsl_vertextextureblend_usebothalphas to work
+r_glsl_postprocess 0 // but note, hud_postprocessing enables this
+r_picmipsprites 0 // Xonotic uses sprites that should never be picmipped (team mate, typing, waypoints)
+r_picmipworld 1
+gl_picmip_world 0
+gl_picmip_sprites 0
+gl_picmip_other 1 // so, picmip -1 is best possible quality
+r_mipsprites 1
+r_mipskins 1
+gl_max_lightmapsize 4096
+r_shadow_realtime_world_lightmaps 1
+r_shadow_realtime_world_importlightentitiesfrommap 0 // Whether build process uses keepLights is nontransparent and may change, so better make keepLights not matter.
+cl_decals_fadetime 5
+cl_decals_time 1
+seta cl_gunalign 3 "Gun alignment; 1 = center, 3 = right, 4 = left; requires reconnect"
+seta cl_nogibs 0 "reduce number of violence effects, or remove them totally"
+seta cl_particlegibs 0 "simpler gibs"
+seta cl_gibs_damageforcescale 3.5 "force to push around gibs"
+seta cl_gibs_lifetime 2.5 "average lifetime of gibs"
+seta cl_gibs_velocity_scale 1 "gib throw velocity force scale"
+seta cl_gibs_velocity_random 1 "gib throw velocity randomness scale"
+seta cl_gibs_velocity_up 1 "extra z velocity for gibs"
+seta cl_gibs_ticrate 0.1 "ticrate for gibs"
+seta cl_gibs_sloppy 1 "sloppy gibs, may temporarily penetrate walls"
+seta cl_gibs_avelocity_scale 1 "how much angular velocity to use on gibs"
+seta cl_casings 1 "enable or disable bullet casings"
+seta cl_casings_shell_time 30 "shell casing lifetime"
+seta cl_casings_bronze_time 10 "bullet casings lifetime"
+seta cl_casings_ticrate 0.1 "ticrate for casings"
+seta cl_casings_sloppy 1 "sloppy casings, may temporarily penetrate walls"
+seta cl_projectiles_sloppy 1 "sloppy projectiles, may temporarily penetrate walls"
+cl_stainmaps 0
+cl_particles_smoke 1
+vid_gl20 1
+r_glsl_deluxemapping 1
+r_glsl_offsetmapping 0
+r_glsl_offsetmapping_lod 1
+r_glsl_offsetmapping_reliefmapping 0
+r_glsl_offsetmapping_scale 0.02
+
+scr_conalpha 1
+scr_conbrightness 0.2
+scr_screenshot_jpeg 1
+scr_screenshot_jpeg_quality 0.9
+
+cl_sound_wizardhit ""
+cl_sound_hknighthit ""
+cl_sound_tink1 weapons/tink1.wav
+cl_sound_ric1 weapons/ric1.wav
+cl_sound_ric2 weapons/ric2.wav
+cl_sound_ric3 weapons/ric3.wav
+cl_sound_r_exp3 ""
+
+seta cl_announcer default "name of the announcer you wish to use from data/sound/announcer"
+seta cl_announcer_antispam 2 "number of seconds before an announcement of the same sound can be played again"
+seta cl_announcer_maptime 3 "play announcer sound telling you the remaining maptime - 0: do not play at all, 1: play at one minute, 2: play at five minutes, 3: play both"
+
+// aliases:
+alias +fire +attack
+alias -fire -attack
+alias +fire2 +button3
+alias -fire2 -button3
+alias +attack2 +button3 // old alias from Nexuiz
+alias -attack2 -button3 // old alias name from Nexuiz
+alias +crouch +button5
+alias -crouch -button5
+alias weapnext "_weapnext_${cl_weaponpriority_useforcycling}"
+alias _weapnext_0 "impulse 18"
+alias _weapnext_1 "impulse 15"
+alias _weapnext_2 "impulse 10"
+alias weaplast "impulse 11"
+alias weapprev "_weapprev_${cl_weaponpriority_useforcycling}"
+alias _weapprev_0 "impulse 19"
+alias _weapprev_1 "impulse 16"
+alias _weapprev_2 "impulse 12"
+alias weapbest "impulse 13"
+
+// experimental zoom toggle (can be in wrong state at start of a game, though)
+set _togglezoom +
+alias +zoom "set _togglezoom -; +button4"
+alias -zoom "set _togglezoom +; -button4"
+alias togglezoom "${_togglezoom}zoom"
+
+alias reload "impulse 20"
+
+// weapons
+alias weapon_group_1 "impulse 1"
+alias weapon_group_2 "impulse 2"
+alias weapon_group_3 "impulse 3"
+alias weapon_group_4 "impulse 4"
+alias weapon_group_5 "impulse 5"
+alias weapon_group_6 "impulse 6"
+alias weapon_group_7 "impulse 7"
+alias weapon_group_8 "impulse 8"
+alias weapon_group_9 "impulse 9"
+alias weapon_group_0 "impulse 14" // cycles the superweapons
+// TODO: remove after 0.8.2. Default impulse commands for 0.8.1 servers
+exec weapons.cfg
+
+cl_curl_enabled 1
+cl_curl_maxdownloads 3
+cl_curl_maxspeed 0
+cl_curl_useragent 1
+cl_curl_useragent_append "$g_xonoticversion"
+
+seta g_waypointsprite_alpha 1 "This allows the client to control transparency of the waypoint"
+seta g_waypointsprite_crosshairfadealpha 0.25 "alpha multiplier near crosshair"
+seta g_waypointsprite_crosshairfadescale 1 "scale multiplier near the crosshair"
+seta g_waypointsprite_crosshairfadedistance 150 "distance in virtual pixels from crosshair where to start fading"
+seta g_waypointsprite_distancefadealpha 1 "alpha multiplier near distance"
+seta g_waypointsprite_distancefadescale 0.7 "scale multiplier near the distance"
+seta g_waypointsprite_distancefadedistancemultiplier 0.5 "distance in map sizes from distance where to stop fading"
+set g_waypointsprite_distancealphaexponent 2
+seta g_waypointsprite_edgefadealpha 0.5 "alpha multiplier near the edge"
+seta g_waypointsprite_edgefadedistance 50 "distance in virtual pixels from edge where to start fading"
+seta g_waypointsprite_edgefadescale 1 "scale multiplier near the edge"
+seta g_waypointsprite_edgeoffset_bottom 0 "offset of how close the waypoint can be to the bottom edge of the screen"
+seta g_waypointsprite_edgeoffset_left 0 "offset of how close the waypoint can be to the left edge of the screen"
+seta g_waypointsprite_edgeoffset_right 0 "offset of how close the waypoint can be to the right edge of the screen"
+seta g_waypointsprite_edgeoffset_top 0 "offset of how close the waypoint can be to the top edge of the screen"
+seta g_waypointsprite_fontsize 12
+seta g_waypointsprite_itemstime 2 "show waypoints to indicate that some important items (mega health, large armor) are about to respawn: 1 when spectating, 2 even playing in warmup stage"
+set g_waypointsprite_minscale 0.5
+set g_waypointsprite_minalpha 0.4
+set g_waypointsprite_normdistance 512
+seta g_waypointsprite_scale 1
+set g_waypointsprite_spam 0 "Debugging feature. Set to 10 and load courtfun in race mode to test."
+set g_waypointsprite_timealphaexponent 1
+seta g_waypointsprite_turrets 1 "disable turret waypoints"
+seta g_waypointsprite_turrets_maxdist 5000 "max distance for turret waypoints"
+seta g_waypointsprite_uppercase 1
+seta g_waypointsprite_text 0 "Always show text instead of icons, setting this to 0 will still use text if the icon is unavailable"
+seta g_waypointsprite_iconsize 32
+seta g_waypointsprite_iconcolor 0 "Show the icon at natural color rather than the waypoint's color"
+
+alias "g_waypointsprite_personal"      "impulse 30"
+alias "g_waypointsprite_personal_p"    "impulse 31"
+alias "g_waypointsprite_personal_d"    "impulse 32"
+alias "g_waypointsprite_team_helpme"   "impulse 33"
+alias "g_waypointsprite_team_here"     "impulse 34"
+alias "g_waypointsprite_team_here_p"   "impulse 35"
+alias "g_waypointsprite_team_here_d"   "impulse 36"
+alias "g_waypointsprite_team_danger"   "impulse 37"
+alias "g_waypointsprite_team_danger_p" "impulse 38"
+alias "g_waypointsprite_team_danger_d" "impulse 39"
+alias "g_waypointsprite_clear_personal"        "impulse 47"
+alias "g_waypointsprite_clear" "impulse 48"
+alias "g_waypointsprite_toggle"        "toggle cl_hidewaypoints"
+
+seta cl_hidewaypoints 0 "disable static waypoints, only show team waypoints"
+
+seta cl_damagetext "1" "Draw damage dealt where you hit the enemy"
+seta cl_damagetext_format "-{total}" "How to format the damage text. {health}, {armor}, {total}, {potential}: full damage not capped to target's health, {potential_health}: health damage not capped to target's health"
+seta cl_damagetext_format_verbose 0 "{health} shows {potential_health} too when they differ; {total} shows {potential} too when they differ"
+seta cl_damagetext_format_hide_redundant 0 "hide {armor} if 0; hide {potential} and {potential_health} when same as actual"
+seta cl_damagetext_color "1 1 0" "Damage text color"
+seta cl_damagetext_color_per_weapon "0" "Damage text uses weapon color"
+seta cl_damagetext_size_min 10 "Damage text font size for small damage"
+seta cl_damagetext_size_min_damage 25 "How much damage is considered small"
+seta cl_damagetext_size_max 16 "Damage text font size for large damage"
+seta cl_damagetext_size_max_damage 140 "How much damage is considered large"
+seta cl_damagetext_alpha_start "1" "Damage text initial alpha"
+seta cl_damagetext_alpha_lifetime "3" "Damage text lifetime in seconds"
+seta cl_damagetext_velocity "0 0 20" "Damage text move direction"
+seta cl_damagetext_offset "0 -40 0" "Damage text offset"
+seta cl_damagetext_accumulate_range "30" "Damage text spawned within this range is accumulated"
+seta cl_damagetext_accumulate_alpha_rel "0.65" "Only update existing damage text when it's above this much percentage (0 to 1) of the starting alpha"
+seta cl_damagetext_friendlyfire "1" "Show damage text for friendlyfire too"
+seta cl_damagetext_friendlyfire_color "1 0 0" "Damage text color for friendlyfire"
+
+seta cl_damagetext_2d_pos "0.47 0.53 0" "2D damage text initial position (X and Y between 0 and 1)"
+seta cl_damagetext_2d_alpha_start 1 "2D damage text initial alpha"
+seta cl_damagetext_2d_alpha_lifetime 1.3 "2D damage text lifetime (alpha fading) in seconds"
+seta cl_damagetext_2d_size_lifetime 3 "2D damage text lifetime (size shrinking) in seconds"
+seta cl_damagetext_2d_velocity "-25 0 0" "2D damage text move direction (screen coordinates)"
+seta cl_damagetext_2d_overlap_offset "0 -15 0" "Offset 2D damage text by this much to prevent overlapping (screen coordinates)"
+seta cl_damagetext_2d_close_range 125 "Always use 2D damagetext for hits closer that this"
+seta cl_damagetext_2d_out_of_view 1 "Always use 2D damagetext for hits that occured off-screen"
+
+seta cl_vehicles_alarm 1 "Play an alarm sound when the vehicle you are driving is heavily damaged"
+seta cl_vehicles_hud_tactical 1
+seta cl_vehicles_hudscale 0.5
+seta cl_vehicles_notify_time 15
+seta cl_vehicles_crosshair_size 0.5
+seta cl_vehicles_crosshair_colorize 1
+
+r_labelsprites_scale 0.40625 // labels sprites get displayed at 0.5x from 640x480 to 1280x1024, and at 1x from 1600x1200 onwards
+
+exec binds-xonotic.cfg
+
+seta menu_skin "luma"
+set menu_slowmo 1
+seta menu_sounds 0 "enables menu sound effects. 1 enables click sounds, 2 also enables hover sounds"
+seta menu_tooltips 1 "menu tooltips: 0 disabled, 1 enabled, 2 also shows cvar or console command (when available) changed or executed by the item"
+set menu_picmip_bypass 0 "bypass texture quality enforcement based on system resources, not recommended and may cause crashes!"
+set menu_showboxes 0 "show item bounding boxes (debug)"
+set menu_cvarlist_onlymodified 0 "show only modified cvars in the cvar list"
+set menu_force_on_disconnection 1 "force to show the menu this number of seconds after you get disconnected (0 to disable)"
+
+r_textbrightness 0.2
+r_textcontrast 0.8
+r_textshadow 0
+r_font_postprocess_blur 1
+r_font_postprocess_outline 1
+
+// good settings for these fonts
+con_chat 5
+con_chatpos -9
+con_chatsize 10
+con_chatwidth 0.6
+con_notify 0
+con_notifysize 10
+con_notifyalign 0
+con_textsize 10
+
+seta sbar_info_pos 0 "Y-axis distance from lower right corner for engine info prints"
+
+// scoreboard
+seta scoreboard_columns default
+
+// keep old scoreboard cvars for compatibility's sake
+// they've been replaced by hud_panel_scoreboard_* cvars
+// TODO remove them after a future release (0.8.2+)
+seta scoreboard_border_thickness 1 "scoreboard border thickness"
+seta scoreboard_accuracy_border_thickness 1 "accuracy stats border thickness"
+seta scoreboard_accuracy_doublerows 0 "use two rows instead of one"
+seta scoreboard_accuracy_nocolors 0 "don't use colors displaying accuracy stats"
+seta scoreboard_accuracy 1 "show weapon accuracy stats panel on scoreboard; colors can be configured with accuracy_color* cvars"
+seta scoreboard_color_bg_r 0.125 "red color component of the scoreboard background"
+seta scoreboard_color_bg_g 0.55 "green color component of the scoreboard background"
+seta scoreboard_color_bg_b 0.875 "blue color component of the scoreboard background"
+seta scoreboard_color_bg_team 0.6 "team color multiplier of the scoreboard background"
+seta scoreboard_alpha_bg 0.7 "scoreboard background alpha"
+seta scoreboard_alpha_fg 1 "scoreboard foreground alpha"
+seta scoreboard_alpha_name 0.9 "alpha of player text in scoreboard list other than self"
+seta scoreboard_alpha_name_self 1 "alpha of player text in scoreboard list of self"
+seta scoreboard_fadeinspeed 10 "speed at which scoreboard fades in, higher is faster (0 = instant)"
+seta scoreboard_fadeoutspeed 5 "speed at which scoreboard fades out, higher is faster (0 = instant)"
+seta scoreboard_highlight 1 "enable highlighting for rows and columns in the scoreboard"
+seta scoreboard_highlight_alpha 0.08 "highlight alpha value (depends on hud_scoreboard_highlight 1)"
+seta scoreboard_highlight_alpha_self 0.3 "self highlight alpha value"
+seta scoreboard_offset_left 0.15 "how far (by percent) the scoreboard is offset from the left screen edge"
+seta scoreboard_offset_right 0.15 "how far (by percent) the scoreboard is offset from the right screen edge"
+seta scoreboard_offset_vertical 0.05 "how far (by percent) the scoreboard is offset from the top and bottom of the screen"
+seta scoreboard_bg_scale 0.25 "scale for the tiled scoreboard background"
+seta scoreboard_respawntime_decimals 1 "decimal places to show for the respawntime countdown display on the scoreboard"
+seta scoreboard_dynamichud 0 "apply the dynamic hud effects to the scoreboard"
+
+seta accuracy_color_levels "0 20 100" "accuracy values at which a specified color (accuracy_color<X>) will be used. If your accuracy is between 2 of these values then a mix of the Xth and X+1th colors will be used. You can specify up to 10 values, in increasing order"
+seta accuracy_color0 "1 0 0"
+seta accuracy_color1 "1 1 0"
+seta accuracy_color2 "0 1 0"
+
+// for menu server list (eventually make them have engine support?)
+seta menu_slist_showfull 1 "show servers even if they are full and have no slots to join"
+seta menu_slist_showempty 1 "show servers even if they are no empty and have no opponents to play against"
+seta menu_slist_modfilter "" // set to either: !modname or modname. modname of = means "same as we are running now".
+
+// other serverlist cvars
+seta menu_slist_categories 1
+seta menu_slist_categories_onlyifmultiple 1
+seta menu_slist_purethreshold 0
+seta menu_slist_modimpurity 0
+seta menu_slist_recommendations 3
+seta menu_slist_recommendations_maxping 150
+seta menu_slist_recommendations_minfreeslots 1
+seta menu_slist_recommendations_minhumans 0
+seta menu_slist_recommendations_purethreshold -1
+
+// serverlist category override cvars
+seta menu_slist_categories_CAT_FAVORITED_override ""
+seta menu_slist_categories_CAT_RECOMMENDED_override ""
+seta menu_slist_categories_CAT_NORMAL_override ""
+seta menu_slist_categories_CAT_SERVERS_override "CAT_NORMAL"
+seta menu_slist_categories_CAT_XPM_override ""
+seta menu_slist_categories_CAT_MODIFIED_override ""
+seta menu_slist_categories_CAT_OVERKILL_override ""
+seta menu_slist_categories_CAT_INSTAGIB_override ""
+seta menu_slist_categories_CAT_DEFRAG_override ""
+
+seta menu_weaponarena ""
+
+seta menu_maxplayers 16 "maxplayers value when the menu starts a game"
+
+// useful keybind to maximize the chat area temporarily
+// HUD code takes care of many of these now...
+//set _backup_con_chatvars_set 0
+//alias _restore_con_chatvars_0 ""
+//alias _restore_con_chatvars_1 "set _backup_con_chatvars_set 0; con_chatpos $_backup_con_chatpos; con_chat $_backup_con_chat; con_notify $_backup_con_notify; con_chattime $_backup_con_chattime; cl_deathscoreboard $_backup_cl_deathscoreboard; scr_centertime $_backup_scr_centertime;r_track_sprites $_backup_r_track_sprites"
+//alias _restore_con_chatvars "_restore_con_chatvars_$_backup_con_chatvars_set"
+//alias _backup_con_chatvars_0 "set _backup_con_chatvars_set 1; set _backup_con_chatpos $con_chatpos; set _backup_con_chat $con_chat; set _backup_con_notify $con_notify; set _backup_con_chattime $con_chattime; set _backup_cl_deathscoreboard $cl_deathscoreboard; set _backup_scr_centertime $scr_centertime;set _backup_r_track_sprites $r_track_sprites"
+//alias _backup_con_chatvars_1 ""
+//alias _backup_con_chatvars "_backup_con_chatvars_$_backup_con_chatvars_set"
+//alias +con_chat_maximize "_backup_con_chatvars; con_chatpos -9; con_chat 100; con_notify 0; con_chattime 3600; cl_deathscoreboard 0; scr_centertime 0; r_track_sprites 0"
+//alias -con_chat_maximize "_restore_con_chatvars"
+
+set _con_chat_maximized 0
+set _backup_con_chatvars_set 0
+alias _restore_con_chatvars_0 ""
+alias _restore_con_chatvars_1 "set _backup_con_chatvars_set 0; con_notify $_backup_con_notify; con_chattime $_backup_con_chattime; cl_deathscoreboard $_backup_cl_deathscoreboard; scr_centertime $_backup_scr_centertime;r_track_sprites $_backup_r_track_sprites"
+alias _restore_con_chatvars "_restore_con_chatvars_$_backup_con_chatvars_set"
+alias _backup_con_chatvars_0 "set _backup_con_chatvars_set 1; set _backup_con_notify $con_notify; set _backup_con_chattime $con_chattime; set _backup_cl_deathscoreboard $cl_deathscoreboard; set _backup_scr_centertime $scr_centertime;set _backup_r_track_sprites $r_track_sprites"
+alias _backup_con_chatvars_1 ""
+alias _backup_con_chatvars "_backup_con_chatvars_$_backup_con_chatvars_set"
+alias +con_chat_maximize "_con_chat_maximized 1; _backup_con_chatvars; con_notify 0; con_chattime 3600; cl_deathscoreboard 0; scr_centertime 0; r_track_sprites 0"
+alias -con_chat_maximize "_con_chat_maximized 0; _restore_con_chatvars"
+
+// tab completion
+set con_completion_playdemo    *.dem
+set con_completion_timedemo    *.dem
+set con_completion_ply         *.dem
+set con_completion_tdem                *.dem
+set con_completion_exec                *.cfg
+set con_completion_chmap       map
+set con_completion_devmap      map
+set con_completion_gotomap     map
+set con_completion_vmap                map
+set con_completion_vnextmap    map
+set con_completion_vdomap      map
+set con_completion_playermodel "models/player/*.iqm"
+
+// helper
+// these non-saved engine cvars shall be saved
+alias makesaved "seta $1 \"${$1 ?}\""
+makesaved cl_maxfps_alwayssleep
+makesaved cl_port
+makesaved gl_finish
+makesaved net_slist_queriespersecond
+makesaved r_ambient
+makesaved r_drawviewmodel
+makesaved r_showsurfaces
+makesaved r_subdivisions_tolerance
+makesaved skill
+makesaved vid_gl13
+makesaved vid_gl20
+makesaved v_idlescale
+makesaved v_kicktime
+makesaved music_playlist_list0
+makesaved music_playlist_random0
+
+cl_netfps 60 // should match or be a multiple of sys_ticrate
+
+seta gl_texturecompression 0
+gl_texturecompression_color 1
+gl_texturecompression_gloss 1
+gl_texturecompression_glow 1
+gl_texturecompression_lightcubemaps 1
+gl_texturecompression_q3bsplightmaps 0
+gl_texturecompression_sky 1
+
+cl_maxfps 200
+
+seta menu_mouse_absolute 1 "use the OS mouse pointer motion for menu"
+seta menu_mouse_speed 1 "speed multiplier for the mouse in the menu (does not affect in-game aiming)"
+set menu_use_default_hostname 1
+alias sethostname "set menu_use_default_hostname 0; hostname $*"
+
+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 "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"
+seta cl_weaponpriority8 ""                                                              "use weapon_priority_8_prev for prev gun from this list, weapon_priority_8_best for best gun, weapon_priority_8_next for next gun"
+seta cl_weaponpriority9 ""                                                              "use weapon_priority_9_prev for prev gun from this list, weapon_priority_9_best for best gun, weapon_priority_9_next for next gun"
+seta cl_weaponimpulsemode 0 "0: only cycle between currently usable weapons in weapon priority order; 1: cycle between all possible weapons on a key in weapon priority order"
+
+alias _gl_flashblend_update_00 "gl_flashblend 1"
+alias _gl_flashblend_update_10 "gl_flashblend 0"
+alias _gl_flashblend_update_01 "gl_flashblend 0"
+alias _gl_flashblend_update_11 "gl_flashblend 0"
+alias gl_flashblend_update "_gl_flashblend_update_$r_shadow_realtime_dlight$r_showsurfaces"
+
+set cl_handicap 1      "multiplies damage received and divides damage dealt NOTE: reconnect or use 'sendcvar cl_handicap' to update the choice."
+
+seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice."
+
+seta cl_autoscreenshot 1 "Take a screenshot upon the end of a match... 0 = Disable completely, 1 = Allow sv_autoscreenshot to take a screenshot when requested, 2 = Always take an autoscreenshot anyway."
+
+seta cl_jetpack_jump 1 "Activate jetpack by pressing jump in the air. 0 = Disable, 1 = Stop when touching ground, 2 = Enable"
+
+seta cl_race_cptimes_showself 1 "Always show your own times as well as the current best on checkpoints in Race/CTS"
+seta cl_race_cptimes_onlyself 0 "Only show your own times on checkpoints in Race/CTS"
+
+set cl_stripcolorcodes 0       "experimental feature (notes: strips ALL color codes from messages!)"
+
+// Demo camera
+set camera_enable              0       "Enables the camera for demo playback"
+set camera_free                0       "Free camera instead of chasing the player"
+set camera_reset               0       "Resets the camera position and switch to chase mode"
+set camera_speed_roll          0.9     "Camera rotation speed"
+set camera_speed_chase                 4       "Camera movement speed on the x/y/z axis while chasing the player"
+set camera_speed_free          8       "Camera movement speed on the x/y/z axis in free mode"
+set camera_speed_attenuation   10      "Camera movements attenuation factor. Bigger is smoother. Applies to mouse movements"
+set camera_mouse_threshold     0.5     "Use to ignore small mouse movements. This allows for smoother camera control"
+set camera_chase_smoothly      0       "Attenuate player movements (only in chase mode)"
+set camera_look_player         0       "Always look to the player. Mouse input is ignored in this mode"
+set camera_look_attenuation    8       "Attenuation of \"looking\" movements, only if camera_look_player is set. Bigger is smoother"
+set camera_forward_follows     1       "0: Move the camera forwards without changing altitude. 1: Move towards what you are looking"
+
+// "Gentle mode": show no blood
+seta cl_gentle 0               "client side gentle mode, master switch for removing both gibs and messages"
+seta cl_gentle_gibs 0          "client side gentle mode (only replaces gibs); when set to 1, white smoke replaces gibs, when set to 2, colorful clouds replace gibs"
+seta cl_gentle_messages 0      "client side gentle mode (only replaces frag messages/centerprints)"
+seta cl_gentle_damage 0        "client side gentle mode (only replaces damage flash); when set to 1, a white flash replaces the blood image, when set to 2, a randomly colored flash is used instead"
+
+set cl_jetpack_attenuation 2 "jetpack sound attenuation"
+
+set cl_warpzone_usetrace 1 "do not touch"
+
+set cl_effects_lightningarc_simple 0
+set cl_effects_lightningarc_segmentlength 64
+set cl_effects_lightningarc_drift_start 0.45
+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_getpacks 1 "get update packs from update server"
+
+seta cl_loddistance1 1024
+seta cl_loddistance2 3072
+seta cl_playerdetailreduction 4        "the higher, the less detailed player models are displayed (LOD)"
+seta cl_modeldetailreduction 1 "the higher, the less detailed certain map models are displayed (LOD)"
+
+seta cl_casings_maxcount 100 "maximum amount of shell casings (must be at least 1)"
+seta cl_gibs_maxcount 100 "maximum amount of gibs (must be at least 1)"
+
+//cl_gunalign calculator
+seta menu_cl_gunalign 3 "Gun alignment; 1 = center (if allowed by g_shootfromclient) or right, 2 = center (if allowed by g_shootfromclient) or left, 3 = right only, 4 = left only"
+alias _gunalign_01 "cl_gunalign 1"
+alias _gunalign_02 "cl_gunalign 2"
+alias _gunalign_03 "cl_gunalign 3"
+alias _gunalign_04 "cl_gunalign 4"
+alias _gunalign_11 "cl_gunalign 2"
+alias _gunalign_12 "cl_gunalign 1"
+alias _gunalign_13 "cl_gunalign 4"
+alias _gunalign_14 "cl_gunalign 3"
+alias _gunalign_update "_gunalign_$v_flipped$menu_cl_gunalign"
+
+set _menu_alpha "" // will be set by menu QC to the current fading of the menu, can be used by CSQC to fade items
+set _menu_initialized 0 "is 0 on first menu loading, 1 later"
+
+seta cl_noantilag 0 "turn this on if you believe antilag is bad"
+
+set cl_accuracy_data_share 0 "1 share my weapon accuracy data statistics with other players, 0 keep my weapon accuracy data statistics hidden"
+set cl_accuracy_data_receive 0 "1 receive weapon accuracy data statistics at the end of the match"
+
+set developer_csqcentities 0 "csqc entity spam"
+
+seta cl_forceplayermodels 0 "make everyone look like your own model (requires server to have sv_defaultcharacter 0)"
+seta cl_forceplayercolors 0 "make enemies look like your own color (requires server to have sv_defaultcharacter 0); set it to 2 to enable it even in teamplay (only when there is exactly one enemy team)"
+seta cl_forcemyplayermodel "" "set to the model file name you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
+seta cl_forcemyplayerskin 0 "set to the skin number you want to show yourself as (does not affect how enemies look with cl_forceplayermodels)"
+seta cl_forcemyplayercolors 0 "set to the color value (encoding is same as _cl_color) for your own player model (ignored in teamplay; does not affect how enemies look with cl_forceplayermodels)"
+seta cl_movement_errorcompensation 1 "try to compensate for prediction errors and reduce perceived lag"
+seta cl_movement_intermissionrunning 0 "keep velocity after the match ends, players may appear to continue running while stationary"
+
+set debugdraw 0
+set debugdraw_filter ""
+set debugdraw_filterout ""
+set debugtrace 0
+
+// FIXME remove this when the engine feature FINALLY MAYBE works
+r_glsl_skeletal 0
+
+// animation tuning
+set cl_lerpanim_maxdelta_framegroups 0.05 // must be faster than fastest weapon refire
+set cl_lerpanim_maxdelta_server 0.1 // must be slower than slowest server controlled anim (e.g. animinfo stuff)
+
+// autodemo deleting
+seta cl_autodemo_delete_keeprecords 0 "when 1, records with a newly made race/cts demo are kept even if cl_autodemo_delete is used to delete demos"
+
+// freeze camera
+set cl_lockview 0 "when 1, the camera does not move any more"
+
+// we now use mastervolume
+volume 1
+
+// sucks less than the old one
+cl_decals_newsystem 1
+
+scr_conalpha 1
+scr_conalpha2factor 0.3
+scr_conalpha3factor 1
+scr_conalphafactor 0.8
+scr_conbrightness 0.35
+scr_conforcewhiledisconnected 1
+scr_conscroll2_x 0.11
+scr_conscroll2_y 0.2
+scr_conscroll3_x 0
+scr_conscroll3_y 0
+scr_conscroll_x -0.1
+scr_conscroll_y -0.3
+
+scr_conforcewhiledisconnected 0
+scr_infobar_height 12
+
+// DP cannot properly detect this, so rather turn off the detection
+r_texture_dds_load_alphamode 2
+r_texture_dds_swdecode 1 // SW decode to quarter res if we want to load DDS but don't support the extension for it
+r_texture_dds_load_logfailure 0 // this engine feature SUCKS
+set vid_netwmfullscreen 0 // doesn't support non-native res
+
+// particles optimization
+r_drawparticles_nearclip_min 8
+r_drawparticles_nearclip_max 16
+
+r_cullentities_trace 0
+
+// exact gloss looks better, e.g. on g-23
+r_shadow_glossexact 1
+r_shadow_glossintensity 1
+
+// use fake light if map has no lightmaps
+r_fakelight 1
+
+r_water_hideplayer 1 // hide your own feet/player model in refraction views, this way you don't see half of your body under water
+r_water_refractdistort 0.019
+
+set cl_rainsnow_maxdrawdist 2048
+
+// equalize looks better than fullbright
+r_equalize_entities_fullbright 1
+
+// safe font defaults
+r_font_hinting 1
+r_font_disable_freetype 0
+r_font_size_snapping 4
+
+// database management
+set cl_db_saveasdump 0 "write client.db in dump format (loads slower, easier to read/parse)"
+
+// uid2name
+seta cl_allow_uid2name -1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid2name (allows showing your name in race rankings for instance)"
+seta cl_allow_uidtracking 1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid tracking (allows associating your data with your player ID)"
+// FIXME set to -1 before release, once we have a dialog for this!
+
+// polygonoffset for submodel SUCKS SUCKS SUCKS (only a hack for quake1, we don't need that)
+r_polygonoffset_submodel_offset 0
+r_polygonoffset_submodel_factor 0
+// decals: need a higher polygonoffset than default to not compete with _decal surfaces too much
+r_polygonoffset_decals_offset -28
+r_polygonoffset_decals_factor 0
+
+// loading screen
+scr_loadingscreen_background 0
+scr_loadingscreen_barcolor "0 0.5 1"
+scr_loadingscreen_barheight 12
+scr_loadingscreen_count 1
+scr_loadingscreen_firstforstartup 1
+scr_loadingscreen_scale 999
+scr_loadingscreen_scale_base 1
+scr_loadingscreen_scale_limit 2
+
+// other config files
+exec effects-normal.cfg
+exec crosshairs.cfg
+exec gamemodes-client.cfg
+exec notifications.cfg
+
+seta cl_physics "default" "client selected physics set"
+
+// hud cvar descriptions and common settings
+exec _hud_common.cfg
+exec _hud_descriptions.cfg
+// exec the default skin config
+// please add any new cvars into the hud_save script in qcsrc/client/hud_config.qc for consistency
+exec hud_luma.cfg
+
+// enable menu syncing - must be after files that call menu_sync on startup - see alias menu_sync ""
+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 (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 (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"
+
+// Facility for config.cfg use ONLY.
+// Interpreted in post-config.cfg.
+seta menu_forced_saved_cvars "" "These cvars will always be saved, despite engine/Xonotic cvar saving status"
+set menu_reverted_nonsaved_cvars "" "These cvars are currently marked as saved in the flags, but have been reverted and won't stay saved. INTERNAL USE ONLY."
diff --git a/xonotic-common.cfg b/xonotic-common.cfg
new file mode 100644 (file)
index 0000000..078fbed
--- /dev/null
@@ -0,0 +1,147 @@
+// Xonotic version (formatted for machines)
+// used to determine if a client version is compatible
+// this doesn't have to be bumped with every release
+// bump when clients become incompatible or any other perfectly good reason
+// (e.g. game data incompatibility, engine version incompatibility, etc
+// note: this automatically filters the server browser, clients of the new
+// version won't see old servers, and clients of the old version won't see new
+// servers either
+//
+// e.g. Xonotic 1.5.1 RC1 will be 15101
+set g_xonoticversion git "Xonotic version (formatted for humans)"
+
+gameversion 802 // 0.8.2
+gameversion_min 0 // git builds see all versions
+gameversion_max 65535 // git builds see all versions
+
+// compatibility guideline:
+//   version a.b.c   = a0b0c
+//   gameversion_min = a0(b-1)00 // show servers of the previous "line"
+//   gameversion_max = a0(b+1)99 // show servers of the next "line"
+// so, for a given gameversion, _min and _max calculate as follows:
+//   gameversion_min = (gameversion / 100) * 100 - 100
+//   gameversion_max = (gameversion / 100) * 100 + 199
+
+seta g_configversion 0 "Configuration file version (used to upgrade settings) 0: first run, or previous start was <2.4.1  Later, it's overridden by config.cfg, version ranges are defined in config_update.cfg"
+
+exec xonotic-client.cfg
+exec xonotic-server.cfg
+
+set ekg 0      "Throw huge amounts of gibs"
+
+_cl_playermodel "models/player/erebus.iqm"
+
+locs_enable 0
+pausable 0
+set samelevel 0 "when 1, always play the same level over and over again"
+
+fs_empty_files_in_pack_mark_deletions 1 // makes patches able to delete files
+
+// singleplayer campaign
+set g_campaign 0
+set g_campaign_forceteam 0 "Forces the player to a given team in campaign mode, 1 = red, 2 = blue, 3 = yellow, 4 = pink"
+seta g_campaign_name "xonoticbeta"
+seta g_campaign_skill -1 // -2 easy -1 medium 0 hard
+
+alias singleplayer_start "g_campaign_index 0; set scmenu_campaign_goto 0"
+alias singleplayer_continue "set scmenu_campaign_goto -1"
+alias singleplayer_levellist "set scmenu_campaign_dump 1; togglemenu; wait; togglemenu"
+
+// campaign internal, set when loading a campaign map1G
+set _campaign_index ""
+set _campaign_name ""
+set _campaign_testrun 0 "To verify the campaign file, set this to 1, then start the first campaign level from the menu. If you end up in the menu again, it's good, if you get a QC crash, it's bad."
+
+// used by both server and menu to maintain the available list of maps
+seta g_maplist "" "the list of maps to be cycled among (is autogenerated if empty)"
+
+// we must change its default from 1.0 to 1 to be consistent with menuqc
+set slowmo 1
+
+// ticrate
+//sys_ticrate 0.0166667 // 60fps. This would be ideal, but kills home routers.
+sys_ticrate 0.0333333 // Use 30fps instead.
+
+// Audio track names (for old-style "cd loop NUMBER" usage)
+set _cdtrack_first "1"
+alias _cdtrack_0 "g_cdtracks_remaplist \"$g_cdtracks_remaplist $1\""
+alias _cdtrack_1 "g_cdtracks_remaplist \"$1\"; set _cdtrack_first 0"
+alias _cdtrack "_cdtrack_$_cdtrack_first $2"
+set g_cdtracks_remaplist ""
+exec cdtracks.cfg
+unset _cdtrack_first
+unalias _cdtrack_0
+unalias _cdtrack_1
+unalias _cdtrack
+
+cd remap $g_cdtracks_remaplist
+set sv_intermission_cdtrack ""
+
+set g_cdtracks_dontusebydefault "rising-of-the-phoenix"
+seta menu_cdtrack "rising-of-the-phoenix"
+
+// these entities are not referenced by anything directly, they just represent
+// teams and are found by find() when needed
+prvm_leaktest_ignore_classnames "ctf_team dom_team tdm_team"
+prvm_backtraceforwarnings 1
+
+set _urllib_nextslot 0 "temp variable"
+
+set g_debug_defaultsounds 0 "always use default sounds"
+
+// define some engine cvars that we need even on dedicated server
+set r_showbboxes 0
+
+// support Q1BSP maps
+mod_q1bsp_polygoncollisions 1
+
+// match q3map2
+mod_obj_orientation 0
+
+// UTF-8
+utf8_enable 1
+
+// this is mainly for _decal entities (their shaders should use "polygonoffset" shader parameter) - this is "good enough" as it seems, but smaller than the decals one so these don't zfight decals
+mod_q3shader_default_polygonoffset -14
+mod_q3shader_default_polygonfactor 0
+
+// random charge stuff :P
+set g_weapon_charge_colormod_hdrmultiplier 4 "how much to multiply the colors by in the colormod vector"
+set g_weapon_charge_colormod_red_half 0
+set g_weapon_charge_colormod_green_half 0.5
+set g_weapon_charge_colormod_blue_half 1
+set g_weapon_charge_colormod_red_full 1
+set g_weapon_charge_colormod_green_full -0.5
+set g_weapon_charge_colormod_blue_full -1
+
+// session locking
+locksession 1
+
+// create this cvar in case the engine did not
+set snd_soundradius 1200
+set snd_softclip 1
+set snd_maxchannelvolume 0
+set snd_streaming_length 2
+seta menu_snd_sliderscale 2 "0: decibels; 1: linear percent; 2: 0..10 scale; 3: slider size percent"
+seta menu_snd_attenuation_method 1 "Use exponential instead of linear falloff for sound attenuation"
+alias snd_attenuation_method_0 "set menu_snd_attenuation_method 0; set snd_soundradius 1200; set snd_attenuation_exponent 1; set snd_attenuation_decibel 0" // Quake default
+alias snd_attenuation_method_1 "set menu_snd_attenuation_method 1; set snd_soundradius 2400; set snd_attenuation_exponent 4; set snd_attenuation_decibel 0" // nice approximation for method 2
+alias snd_attenuation_method_2 "set menu_snd_attenuation_method 2; set snd_soundradius 1200; set snd_attenuation_exponent 0; set snd_attenuation_decibel 10" // warning: plays sounds within up to 6000qu
+snd_attenuation_method_1
+
+// declare the channels we use
+seta snd_channel8volume 1 "QuakeC controlled background music volume"
+seta snd_channel9volume 1 "QuakeC controlled ambient sound volume"
+
+// sound randomization
+snd_identicalsoundrandomization_time -0.1
+snd_identicalsoundrandomization_tics    1
+
+// load console command aliases and settings
+exec commands.cfg
+
+// ... and now that everything is configured/aliased, we can do some things:
+
+// Change g_start_delay based upon if the server is local or not.
+if_client set g_start_delay 0  "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
+if_dedicated set g_start_delay 15      "delay before the game starts, so everyone can join; recommended to set this to like 15 on a public server"
diff --git a/xonotic-server.cfg b/xonotic-server.cfg
new file mode 100644 (file)
index 0000000..21a94e3
--- /dev/null
@@ -0,0 +1,561 @@
+// this should reset most cvars and aliases affecting gameplay to their defaults
+// note that it doesn't reset all server cvars,
+// some are shared with the client and so are left in xonotic-common.cfg
+
+
+// taunts and voices
+set sv_taunt 1 "allow taunts on the server"
+set sv_autotaunt 1 "allow autotaunts on the server"
+
+// server settings
+hostname "Xonotic $g_xonoticversion Server"
+set sv_mapchange_delay 5
+set minplayers 0 "number of players playing at the same time (if not enough real players are there the remaining slots are filled with bots)"
+
+// restart server if all players hit "ready"-button
+set sv_ready_restart 0 "allow a map to be restarted once all players pressed the \"ready\" button"
+set sv_ready_restart_after_countdown 0 "reset players and map items after the countdown ended, instead of at the beginning of the countdown"
+set sv_ready_restart_repeatable 0      "allows the players to restart the game as often as needed"
+
+//nifreks lockonrestart feature, used in team-based game modes, if set to 1 and all players readied up no other player can then join the game anymore, useful to block spectators from joining
+set teamplay_lockonrestart 0 "lock teams once all players readied up and the game restarted (no new players can join after restart unless using the server-command unlockteams)"
+
+set g_maxplayers 0     "maximum number of players allowed to play at the same time, set to 0 to allow all players to join the game"
+set g_maxplayers_spectator_blocktime 5 "if the players voted for the \"nospectators\" command, this setting defines the number of seconds a observer/spectator has time to join the game before he gets kicked"
+
+// tournament mod
+set g_warmup 0 "split the game into a warmup- and match-stage"
+set g_warmup_limit 0   "limit warmup-stage to this time (in seconds); if set to -1 the warmup-stage is not affected by any timelimit, if set to 0 the usual timelimit also affects warmup-stage"
+set g_warmup_allow_timeout 0   "allow calling timeouts in the warmup-stage (if sv_timeout is set to 1)"
+set g_warmup_allguns 1 "provide more weapons on start while in warmup: 0 = normal start weapons, 1 = all guns available on the map, 2 = all normal weapons"
+set g_warmup_majority_factor 0.8 "minimum percentage of players ready needed for warmup to end"
+
+set g_chat_nospectators 0      "if 0 spec/observer chat is always visible to the player, if 1 it is never visible to players, if 2 it is only visible to players during warmup stage"
+set sv_vote_nospectators 0     "only players can call a vote (thus spectators and observers can't call a vote): 0 = all people can vote, 1 = spectators can vote in warmup stage, 2 = only players can vote (no exceptions)."
+
+alias g_tourney "g_tourney_$1"
+alias g_tourney_1 "g_warmup 1; g_chat_nospectators 2; sv_vote_nospectators 1"
+alias g_tourney_0 "g_warmup 0; g_chat_nospectators 0; sv_vote_nospectators 0"
+
+set sv_timeout 0       "allow a player to call a timeout, this will pause the game for some time"
+set sv_timeout_length 120      "how long the game will be paused at max, in seconds"
+set sv_timeout_number 2        "how many timeouts one player is allowed to call (gets reset after a restart)"
+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 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"
+set g_telefrags_avoid 1 "when teleporters have a random destination, avoid teleporting to locations where a telefrag would happen"
+set g_teleport_maxspeed 0 "maximum speed that a player can keep when going through a teleporter (if a misc_teleporter_dest also has a cap the smallest one of these will be used), 0 = don't limit, -1 = keep no speed"
+
+set g_respawn_ghosts 1 "if 1 dead bodies become ghosts and float away when the player respawns"
+set g_respawn_ghosts_speed 5 "the speed with which respawn ghosts float and rotate"
+set g_respawn_ghosts_maxtime 6 "maximum amount of time a respawn ghost can last, minimum time is half this value. 0 disables and ghosts fade when the body would"
+
+set sv_gibhealth 100 "Minus health a dead body must have in order to get gibbed"
+
+// use default physics
+set sv_friction_on_land 0
+set sv_friction_slick 0.5
+
+set sv_slick_applygravity 0
+
+set sv_aircontrol_backwards 0 "apply forward aircontrol options to backward movement"
+set sv_aircontrol_sidewards 0 "apply forward aircontrol options to sideward movement"
+
+set sv_player_viewoffset "0 0 35" "view offset of the player model"
+set sv_player_mins "-16 -16 -24" "playermodel mins"
+set sv_player_maxs "16 16 45" "playermodel maxs"
+set sv_player_crouch_viewoffset "0 0 20" "view offset of the player model when crouched"
+set sv_player_crouch_mins "-16 -16 -24" "mins of a crouched playermodel"
+set sv_player_crouch_maxs "16 16 25" "maxs of a crouched playermodel"
+
+set sv_doublejump 0 "allow Quake 2-style double jumps"
+set sv_jumpspeedcap_min "" "lower bound on the baseline velocity of a jump; final velocity will be >= (jumpheight * min + jumpheight)"
+set sv_jumpspeedcap_max "" "upper bound on the baseline velocity of a jump; final velocity will be <= (jumpheight * max + jumpheight)"
+set sv_jumpspeedcap_max_disable_on_ramps 0 "disable upper baseline velocity bound on ramps to preserve the old rampjump style"
+set sv_track_canjump 0 "track if the player released the jump key between 2 jumps to decide if they are able to jump or not"
+set sv_jumpvelocity_crouch 0 "jump height while crouching, set to 0 to use regular jump height"
+
+set sv_precacheplayermodels 1
+set sv_precacheweapons 0
+set sv_precacheitems 0
+set sv_spectator_speed_multiplier 1.5
+set sv_spectator_speed_multiplier_min 1
+set sv_spectator_speed_multiplier_max 5
+set sv_spectate 1 "if set to 1, new clients are allowed to spectate or observe the game, if set to 0 joining clients spawn as players immediately (no spectating)"
+set sv_defaultcharacter 0 "master switch, if set to 1 the further configuration for replacing all player models, skins and colors is taken from the sv_defaultplayermodel, sv_defaultplayerskin and sv_defaultplayercolors variables"
+set sv_defaultcharacterskin 0 "if set to 1 the further configuration for replacing all skins is taken from the sv_defaultplayerskin variables"
+set sv_defaultplayermodel "models/player/erebus.iqm" "default model selection, only works if sv_defaultcharacter is set to 1; you may append a :<skinnumber> suffix to model names; you can specify multiple, separated by space, and a random one will be chosen"
+set sv_defaultplayerskin 0 "each model has 1 or more skins (combination of model and skin = character), set which skin of the model you wish the default character to have, only works if sv_defaultcharacter is set to 1; can be overridden by :<skinnumber> suffix in sv_defaultplayermodel"
+set sv_defaultplayermodel_red ""       "\"\" means see sv_defaultplayermodel"
+set sv_defaultplayerskin_red 0
+set sv_defaultplayermodel_blue "" "\"\" means see sv_defaultplayermodel"
+set sv_defaultplayerskin_blue 0
+set sv_defaultplayermodel_yellow "" "\"\" means see sv_defaultplayermodel"
+set sv_defaultplayerskin_yellow 0
+set sv_defaultplayermodel_pink "" "\"\" means see sv_defaultplayermodel"
+set sv_defaultplayerskin_pink 0
+set sv_defaultplayercolors ""  "set to 16*shirt+pants to force a color, note: it does NOT depend on defaultcharacter! Set to \"\" to disable"
+set sv_autoscreenshot 0 "if set to 1, the server forces all clients to create a local screenshot once the map ended"
+net_messagetimeout 30
+net_connecttimeout 30
+sv_jumpstep 1 // step up stairs while jumping, makes it easier to reach ledges
+
+set sv_shownames_cull_distance 2500 "distance after which to not send origin/health/armor of another player"
+
+set bot_config_file bots.txt "Name and path of the bot configuration file"
+set bot_number 0       "Minimum number of bots"
+set bot_usemodelnames 0        "Use player model names for bot names"
+set bot_nofire 0       "When set, bots never fire. Mainly for testing in g_waypointeditor mode"
+set bot_prefix [BOT]   "Prefix in front of the bot names"
+set bot_suffix ""      "Suffix behind the bot names"
+set skill_auto 0       "when 1, \"skill\" gets adjusted to match the best player on the map"
+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"
+set bot_ai_strategyinterval_movingtarget 5.5 "How often a new objective is chosen when current objective can move"
+set bot_ai_enemydetectioninterval 2 "How often bots pick a new target"
+set bot_ai_enemydetectionradius 10000 "How far bots can see enemies"
+set bot_ai_dodgeupdateinterval 0.2 "How often scan for items to dodge. Currently not in use."
+set bot_ai_chooseweaponinterval 0.5 "How often the best weapon according to the situation will be chosen"
+set bot_ai_dangerdetectioninterval 0.25 "How often scan for waypoints with dangers near"
+set bot_ai_dangerdetectionupdates 64 "How many waypoints will be considered for danger detection"
+set bot_ai_aimskill_blendrate 2        "How much correction will be applied to the aiming angle"
+set bot_ai_aimskill_fixedrate 15
+set bot_ai_aimskill_firetolerance_distdegrees 100
+set bot_ai_aimskill_firetolerance_mindegrees 2 "Minimum angle tolerance. Used on large distances"
+set bot_ai_aimskill_firetolerance_maxdegrees 60 "Maximum firing angle. Used on close range"
+set bot_ai_aimskill_mouse 1 "How much of the aiming filters are applied"
+set bot_ai_keyboard_distance 250 "Keyboard emulation is disabled after this distance to the goal"
+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 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"
+set bot_ai_ignoregoal_timeout 3        "Ignore goals making bots to get stuck in front of a wall for N seconds"
+set bot_ai_bunnyhop_skilloffset 7      "Bots with skill equal or greater than this value will perform the  \"bunnyhop\" technique"
+set bot_ai_bunnyhop_startdistance 200 "Run to goals located further than this distance"
+set bot_ai_bunnyhop_stopdistance 300 "Stop jumping after reaching this distance to the goal"
+set bot_ai_bunnyhop_firstjumpdelay 0.2 "Start running to the goal only if it was seen for more than N seconds"
+set bot_god 0 "god mode for bots"
+set bot_ai_navigation_jetpack 0 "Enable bots to navigate maps using the jetpack"
+set bot_ai_navigation_jetpack_mindistance 3500 "Bots will try fly to objects located farther than this distance"
+// Better don't touch these, there are hard to tweak!
+set bot_ai_aimskill_order_mix_1st 0.01 "Amount of the 1st filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_2nd 0.1 "Amount of the 2nd filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_3th 0.01 "Amount of the 3th filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_4th 0.05 "Amount of the 4th filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_mix_5th 0.01 "Amount of the 5th filter output to apply to the aiming angle"
+set bot_ai_aimskill_order_filter_1st 0.4 "Position filter"
+set bot_ai_aimskill_order_filter_2nd 0.4 "Movement filter"
+set bot_ai_aimskill_order_filter_3th 0.2 "Acceleration filter"
+set bot_ai_aimskill_order_filter_4th 0.4 "Position prediction filter. Used rarely"
+set bot_ai_aimskill_order_filter_5th 0.5 "Movement prediction filter. Used rarely"
+set bot_ai_timeitems 1 "allow skilled bots to run to important items a little time before respawning"
+set bot_ai_timeitems_minrespawndelay 25 "bots run to items with this minimum respawn delay before respawning"
+
+// waypoint editor enable
+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)"
+set bot_ignore_bots 0  "When set, bots don't shoot at other bots"
+set bot_join_empty 0   "When set, bots also play if no player has joined the server"
+set bot_vs_human 0     "Bots and humans play in different teams when set. positive values to make an all-bot blue team, set to negative values to make an all-bot red team, the absolute value is the ratio bots vs humans (1 for equal count). Changes will be correctly applied only from the next game"
+
+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)"
+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"
+set g_shootfromfixedorigin "" "if set to a string like 0 y z, the gun is moved to the given y and z coordinates. If set to a string like x y z, the whole shot origin is used"
+set g_pinata 0 "if set to 1 you will not only drop your current weapon when you are killed, but you will drop all weapons that you possessed"
+set g_weapon_stay 0 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
+set g_weapon_throwable 1 "if set to 1, weapons can be dropped"
+set g_powerups -1 "if set to 0 the strength and shield (invincibility) will not spawn on the map, if 1 they will spawn in all game modes, -1 is game mode default"
+set g_use_ammunition 1 "if set to 0 all weapons have unlimited ammunition"
+set g_pickup_items -1 "if set to 0 all items (health, armor, ammo, weapons...) are removed from the map, if 1 they are forced to spawn"
+set g_pickup_respawntime_scaling_reciprocal 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*"
+set g_pickup_respawntime_scaling_offset 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening"
+set g_pickup_respawntime_scaling_linear 1 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `linear` can be used to simply scale the respawn time linearly"
+set g_weaponarena "0"  "put in a list of weapons to enable a weapon arena mode, or try \"all\" or \"most\""
+set g_weaponarena_random "0"   "if set to a number, only that weapon count is given on every spawn (randomly)"
+set g_weaponarena_random_with_blaster "1"      "additionally, always provide the blaster in random weapon arena games"
+set g_spawnpoints_auto_move_out_of_solid 0 "if set to 1 you will see a warning if a spawn point was placed inside a solid"
+set g_forced_respawn 0 "if set to 1 and a player died, that player gets automatically respawned once <g_respawn_delay> seconds are over"
+set g_fullbrightplayers 0 "brightens up player models (note that the color, skin or model of the players does not change!)"
+set g_fullbrightitems 0 "brightens up items"
+set g_nodepthtestplayers 0 "disables depth testing on players"
+set g_nodepthtestitems 0 "disables depth testing on items"
+set g_casings 2 "specifies which casings (0: none, 1: only shotgun casings, 2: shotgun and machine gun casings) are sent to the client"
+set g_norecoil 0 "if set to 1 shooting weapons won't make you crosshair to move upwards (recoil)"
+set g_maplist_mostrecent "" "contains the name of the maps that were most recently played"
+set g_maplist_mostrecent_count 3       "number of most recent maps that are blocked from being played again"
+set g_maplist_index 0  "this is used internally for saving position in maplist cycle"
+set g_maplist_selectrandom 0   "if 1, a random map will be chosen as next map - DEPRECATED in favor of g_maplist_shuffle"
+set g_maplist_shuffle 1        "new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list"
+set g_maplist_check_waypoints 0        "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
+
+set g_items_mindist 4000 "starting distance for the fading of items"
+set g_items_maxdist 4500 "maximum distance at which an item can be viewed, after which it will be invisible"
+
+set g_grab_range 200 "distance at which dragable objects can be grabbed"
+
+set g_cloaked 0 "display all players mostly invisible"
+set g_player_alpha 1
+set g_player_brightness 0      "set to 2 for brighter players"
+set g_balance_cloaked_alpha 0.25
+
+set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"
+set g_botclip_collisions 1 "0 = disable collision testing against botclips, might be useful on some defrag maps"
+
+set g_spawn_alloweffects 1 "allow clients to enable spawn point and event effects such as particles and sounds, see cl_spawn_ cvars for more info"
+set g_spawn_furthest 0.5 "this amount of the spawns shall be far away from any players"
+set g_spawn_useallspawns 0 "use all spawns, e.g. also team spawns in non-teamplay, and all spawns, even enemy spawns, in teamplay"
+// respawn delay
+set g_respawn_delay_small 2 "small game number of seconds you have to wait before you can respawn again"
+set g_respawn_delay_small_count 0 "Player count per team for g_respawn_delay_small. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
+set g_respawn_delay_large 2 "large game number of seconds you have to wait before you can respawn again"
+set g_respawn_delay_large_count 8 "Player count per team for g_respawn_delay_large. <=0 values mean the minimum amount of players to have gameplay (typically 2 in FFA, 1 in teamplay)."
+set g_respawn_delay_max 5 "number of seconds you can wait before you're forced to respawn (only effective with g_forced_respawn 1)"
+set g_respawn_delay_forced 0 "enforce regular respawn delay (prevent gamemode specific respawn delays)"
+set g_respawn_waves 0 "respawn in waves (every n seconds), intended to decrease overwhelming base attacks"
+
+// overtime
+set timelimit_overtime 2 "duration in minutes of one added overtime, added to the timelimit"
+set timelimit_overtimes 0 "how many overtimes to add at max"
+set timelimit_suddendeath 5 "number of minutes suddendeath mode lasts after all overtimes were added and still no winner was found"
+
+// common team values
+set g_tdm 0 "Team Deathmatch: the team who kills their opponents most often wins"
+set g_tdm_on_dm_maps 0 "when this is set, all DM maps automatically support TDM"
+
+set teamplay_mode 4 "default teamplay setting in team games. 1 = no friendly fire, self damage. 2 = friendly fire and self damage enabled. 3 = no friendly fire, but self damage enabled. 4 = obey the cvars g_mirrordamage*, g_friendlyfire* and g_teamdamage*"
+set g_mirrordamage 0.7              "for teamplay_mode 4: mirror damage factor"
+set g_mirrordamage_virtual 1        "for teamplay_mode 4: do not actually apply mirror damage, just show graphics effect for it"
+set g_mirrordamage_onlyweapons 0    "for teamplay_mode 4: only apply mirror damage if the attack was from a weapon"
+set g_friendlyfire 0.5              "for teamplay_mode 4: friendly fire factor"
+set g_friendlyfire_virtual 1        "for teamplay_mode 4: do not actually apply friendly fire, just show graphics effect for it"
+set g_friendlyfire_virtual_force 1  "for teamplay_mode 4: apply force even though damage was made virtual only"
+set g_teamdamage_threshold 40       "for teamplay_mode 4: threshold over which to apply mirror damage"
+set g_teamdamage_resetspeed 20      "for teamplay_mode 4: how fast player's teamdamage count decreases"
+
+set g_balance_teams 1  "automatically balance out players entering instead of asking them for their preferred team"
+set g_balance_teams_prevent_imbalance  1       "prevent players from changing to larger teams"
+set g_balance_teams_scorefactor 0.25 "at the end of the game, take score into account instead of team size by this amount (beware: values over 0.5 mean that a x:0 score imbalance will cause ALL new players to prefer the losing team at the end, despite numbers)"
+set g_changeteam_banned 0      "not allowed to change team"
+set g_changeteam_fragtransfer 0        "% of frags you get to keep when you change teams (rounded down)"
+
+set sv_teamnagger 1 "enable a nag message when the teams are unbalanced"
+
+set g_bloodloss 0   "amount of health below which blood loss occurs"
+
+set g_footsteps 1      "serverside footstep sounds"
+
+set g_throughfloor_debug 0 "enable debugging messages for throughfloor calculations"
+set g_throughfloor_damage_max_stddev 2 "Maximum standard deviation for splash damage"
+set g_throughfloor_force_max_stddev 10 "Maximum standard deviation for splash force"
+set g_throughfloor_min_steps_player 1 "Minimum number of steps for splash damage"
+set g_throughfloor_min_steps_other 1 "Minimum number of steps for splash damage"
+set g_throughfloor_max_steps_player 100 "Maximum number of steps for splash damage"
+set g_throughfloor_max_steps_other 10 "Maximum number of steps for splash damage"
+// note: for damage X, 0.25 * ((1-g_throughfloor_damage)*X / g_throughfloor_damage_max_stddev)^2 steps are used
+// for these numbers:
+//   damage  25: 3
+//   damage  60: 15
+//   damage  80: 25
+//   damage 200: 157
+//   force  250: 10
+//   force  300: 15
+//   force  600: 57
+
+sv_maxvelocity 1000000000
+sv_sound_land ""
+sv_sound_watersplash ""
+
+// startmap_dm is used when running with the -listen or -dedicated commandline options
+set serverconfig server.cfg
+alias loadconfig "cvar_resettodefaults_saveonly; exec ${* !}"
+set _sv_init 0
+alias startmap_dm "set _sv_init 0; map _init/_init; exec $serverconfig; set _sv_init 1"
+
+// score log
+set sv_logscores_console 0     "print scores to server console"
+set sv_logscores_file 0        "print scores to file"
+set sv_logscores_filename scores.log   "filename"
+set sv_logscores_bots 0        "exclude bots by default"
+
+// spam (frag/capture) log
+set sv_eventlog 0      "the master switch for efficiency reasons"
+set sv_eventlog_console 1
+set sv_eventlog_files 0
+set sv_eventlog_files_timestamps 1
+set sv_eventlog_files_counter 0
+set sv_eventlog_files_nameprefix xonotic
+set sv_eventlog_files_namesuffix .log
+
+set nextmap "" "override the maplist when switching to the next map"
+set lastlevel ""
+set quit_when_empty 0  "set to 1, then the server exits when the next level would start but is empty"
+set quit_and_redirect ""       "set to an IP to redirect all players at the end of the match to another server. Set to \"self\" to let all players reconnect at the end of the match (use it to make seamless engine updates)"
+set quit_and_redirect_timer 1.5 "set to number of seconds after quit before performing the connect operation of quit_and_redirect"
+
+// Green's fullbright skins, updated by Samual
+alias sv_fbskin_unique "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors \"\""
+alias sv_fbskin_green "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 51"
+alias sv_fbskin_red "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 68"
+alias sv_fbskin_orange "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 238"
+alias sv_fbskin_rainbow "sv_defaultcharacter 1; sv_defaultplayermodel models/player/megaerebus.iqm; sv_defaultplayerskin 1; sv_defaultplayercolors 95"
+
+alias sv_fbskin_off "sv_defaultcharacter 0; sv_defaultplayerskin 0; sv_defaultplayercolors \"\""
+
+set sv_servermodelsonly 1
+
+sv_curl_defaulturl "http://www.xonotic.org/contentdownload/getmap.php?file="
+set sv_curl_serverpackages_auto 1 "automatically add packs with *.serverpackage files to sv_curl_serverpackages"
+
+set sv_motd ""
+
+set g_waypoints_for_items 0    "make waypoints out of items, values: 0 = never, 1 = unless the mapper prevents it by worldspawn.spawnflags & 1, 2 = always"
+
+set g_maplist_votable 6 "number of maps that are shown in the map voting at the end of a match"
+set g_maplist_votable_keeptwotime 15 "show only 2 options after this amount of time during map vote screen"
+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 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 1 "show a vote screen for gametypes before map vote screen"
+set sv_vote_gametype_keeptwotime 10 "show only 2 options after this amount of time during gametype vote screen"
+set sv_vote_gametype_options "dm tdm ctf" "Keep the identifiers short, otherwise you'll run into issues with too long alias names (max is 31 characters) when using sv_vote_gametype_hook_*"
+set sv_vote_gametype_timeout 20
+set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
+
+set g_chat_flood_spl 3 "normal chat: seconds between lines to not count as flooding"
+set g_chat_flood_lmax 2        "normal chat: maximum number of lines per chat message at once"
+set g_chat_flood_burst 2       "normal chat: allow bursts of so many chat lines"
+set g_chat_flood_spl_team 1    "team chat: seconds between lines to not count as flooding"
+set g_chat_flood_lmax_team 2   "team chat: maximum number of lines per chat message at once"
+set g_chat_flood_burst_team 2  "team chat: allow bursts of so many chat lines"
+set g_chat_flood_spl_tell 1    "private chat: seconds between lines to not count as flooding"
+set g_chat_flood_lmax_tell 2   "private chat: maximum number of lines per chat message at once"
+set g_chat_flood_burst_tell 2  "private chat: allow bursts of so many chat lines"
+set g_chat_flood_notify_flooder 1      "when 0, the flooder still can see his own message"
+set g_chat_teamcolors 0        "colorize nicknames in team color for chat"
+set g_chat_tellprivacy 1 "when disabled, tell messages are also sent to the server console log... otherwise they're kept private between players."
+set g_nick_flood_timeout 120 "time after which nick flood protection resets (set to 0 to disable nick flood checking)"
+set g_nick_flood_penalty 0.5 "duration of the nick flood penalty"
+set g_nick_flood_penalty_yellow 3 "number of changes to allow before warning and movement blocking"
+set g_nick_flood_penalty_red 30 "number of changes to allow before totally disorienting the player"
+
+set sv_waypointsprite_deployed_lifetime 10
+set sv_waypointsprite_deadlifetime 1
+set sv_waypointsprite_limitedrange 5120
+
+set sv_itemstime 1 "enable networking of time left until respawn for items such as mega health/armor and powerups"
+
+set g_ban_default_bantime 5400 "90 minutes"
+set g_ban_default_masksize 3   "masksize 0 means banning by UID only, 1 means banning by /8 (IPv6: /32) network, 2 means banning by /16 (IPv6: /48) network, 3 means banning by /24 (IPv6: /56) network, 4 means banning by single IP (IPv6: /64 network)"
+set g_banned_list ""   "format: IP remainingtime IP remainingtime ..."
+set g_banned_list_idmode "1"   "when set, the IP banning system always uses the ID over the IP address (so a user in a banned IP range can connect if they have a valid signed ID)"
+
+// useful vote aliases
+set timelimit_increment 5
+set timelimit_decrement 5
+set timelimit_min 5
+set timelimit_max 60
+
+sv_gameplayfix_delayprojectiles 0
+sv_gameplayfix_q2airaccelerate 1
+sv_gameplayfix_stepmultipletimes 1
+
+// delay for "kill" to prevent abuse
+set g_balance_kill_delay 2
+set g_balance_kill_antispam 5
+
+// this feature is currently buggy in the engine (it appears to PREVENT any dropping in lots of maps, leading to weirdly aligned entities, and in some cases even CAUSES them to drop through solid, like in facing worlds nex)
+sv_gameplayfix_droptofloorstartsolid 0
+
+set sv_foginterval 1 "force enable fog in regular intervals"
+
+set sv_maxidle 0 "kick players idle for more than this amount of time in seconds"
+set sv_maxidle_spectatorsareidle 0 "when sv_maxidle is not 0, assume spectators are idle too"
+set sv_maxidle_slots 0 "when not 0, only kick idlers when this many or less player slots are available"
+set sv_maxidle_slots_countbots 1 "count bots as player slots"
+
+sv_allowdownloads_inarchive 1 // for csprogs.dat
+sv_allowdownloads 0 // download protocol is evil
+
+set g_jump_grunt 0     "Do you make a grunting noise every time you jump? Is it the same grunting noise every time?"
+
+set g_maplist_allow_hidden 0           "allow hidden maps to be, e.g., voted for and in the maplist"
+set g_maplist_allow_frustrating 0      "allow impossible maps to be, e.g., voted for and in the maplist (if set to 2, ONLY impossible maps are allowed)"
+
+set sv_clones 0        "number of clones a player may make (reset by the \"kill\" command)"
+
+set g_ban_sync_uri ""  "sync using this ban list provider (empty string to disable)"
+set g_ban_sync_interval 5      "sync every 5 minutes"
+set g_ban_sync_trusted_servers ""      "request ban lists from these xonotic servers (do not include your own server there, or unbanning may fail)"
+set g_ban_sync_timeout 45      "time out in seconds for the ban sync requests"
+set g_ban_sync_trusted_servers_verify 0        "when set to 1, additional bans sent by the servers are ignored, and only bans for the requested IP are used"
+
+set g_showweaponspawns 1 "1: display waypoints for weapon spawns found on the map when a weapon key is pressed and the weapon is not owned; 2: for dropped weapons too; 3: for all the weapons sharing the same impulse"
+
+// ballistics use physical units, but qu based
+//   Quake-Newton: 1 qN  = 1 qu * 1 g / 1 s^2
+//   Quake-Joule:  1 qJ  = 1 qN * 1 qu
+//   Quake-Pascal: 1 qPa = 1 qN / 1 qu^2
+
+set g_ballistics_mindistance 2 // enable ballistics starting from 2 qu
+set g_ballistics_density_player 0.50 // players are 2x as easy to pass as walls
+set g_ballistics_density_corpse 0.10 // corpses are 10x as easy to pass as walls
+set g_ballistics_penetrate_clips 0 "allow ballistics to pass through weapon clips"
+
+sv_status_show_qcstatus 1      "Xonotic uses this field instead of frags"
+set g_full_getstatus_responses 0       "this currently breaks qstat"
+
+// "Gentle mode": show no blood
+set sv_gentle 0                "force gentle mode for everyone, also remove references to acts of killing from the messages"
+
+set g_jetpack 0 "Jetpack mutator"
+
+set g_hitplots 0 "when set to 1, hitplots are stored by the server to provide a means of proving that a triggerbot was used"
+set g_hitplots_individuals "" "the individuals, by IP, that should have their hitplots recorded"
+
+set bot_navigation_ignoreplayers 0 // FIXME remove this once the issue is solved
+set bot_sound_monopoly 0 "when enabled, only bots can make any noise"
+
+set g_mapinfo_settemp_acl "+*" "ACL for mapinfo setting cvars"
+
+set g_triggerimpulse_accel_power 1 "trigger_impulse accelerator power (applied BEFORE the multiplier)"
+set g_triggerimpulse_accel_multiplier 1 "trigger_impulse accelerator multiplier (applied AFTER the power)"
+set g_triggerimpulse_directional_multiplier 1 "trigger_impulse directional field multiplier"
+set g_triggerimpulse_radial_multiplier 1 "trigger_impulse radial field multiplier"
+
+set sv_weaponstats_file "" "when set to a file name, per-weapon stats get written to that file"
+
+set rescan_pending 0 "set to 1 to schedule a fs_rescan at the end of this match"
+
+set g_mapinfo_allow_unsupported_modes_and_let_stuff_break "0" "set to 1 to be able to force game types using g_ cvars even if the map does not support them"
+set g_mutatormsg "" "mutator message"
+
+set spawn_debug 0 "use all spawns one by one, then abort, to verify all spawnpoints"
+set loddebug 0 "force this LOD level"
+set speedmeter 0 "print landing speeds"
+set waypoint_benchmark 0 "quit after waypoint loading to benchmark bot navigation code"
+set g_debug_bot_commands 0 "print scripted bot commands before executing"
+
+// weapon accuracy stats
+set sv_accuracy_data_share 1 "1 send weapon accuracy data statistics to spectating clients, depends on cl_accuracy_data_share"
+set sv_accuracy_data_send 1 "1 send weapon accuracy data statistics and improved score info to all the clients at the end of the match, depends on cl_accuracy_data_receive, 0 send the current 'player has won' to all the clients"
+
+// debug
+set _independent_players 0 "DO NOT TOUCH"
+set _notarget 0 "NO, REALLY, DON'T"
+
+set debug_text_3d_default_align 0 "Default text alignment for debug_text_3d()"
+set debug_text_3d_default_duration 10 "Default duration for debug_text_3d()"
+set debug_text_3d_default_velocity "0 -10 0" "Default velocity for debug_text_3d() in screen coords (X and Y from top left)"
+
+// otherwise, antilag breaks
+sv_gameplayfix_consistentplayerprethink 1
+
+// improve some minor details
+sv_gameplayfix_gravityunaffectedbyticrate 1
+sv_gameplayfix_nogravityonground 1
+
+set sv_q3acompat_machineshotgunswap 0 "shorthand for swapping machinegun and shotgun (for Q3A map compatibility in mapinfo files)"
+
+set g_movement_highspeed 1 "movement speed modification factor (only changes movement when above maxspeed)"
+
+set g_maxspeed 0 "player speed limit, faster players are killed (0 for unlimited speed)"
+
+// sv_cullentities_trace is 1, so the client doesn't have to
+sv_cullentities_trace 1
+
+// less "lagging" of other players, but also less PL tolerant... let's try this
+sv_clmovement_inputtimeout 0.066 // slightly less than 2 frames, so only one frame can be compensated
+
+// strength sound settings
+set sv_strengthsound_antispam_time 0.1 "minimum distance of strength sounds"
+set sv_strengthsound_antispam_refire_threshold 0.04 "apply minimum distance only if refire of the gun is smaller than this"
+
+// database management
+set sv_db_saveasdump 0 "write server.db in dump format (loads slower, easier to read/parse)"
+
+// allow fullbright
+set sv_allow_fullbright 1 "when set, clients may use r_fullbright on this server without getting a night vision effect overlay"
+
+// auto-teams (team selection by player ID)
+// any player not listed is forced to spectate
+set g_forced_team_red "" "list of player IDs for red team"
+set g_forced_team_blue "" "list of player IDs for blue team"
+set g_forced_team_yellow "" "list of player IDs for yellow team"
+set g_forced_team_pink "" "list of player IDs for pink team"
+set g_forced_team_otherwise "default" "action if a non listed player joins (can be default for default action, spectate for forcing to spectate, or red, blue, yellow, pink)"
+
+// nice alias to set up a match
+// example: g_forced_team_matchsetup stormkeep "mzDo0nO2y3XpFPNbQAyeUucyaejZ9xpiXLYMGU2x3qM=" "BRLOGENSHFEGLE/+Mq3x2UGMYLXipx9ZjeaycuUeyAQ="
+// will set up a match on stormkeep where mzDo0nO2y3XpFPNbQAyeUucyaejZ9xpiXLYMGU2x3qM= and BRLOGENSHFEGLE/+Mq3x2UGMYLXipx9ZjeaycuUeyAQ= play against each other
+alias g_forced_team_matchsetup "map $1; settemp g_forced_team_red \"$2\"; settemp g_forced_team_blue \"$3\"; settemp g_forced_team_yellow \"$4\"; settemp g_forced_team_pink \"$5\"; settemp g_forced_team_otherwise spectate"
+
+// frozen
+set g_frozen_revive_falldamage 0 "Enable reviving from this amount of fall damage"
+set g_frozen_revive_falldamage_health 40 "Amount of health player has if they revived from falling"
+set g_frozen_damage_trigger 1 "if 1, frozen players falling into the void will die instead of teleporting to spawn"
+set g_frozen_force 0.6 "How much to multiply the force on a frozen player with"
+
+// player statistics
+set g_playerstats_gamereport_uri "http://stats.xonotic.org/stats/submit" "Output player statistics information to either: URL (with ://), console (with a dash like this: -), or supply a filename to output to data directory."
+set g_playerstats_gamereport_ladder ""
+set g_playerstats_playerbasic_uri "http://stats.xonotic.org"
+set g_playerstats_playerdetail_uri "http://stats.xonotic.org/player/me"
+set g_playerstats_playerdetail_autoupdatetime 1800 // automatically update every 30 minutes anyway
+
+// autoscreenshots
+set g_max_info_autoscreenshot 3 "how many info_autoscreenshot entities are allowed"
+
+// mod names for server browser
+// note: the lowest of these that mismatches default is used
+set g_mod_physics "" "Current physics config name"
+set g_mod_balance "" "Current balance config name"
+set g_mod_config  "" "Current config mod name"
+
+// other config files
+exec balance-xonotic.cfg
+exec physicsX.cfg
+exec turrets.cfg
+exec gamemodes-server.cfg
+exec mutators.cfg
+exec monsters.cfg
+exec minigames.cfg
+exec physics.cfg
+
+set sv_join_notices ""
+set sv_join_notices_time 15
+
+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"