*.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
*.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
*.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
*.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
*.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
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
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 ..
- 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 '^:'
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 ..
-Sat Jul 8 07:24:47 CEST 2017
+Wed Jun 20 07:24:25 CEST 2018
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
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"
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 ${* ?}"
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"
// {{{ #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
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
// }}}
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
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
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
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
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
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
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
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
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
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
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
// }}}
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
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
// }}}
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
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
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
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
// }}}
--- /dev/null
+// 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
+// }}}
+++ /dev/null
-// {{{ #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
-// }}}
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_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
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
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
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
// }}}
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
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
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
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
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
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
// }}}
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_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
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
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
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
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
// }}}
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_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
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
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
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
// }}}
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
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
// {{{ 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
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
// {{{ 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
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
// {{{ 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
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
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
// {{{ 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
// }}}
// {{{ 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
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
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
// {{{ 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
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
// {{{ 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
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
// {{{ 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
bind f6 team_auto
bind f7 menu_showsandboxtools
-
+bind f8 "quickmenu"
bind f9 "cl_cmd hud minigame"
// movement
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} \
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
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
// =================================
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)"
// 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"
"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"
#: 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
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "Уключыць панэль"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Чат"
"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"
#: 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
#: 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 "
"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"
#: 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
# 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
#: 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."
#: 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
#: 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
#: 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
#: 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
#: 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
"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"
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: qcsrc/menu/xonotic/credits.qc:231
msgid "Irish"
-msgstr ""
+msgstr "Irisch"
#: qcsrc/menu/xonotic/credits.qc:234
msgid "Italian"
#: qcsrc/menu/xonotic/credits.qc:279
msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Schottisch-Gälisch"
#: qcsrc/menu/xonotic/credits.qc:282
msgid "Serbian"
#: 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
#: 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:"
#: 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:"
#: 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"
"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"
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: qcsrc/menu/xonotic/credits.qc:231
msgid "Irish"
-msgstr ""
+msgstr "Irisch"
#: qcsrc/menu/xonotic/credits.qc:234
msgid "Italian"
#: qcsrc/menu/xonotic/credits.qc:279
msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Schottisch-Gälisch"
#: qcsrc/menu/xonotic/credits.qc:282
msgid "Serbian"
#: 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
#: 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:"
#: 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:"
#: 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"
"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"
#: 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
"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"
#: 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"
#: 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
#: 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"
"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"
#: 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
# 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
"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"
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: 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"
#: qcsrc/common/mapinfo.qh:220
msgid "Capture the Flag"
-msgstr "Consigue la bandera"
+msgstr "Captura la bandera"
#: qcsrc/common/mapinfo.qh:220
msgid ""
#: 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"
#: 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
"^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
"^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"
#: 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
#: 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"
#: 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
#: 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
#: 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
#: 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
#: 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"
#: 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"
#: qcsrc/menu/xonotic/credits.qc:231
msgid "Irish"
-msgstr ""
+msgstr "Irlandés"
#: qcsrc/menu/xonotic/credits.qc:234
msgid "Italian"
#: qcsrc/menu/xonotic/credits.qc:279
msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Gaélico escocés"
#: qcsrc/menu/xonotic/credits.qc:282
msgid "Serbian"
#: 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)"
#: 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"
"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"
#: 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
"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"
#: 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
"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"
#: 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"
#: 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
#: 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:"
#: 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)"
#: 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"
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "Cumasaigh an painéal"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Comhrá"
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
-# GunChleoc, 2017
+# GunChleoc, 2017-2018
# GunChleoc, 2017
# GunChleoc, 2017
msgid ""
"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"
#: 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
#: 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"
#: 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
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr ""
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Cabadaich"
"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"
"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
#: 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
"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"
#: 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
"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"
#: 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"
#: 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"
#: 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
#: 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
#: 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
#: 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"
#: 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"
"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"
#: 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
"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"
#: 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
"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
#: 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
# 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"
#: 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"
#: 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)"
#: 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
#: 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
#: qcsrc/client/hud/panel/scoreboard.qc:84
msgid "SCO^damage"
-msgstr ""
+msgstr "SCO^데미지"
#: qcsrc/client/hud/panel/scoreboard.qc:85
msgid "SCO^dmgtaken"
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:97
msgid "SCO^losses"
-msgstr ""
+msgstr "SCO^패배"
#: qcsrc/client/hud/panel/scoreboard.qc:98
msgid "SCO^name"
#: qcsrc/client/hud/panel/scoreboard.qc:99
msgid "SCO^sum"
-msgstr ""
+msgstr "SCO^합"
#: qcsrc/client/hud/panel/scoreboard.qc:100
msgid "SCO^nick"
#: qcsrc/client/hud/panel/scoreboard.qc:102
msgid "SCO^pickups"
-msgstr ""
+msgstr "SCO^픽업"
#: qcsrc/client/hud/panel/scoreboard.qc:103
msgid "SCO^ping"
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:109
msgid "SCO^rounds won"
-msgstr ""
+msgstr "SCO^회 이김"
#: qcsrc/client/hud/panel/scoreboard.qc:110
msgid "SCO^score"
#: qcsrc/client/hud/panel/scoreboard.qc:112
msgid "SCO^takes"
-msgstr ""
+msgstr "SCO^가져감"
#: qcsrc/client/hud/panel/scoreboard.qc:113
msgid "SCO^ticks"
#: 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
#: 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
#: 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
#: 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"
#: qcsrc/common/notifications/all.qh:444
msgid "TRIPLE FRAG! "
-msgstr ""
+msgstr "트리플 킬!"
#: qcsrc/common/notifications/all.qh:445
#, c-format
#: qcsrc/common/notifications/all.qh:445
msgid "RAGE! "
-msgstr ""
+msgstr "레이지!"
#: qcsrc/common/notifications/all.qh:446
#, c-format
#: qcsrc/common/notifications/all.qh:446
msgid "MASSACRE! "
-msgstr ""
+msgstr "대학살!"
#: qcsrc/common/notifications/all.qh:447
#, c-format
#: 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"
#: 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
#: 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"
#: 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:"
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:14
msgid "Info messages:"
-msgstr ""
+msgstr "정보 메세지:"
#: qcsrc/menu/xonotic/dialog_hudpanel_infomessages.qc:17
msgid "Flip align"
#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:217
msgid "Hostname:"
-msgstr ""
+msgstr "호스트이름:"
#: qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfo.qc:231
msgid "Gametype:"
#: 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
#: 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:"
#: 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"
#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:25
msgid "Demos"
-msgstr ""
+msgstr "데모들"
#: qcsrc/menu/xonotic/dialog_multiplayer_media.qc:26
msgid "Screenshots"
#: 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."
#: 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"
#: 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"
#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:48
msgid "Name"
-msgstr ""
+msgstr "이름"
#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:77
msgid "Model"
#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:145
msgid "Country"
-msgstr ""
+msgstr "국가"
#: qcsrc/menu/xonotic/dialog_multiplayer_profile.qc:159
msgid "Gender:"
#: 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!"
#: 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:"
#: 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"
#: qcsrc/menu/xonotic/dialog_settings_audio.qc:29
msgid "Master:"
-msgstr ""
+msgstr "마스터:"
#: qcsrc/menu/xonotic/dialog_settings_audio.qc:35
msgid "Music:"
#: 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"
#: 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"
#: 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"
#: 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)"
#: 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)"
#: 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."
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qh:7
msgid "Messages"
-msgstr ""
+msgstr "메시지"
#: qcsrc/menu/xonotic/dialog_settings_game_model.qc:30
msgid "Items"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:37
msgid "56k"
-msgstr ""
+msgstr "56k"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:38
msgid "ISDN"
#: 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"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:85
msgid "Framerate"
-msgstr ""
+msgstr "프레임레이트"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:87
msgid "Maximum:"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:135
msgid "Menu tooltips:"
-msgstr ""
+msgstr "메뉴 팁:"
#: qcsrc/menu/xonotic/dialog_settings_misc.qc:137
msgid ""
#: 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"
#: 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"
#: qcsrc/menu/xonotic/gametypelist.qc:86
msgid "teamplay"
-msgstr ""
+msgstr "팀플레이"
#: qcsrc/menu/xonotic/gametypelist.qc:88
msgid "free for all"
#: qcsrc/menu/xonotic/keybinder.qc:97
msgid "quit"
-msgstr ""
+msgstr "종료"
#: qcsrc/menu/xonotic/keybinder.qc:101
msgid "auto-join team"
#: qcsrc/menu/xonotic/keybinder.qc:106
msgid "quick menu"
-msgstr ""
+msgstr "빠른메뉴"
#: qcsrc/menu/xonotic/keybinder.qc:107
msgid "sandbox menu"
#: 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"
#: 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:"
#: qcsrc/menu/xonotic/statslist.qc:110
msgid "Time_Played:"
-msgstr ""
+msgstr "플레이_시간:"
#: qcsrc/menu/xonotic/statslist.qc:117
msgid "Favorite_Map:"
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "제어반 활성화"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^채팅"
# 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
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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
#: 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."
#: 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"
#: 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
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:84
msgid "SCO^damage"
-msgstr ""
+msgstr "SCO^damach"
#: qcsrc/client/hud/panel/scoreboard.qc:85
msgid "SCO^dmgtaken"
#: 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"
#: 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"
#: 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"
#: 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 ""
#: 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"
#: 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
#: 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
#: 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"
#: qcsrc/client/view.qc:1385
msgid "Capture progress"
-msgstr ""
+msgstr "Spedyans ow sesya"
#: qcsrc/client/view.qc:1390
msgid "Revival progress"
#: qcsrc/common/items/item/armor.qh:111
msgid "Big armor"
-msgstr ""
+msgstr "Arvwisk bras"
#: qcsrc/common/items/item/armor.qh:147
msgid "Mega armor"
#: qcsrc/common/items/item/health.qh:111
msgid "Big health"
-msgstr ""
+msgstr "Yeghes bras"
#: qcsrc/common/items/item/health.qh:147
msgid "Mega health"
"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"
#: 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
#: 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"
#: 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"
#: qcsrc/common/mutators/mutator/waypoints/all.inc:6
msgid "DANGER"
-msgstr ""
+msgstr "PERYL"
#: qcsrc/common/mutators/mutator/waypoints/all.inc:8
msgid "Frozen!"
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr ""
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Keskows"
"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"
#: 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
--- /dev/null
+# 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"
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "Activeer paneel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Chat"
"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"
#: 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
# 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"
#: 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"
#: 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"
#: 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 ""
"^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"
#: 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"
#: 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"
#: 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"
"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"
"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
"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
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "Włącz panel"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "Czat"
#
# 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"
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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."
#: 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
#: 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"
#: 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"
#: 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"
#: 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)"
#: 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
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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
#: 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
#: qcsrc/client/hud/panel/scoreboard.qc:89
msgid "SCO^goals"
-msgstr "gols"
+msgstr "golos"
#: qcsrc/client/hud/panel/scoreboard.qc:90
msgid "SCO^kckills"
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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
"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
"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"
"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
"'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
#: 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:"
#: 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"
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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"
#: 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
#: 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"
#: 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
#: 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
#: 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"
#: 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
"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
"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
#: 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"
#: 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
#: 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
#: 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"
#: qcsrc/common/mutators/mutator/buffs/all.inc:86
msgid "Jump"
-msgstr "Pular"
+msgstr "Saltar"
#: qcsrc/common/mutators/mutator/buffs/all.inc:95
msgid "Invisible"
#: qcsrc/common/mutators/mutator/buffs/all.inc:120
msgid "Magnet"
-msgstr "Ímã"
+msgstr "Íman"
#: qcsrc/common/mutators/mutator/buffs/all.inc:128
msgid "Luck"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: 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
#: 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:"
#: 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
"^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"
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
#: 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
#: 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
#, 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#, 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
#: 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
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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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"
#: 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
"^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
#: 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
#, 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
"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
"^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
"^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
"^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
"^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
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
"^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
"^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
#: 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
#: 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
#: 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
#: 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
"^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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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 ""
"^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 ""
"^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
#: 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
"^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!"
#: 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
#: 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
"^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
"^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
#: 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 ""
"^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!"
"^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 ""
"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
"^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 o 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 há mais..."
#: qcsrc/common/notifications/all.inc:768
#, c-format
#: 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"
#: 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
#: qcsrc/common/notifications/all.qh:420
msgid "throw nade"
-msgstr "arremessar granada"
+msgstr "atirar granada"
#: qcsrc/common/notifications/all.qh:431
#, c-format
#: 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
#: qcsrc/common/notifications/all.qh:444
msgid "TRIPLE FRAG! "
-msgstr "FRAG TRIPLO! "
+msgstr "EXECUÇÃO TRIPLA! "
#: qcsrc/common/notifications/all.qh:445
#, c-format
#: 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
#: 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
#: 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
"(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
#: 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! "
#: 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
#: 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"
#: qcsrc/common/teams.qh:33
msgid "Team"
-msgstr "Equipe"
+msgstr "Equipa"
#: qcsrc/common/teams.qh:34
msgid "Neutral"
#: 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"
#: 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"
#: qcsrc/common/turrets/turret/phaser_weapon.qh:7
msgid "Phaser"
-msgstr "Phaser"
+msgstr ""
#: qcsrc/common/turrets/turret/plasma.qh:13
msgid "Plasma Cannon"
#: 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"
#: 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"
#: qcsrc/common/weapons/weapon/fireball.qc:17
msgid "Fireball"
-msgstr "Fireball"
+msgstr "Bola de Fogo"
#: qcsrc/common/weapons/weapon/hagar.qc:17
msgid "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"
#: 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"
#: 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
#: 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
"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
#: 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"
#: 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"
#: 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
#: 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"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/credits.qc:156
msgid "Belarusian"
-msgstr "Bielorusso"
+msgstr "Bielorrusso"
#: qcsrc/menu/xonotic/credits.qc:159
msgid "Bulgarian"
#: qcsrc/menu/xonotic/credits.qc:180
msgid "Czech"
-msgstr "Tcheco"
+msgstr "Checo"
#: qcsrc/menu/xonotic/credits.qc:185
msgid "Dutch"
#: 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"
#: qcsrc/menu/xonotic/credits.qc:231
msgid "Irish"
-msgstr ""
+msgstr "Irlandês"
#: qcsrc/menu/xonotic/credits.qc:234
msgid "Italian"
#: qcsrc/menu/xonotic/credits.qc:247
msgid "Polish"
-msgstr "Polônes "
+msgstr "Polaco"
#: qcsrc/menu/xonotic/credits.qc:255
msgid "Portuguese"
#: qcsrc/menu/xonotic/credits.qc:279
msgid "Scottish Gaelic"
-msgstr ""
+msgstr "Gaélico Escocês"
#: qcsrc/menu/xonotic/credits.qc:282
msgid "Serbian"
#: 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"
#: 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
"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
#: 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:"
#: 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
#: 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
#: 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:"
#: 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
#: 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:"
#: 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
#: 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:"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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:"
#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:32
msgid "Forward"
-msgstr "Para frente"
+msgstr "Para a frente"
#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:33
msgid "West"
#: 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"
#: 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:"
#: 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"
#: 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:"
#: 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
#: 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:"
#: 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
#: 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"
#: 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:"
#: 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:"
#: 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
#: 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"
#: 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"
#: 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
#: 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:"
#: 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"
#: 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:"
"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"
#: 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"
"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"
#: 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"
#: 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:"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:30
msgid "Most Weapons Arena"
-msgstr "Arena com Maior Parte das Armas"
+msgstr "Arena com a Maior Parte das Armas"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:49
#, c-format
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: 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
#: 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)"
"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"
"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 ""
"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"
#: 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"
#: 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"
#: 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"
"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"
#: 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
#: 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)"
#: 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)"
#: 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)"
#: 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:"
#: 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"
#: 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"
#: 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
#: 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"
#: 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"
#: 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"
#: 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"
#: 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
#: 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..."
#: 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"
#: 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 *"
#: 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:"
#: 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:"
#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:67
msgid "Movable"
-msgstr "Movível"
+msgstr "Deslocável"
#: qcsrc/menu/xonotic/dialog_sandboxtools.qc:68
msgid "Physical"
#: 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"
#: 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
#: 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:"
#: 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:"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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"
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"
"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:"
"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)"
#: 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"
#: 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:"
#: 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:"
#: 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"
#: 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"
"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
#: 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"
"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"
#: 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"
#: 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"
"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"
#: 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
"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"
"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
#: 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"
"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"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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:"
#: 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:"
#: 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"
#: 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"
#: 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
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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 a 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"
#: 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"
#: 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:"
#: 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"
"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"
#: 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"
#: 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
#: 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
#: 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:"
#: 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"
#: 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
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:"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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:"
"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"
#: 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..."
#: 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:"
#: 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:"
#: 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"
#: 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 ""
"(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"
#: 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"
"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)"
#: 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
"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"
"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"
"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:"
#: 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)"
#: 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 "???"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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
"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>"
#: qcsrc/menu/xonotic/serverlist.qc:273
msgid "Favorite"
-msgstr "Favoritar"
+msgstr "Adicionar aos favoritos"
#: qcsrc/menu/xonotic/serverlist.qc:274
msgid ""
#: 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
#: 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"
#: 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"
"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"
#: 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"
"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
#: 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
#: 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"
--- /dev/null
+# 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"
"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"
#: 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"
#: 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
#: 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"
# 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
"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"
#: 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
#: 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
#: 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
#: 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!"
#: 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..."
#: qcsrc/client/hud/panel/infomessages.qc:196
msgid "Teamnumbers are unbalanced!"
-msgstr "Команды не равны!"
+msgstr "Команды не равны по составу!"
#: qcsrc/client/hud/panel/infomessages.qc:199
#, c-format
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:80
msgid "SCO^caps"
-msgstr "SCO^захваты"
+msgstr "SCO^захватов"
#: qcsrc/client/hud/panel/scoreboard.qc:81
msgid "SCO^captime"
#: 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"
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"
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"
"\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
#: 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:"
#: 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
#: 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
#: 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?"
#: qcsrc/client/main.qc:1020
msgid " mph"
-msgstr "милÑ\8f/ч"
+msgstr "милÑ\8c/ч"
#: qcsrc/client/main.qc:1022
msgid " knots"
#: 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"
#: qcsrc/common/items/item/armor.qh:147
msgid "Mega armor"
-msgstr "Мега броня"
+msgstr "Мега-броня"
#: qcsrc/common/items/item/health.qh:111
msgid "Big health"
#: 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"
"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"
"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"
#: 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"
#: 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
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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"
#: 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
#: 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
#: 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
#: 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"
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"
#: 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
#: 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
#: 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
#: 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
#: 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
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
#: 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
#, 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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!"
"^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
#: 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
"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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#, 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
#: 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
#: 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
#: 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
#: 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!"
#: 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"
#: 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
#: 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!"
#: 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
#: 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
#: 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
#: 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
#: 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!"
#: 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!"
#: 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"
#: 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!"
#: 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!"
#: 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!"
#: 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 ""
"^BGDisconnecting in ^COUNT..."
msgstr ""
"^K1Хватит бездельничать!\n"
-"^BGРаÑ\81Ñ\81оединение через ^COUNT..."
+"^BGÐ\9eÑ\82клÑ\8eÑ\87ение через ^COUNT..."
#: qcsrc/common/notifications/all.inc:670
#, c-format
#: 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"
"^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
#: 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!"
#: 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!"
#: 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"
#: 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"
#: qcsrc/common/notifications/all.inc:767
msgid "^BGThere are more to go..."
-msgstr "^BGВпереди еще много чего..."
+msgstr "^BGВпереди ещё много чего..."
#: qcsrc/common/notifications/all.inc:768
#, c-format
#: 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"
#: 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
#: 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
#: qcsrc/common/notifications/all.qh:446
msgid "MASSACRE! "
-msgstr "РЕЗНЯ!"
+msgstr "РЕЗНЯ! "
#: qcsrc/common/notifications/all.qh:447
#, c-format
#: 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
#: qcsrc/common/notifications/all.qh:448
msgid "BERSERKER! "
-msgstr "БЕРСЕРКЕР! "
+msgstr "БЕРСЕРК! "
#: qcsrc/common/notifications/all.qh:449
#, c-format
#: qcsrc/common/notifications/all.qh:449
msgid "CARNAGE! "
-msgstr "БОЙНЯ!"
+msgstr "БОЙНЯ! "
#: qcsrc/common/notifications/all.qh:450
#, c-format
#: qcsrc/common/notifications/all.qh:450
msgid "ARMAGEDDON! "
-msgstr "АРМАГЕДДОН!"
+msgstr "АРМАГЕДДОН! "
#: qcsrc/common/notifications/all.qh:457
#, c-format
#: 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
#: 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
#: 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"
#: 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
#: 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"
#: qcsrc/menu/xonotic/credits.qc:116
msgid "Marketing / PR"
-msgstr "Маркетинг / Cвязи с общественностью"
+msgstr "Маркетинг / Связи с общественностью"
#: qcsrc/menu/xonotic/credits.qc:122
msgid "Legal"
#: 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"
#: 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
#: 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"
#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:54
msgid "mph"
-msgstr "милÑ\8f/ч"
+msgstr "милÑ\8c/ч"
#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:55
msgid "knots"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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:"
#: 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
#: 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:"
#: 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"
#: 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
"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"
#: 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"
#: 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
#: 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
#: 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)"
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 ""
"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"
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"
#: 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:"
#: 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"
#: 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)"
"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"
"\"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"
"(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:"
"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)"
"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"
#: 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"
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"
msgstr ""
"Включить эффект свечения, который увеличивает яркость пикселей, "
"соседствующих с очень яркими. Очень снижает производительность (по "
-"Ñ\83молÑ\87аниÑ\8e: вÑ\8bкл.)"
+"Ñ\83молÑ\87аниÑ\8e: оÑ\82кл.)"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:226
msgid "Extra postprocessing effects"
"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"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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:"
#: 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"
#: 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
#: 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 ""
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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
#: 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:"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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"
"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"
#: 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"
#: 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"
"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"
#: 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:"
"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"
#: qcsrc/menu/xonotic/dialog_settings_video.qc:97
msgid "Depth first:"
-msgstr "СпеÑ\80ва глубина:"
+msgstr "СнаÑ\87ала глубина:"
#: qcsrc/menu/xonotic/dialog_settings_video.qc:99
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"
#: 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"
#: 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
"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)"
"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)"
#: qcsrc/menu/xonotic/dialog_singleplayer.qc:131
msgid "CSKL^Easy"
-msgstr "Легкий"
+msgstr "Лёгкий"
#: qcsrc/menu/xonotic/dialog_singleplayer.qc:132
msgid "CSKL^Medium"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/keybinder.qc:101
msgid "auto-join team"
-msgstr "авто-выбор команды"
+msgstr "автовыбор команды"
#: qcsrc/menu/xonotic/keybinder.qc:103
msgid "drop key / drop flag"
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
"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"
#: 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
#: 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
#: 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"
"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"
#: 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
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "Омогући плочу"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^Ћаскање"
"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"
#: 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
"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"
#: 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
"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"
"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
#: 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
"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"
#: 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
# 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"
#: 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."
#: 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"
#: 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"
#: 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"
#: 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
#: 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"
#: 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)"
#: 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
#: qcsrc/client/hud/panel/quickmenu.qc:871
msgid "QMCMD^Shuffle teams"
-msgstr ""
+msgstr "QMCMD^随机组队"
#: qcsrc/client/hud/panel/racetimer.qc:37
#, c-format
#: 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"
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:96
msgid "SCO^lives"
-msgstr ""
+msgstr "SCO^生命数"
#: qcsrc/client/hud/panel/scoreboard.qc:97
msgid "SCO^losses"
#: qcsrc/client/hud/panel/scoreboard.qc:100
msgid "SCO^nick"
-msgstr ""
+msgstr "SCO^昵称"
#: qcsrc/client/hud/panel/scoreboard.qc:101
msgid "SCO^objectives"
#: 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"
#: qcsrc/client/hud/panel/scoreboard.qc:111
msgid "SCO^suicides"
-msgstr ""
+msgstr "SCO^自杀数"
#: qcsrc/client/hud/panel/scoreboard.qc:112
msgid "SCO^takes"
#: 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"
#: 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"
"^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 ""
#: 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"
#: 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"
#: 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 ""
#: qcsrc/client/hud/panel/scoreboard.qc:1354
msgid "Capture time rankings"
-msgstr ""
+msgstr "占领时间排名"
#: qcsrc/client/hud/panel/scoreboard.qc:1354
msgid "Rankings"
#: qcsrc/client/hud/panel/scoreboard.qc:1604
#, c-format
msgid "Spectators"
-msgstr "观察者"
+msgstr "观众"
#: qcsrc/client/hud/panel/scoreboard.qc:1619
#, c-format
#: 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
#: 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?"
#: qcsrc/client/main.qc:1264
#, c-format
msgid "%s (not bound)"
-msgstr ""
+msgstr "%s (未绑定)"
#: qcsrc/client/mapvoting.qc:49
msgid " (1 vote)"
#: 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"
#: 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"
#: qcsrc/common/items/item/powerup.qh:44
msgid "Strength"
-msgstr "加强"
+msgstr "神力"
#: qcsrc/common/items/item/powerup.qh:76
msgid "Shield"
#: qcsrc/common/mapinfo.qh:126
msgid "Race against other players to the finish line"
-msgstr ""
+msgstr "与其他玩家赛跑到达终点线"
#: qcsrc/common/mapinfo.qh:160
msgid "Race CTS"
#: 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"
#: qcsrc/common/mapinfo.qh:249
msgid "Clan Arena"
-msgstr ""
+msgstr "组队竞技"
#: qcsrc/common/mapinfo.qh:249
msgid "Kill all enemy teammates to win the round"
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"
#: 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"
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"
#: 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"
#: 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!"
#: qcsrc/common/minigames/minigame/bd.qc:1404
msgid "Next Level"
-msgstr ""
+msgstr "下一关"
#: qcsrc/common/minigames/minigame/bd.qc:1405
msgid "Restart"
#: 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
#: 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:"
#: 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
#: qcsrc/common/mutators/mutator/waypoints/all.inc:62
msgid "Intruder!"
-msgstr ""
+msgstr "入侵者!"
#: qcsrc/common/mutators/mutator/waypoints/all.inc:64
msgid "Tagged"
#: 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
"^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
"^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
#: 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"
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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
#: 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"
#: 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
#: 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!"
#: 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!"
#: 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"
#: 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 ""
#: 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"
#: 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"
#: 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"
#: qcsrc/common/turrets/turret/hellion_weapon.qh:7
msgid "Hellion"
-msgstr ""
+msgstr "海龙"
#: qcsrc/common/turrets/turret/hk.qh:15
msgid "Hunter-Killer Turret"
#: 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"
#: 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
#: qcsrc/common/turrets/turret/walker_weapon.qh:7
msgid "Walker"
-msgstr ""
+msgstr "沃克"
#: qcsrc/common/vehicles/cl_vehicles.qc:192
#, c-format
#: 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"
#: 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"
#: qcsrc/common/weapons/weapon/hagar.qc:17
msgid "Hagar"
-msgstr ""
+msgstr "哈格"
#: qcsrc/common/weapons/weapon/hlac.qc:17
msgid "Heavy Laser Assault Cannon"
#: qcsrc/common/weapons/weapon/mortar.qc:17
msgid "Mortar"
-msgstr ""
+msgstr "榴弹枪"
#: qcsrc/common/weapons/weapon/porto.qc:17
msgid "Port-O-Launch"
#: qcsrc/common/weapons/weapon/shockwave.qc:17
msgid "Shockwave"
-msgstr ""
+msgstr "脉冲波枪"
#: qcsrc/common/weapons/weapon/shotgun.qc:17
msgid "Shotgun"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/credits.qc:142
msgid "Other Active Contributors"
-msgstr ""
+msgstr "其他活跃贡献者"
#: qcsrc/menu/xonotic/credits.qc:149
msgid "Translators"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: qcsrc/menu/xonotic/dialog_credits.qh:7
msgid "Credits"
-msgstr "制作人员"
+msgstr ""
#: qcsrc/menu/xonotic/dialog_credits.qh:8
msgid "The Xonotic credits"
#: 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:"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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
#: 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"
#: 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
#: 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
#: 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
#: 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)"
#: 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
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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"
#: 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"
#: 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:"
#: 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"
#: 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
"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"
"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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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"
#: 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:"
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"
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"
#: 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"
#: qcsrc/menu/xonotic/keybinder.qc:106
msgid "quick menu"
-msgstr ""
+msgstr "快速菜单"
#: qcsrc/menu/xonotic/keybinder.qc:107
msgid "sandbox menu"
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"
#: qcsrc/menu/xonotic/serverlist.qc:764
msgid "Hostname"
-msgstr ""
+msgstr "主机名"
#: qcsrc/menu/xonotic/serverlist.qc:765
msgid "Map"
#: qcsrc/menu/xonotic/serverlist.qc:1060
msgid "encryption:"
-msgstr ""
+msgstr "加密:"
#: qcsrc/menu/xonotic/serverlist.qc:1061
#, c-format
#: qcsrc/menu/xonotic/serverlist.qh:156
msgid "SLCAT^Modified Servers"
-msgstr "已更改服务器"
+msgstr "SLCAT^Mod服务器"
#: qcsrc/menu/xonotic/serverlist.qh:157
msgid "SLCAT^Overkill"
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"
"texture memory usage, but make the textures appear very blurry. (default: "
"good)"
msgstr ""
+"改变纹理的锐度,降低该值可以有效减少纹理的内存占用,但会使纹理显得非常模糊。"
+"(默认:好)"
#: qcsrc/menu/xonotic/slider_resolution.qc:115
msgid "Screen resolution"
#: qcsrc/menu/xonotic/statslist.qc:103
msgid "Last_Seen:"
-msgstr ""
+msgstr "上次活动:"
#: qcsrc/menu/xonotic/statslist.qc:110
msgid "Time_Played:"
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "启用面板"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^对话"
"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"
#: 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"
#: 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
#: qcsrc/menu/xonotic/util.qh:44
msgid "Enable panel"
msgstr "開啟板面"
+
+#~ msgid "QMCMD^Chat"
+#~ msgstr "QMCMD^對話"
// 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
-exec defaultXonotic.cfg
+exec xonotic-common.cfg
+++ /dev/null
-// 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."
+++ /dev/null
-// ==============
-// 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
+++ /dev/null
-// 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"
+++ /dev/null
-// ================
-// 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
+++ /dev/null
-// ==================
-// 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
+++ /dev/null
-// 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"
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
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
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
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
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
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
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
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
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"
// ==========================
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"
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
COLOR_SLIDER_D '1 1 1'
COLOR_SLIDER_S '1 1 1'
WIDTH_SLIDERTEXT 0.333333333333
-TOLERANCE_SLIDER '0.2 2 0'
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'
COLOR_SLIDER_D '1 1 1'
COLOR_SLIDER_S '1 1 1'
WIDTH_SLIDERTEXT 0.333333333333
-TOLERANCE_SLIDER '0.2 2 0'
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"
+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%
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
+hidden 1
-name Gak Masked
+name Gak
species alien
sex Male
weight 87
bone_aim3 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
+hidden 1
bone_aim2 0.35 bip01 r hand
bone_weapon bip01 r hand
fixbone 1
+hidden 1
// ==========
// 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
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
//
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"
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
// ==========
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"
// =======
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"
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
// ==============
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
// ===============
// 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"
// =========
g_mod_physics Xonotic
-// current Xonotic physics
+// Xonotic 0.7 physics
sv_gravity 800
sv_maxspeed 360
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
-std=gmqcc \
-Ooverlap-locals \
-O3 \
- -Werror -Wall \
+ $(QCCFLAGS_WERROR) \
+ -Wall \
$(QCCFLAGS_WTFS) \
-flno -futf8 -fno-bail-on-werror \
-frelaxed-switch -freturn-assignments \
#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>
#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>
#include "announcer.qh"
-#include "mutators/events.qh"
+#include <client/mutators/_mod.qh>
#include <common/notifications/all.qh>
#include <common/stats.qh>
void Announcer_Time()
{
+ if(intermission)
+ return;
+
float timeleft;
if(warmup_stage)
{
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;
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;
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)
{
if(i >= bgmscriptbufsize)
{
LOG_INFOF("ERROR: bgmscript does not define %s", e.bgmscript);
- strunzone(e.bgmscript);
- e.bgmscript = string_null;
+ strfree(e.bgmscript);
}
}
}
#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);
#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>
}
}
-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);
case "clickradar":
{
- HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
+ if(!isdemo())
+ HUD_Radar_Show_Maximized(!hud_panel_radar_mouse, 1);
return;
}
}
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")
s = W_FixWeaponOrder(W_NumberWeaponOrder(s), 0);
localcmd("cmd sentcvar ", thiscvar, " \"", s, "\"\n");
- strunzone(thiscvar);
+ strfree(thiscvar);
return;
}
}
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);
#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>
.float death_time;
.int modelflags;
-void CSQCModel_Hook_PreDraw(entity this, bool isplayer);
-
.bool isplayermodel;
// FEATURE: LOD
.int csqcmodel_traileffect;
void CSQCModel_Effects_Apply(entity this);
+
+void CSQCModel_Hook_PreDraw(entity this, bool isplayer);
#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>
/*
==================
*/
-void CSQC_BUMBLE_GUN_HUD();
-
void HUD_Vehicle()
{
if(autocvar__hud_configure) return;
return true;
}
-entity CSQCModel_server2csqc(int i);
-void calc_followmodel_ofs(entity view);
void Hud_Dynamic_Frame()
{
vector ofs = '0 0 0';
// 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
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);
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;
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;
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
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;
} \
} \
} \
- 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.
}
}
-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)
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)
void HUD_Configure_PostDraw();
float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary);
+
+void HUD_Panel_EnableMenu();
+
+void HUD_Panel_FirstInDrawQ(float id);
#include "hud.qh"
#include "hud_config.qh"
-#include <client/mutators/events.qh>
+#include <client/mutators/_mod.qh>
#include <client/view.qh>
#include <common/t_items.qh>
#include <common/wepent.qh>
+#include <common/mutators/mutator/nades/nades.qh>
// Ammo (#1)
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);
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)
{
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;
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);
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;
#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)
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"
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);
}
}
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;
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);
// 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()
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);
++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;
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);
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;
}
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;
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)
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)
}
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")
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;
}
}
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);
#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>
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)
{
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));
#pragma once
#include "../panel.qh"
+
+void HUD_Radar_Show_Maximized(bool doshow, bool clickable);
#include <client/autocvars.qh>
#include <client/defs.qh>
+#include <client/main.qh>
#include <client/miscfunctions.qh>
#include "quickmenu.qh"
#include <common/ent_cs.qh>
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)
{
Cmd_Scoreboard_SetFields(0);
}
-float SetTeam(entity pl, float Team);
//float lastpnum;
void Scoreboard_UpdatePlayerTeams()
{
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
// 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" \
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)
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;
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);
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, {
}
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;
}
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;
}
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;
}
}
+ 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);
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)))
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)
{
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 {
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;
}
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; \
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;
}
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)
{
// 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)
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)
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;
}
}
// 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));
#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>
#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>
// 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"));
registercvar("cl_jumpspeedcap_min", "");
registercvar("cl_jumpspeedcap_max", "");
+ registercvar("cl_shootfromfixedorigin", "");
+
registercvar("cl_multijump", "1");
registercvar("cl_spawn_near_teammate", "1");
this.nextthink = time + 0.2;
}
-void TrueAim_Init();
void PostInit()
{
entity playerchecker = new_pure(playerchecker);
// --------------------------------------------------------------------------
// BEGIN OPTIONAL CSQC FUNCTIONS
-void Ent_Remove(entity this);
-
void Ent_RemovePlayerScore(entity this)
{
if(this.owner) {
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
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)
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);
if(entnum)
{
- this.origin_x = ReadCoord();
- this.origin_y = ReadCoord();
- this.origin_z = ReadCoord();
+ this.origin = ReadVector();
if(is_new)
{
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);
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;
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;
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;
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:
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:
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:
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;
// 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;
}
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;
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;
}
}
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];
int spectatorlist[MAX_SPECTATORS];
int framecount;
-.float health;
float GetSpeedUnitFactor(int speed_unit);
string GetSpeedUnit(int speed_unit);
return mv_mouse_selection;
}
-vector HUD_GetTableSize_BestItemAR(int item_count, vector psize, float item_aspect);
void MapVote_Draw()
{
string map;
{
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;
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
#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;
#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)
{
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;
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
#include "autocvars.qh"
#include "miscfunctions.qh"
+#include "resources.qh"
#include "hud/_mod.qh"
#include <common/ent_cs.qh>
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);
}
}
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);
#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();
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;
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)
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
#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>
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);
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;
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())
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);
}
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)
case WEP_MORTAR: // toss curve
return SHOTTYPE_HITWORLD;
case WEP_VORTEX:
+ case WEP_OVERKILL_NEX:
case WEP_VAPORIZER:
mv = MOVE_NORMAL;
break;
return SHOTTYPE_HITWORLD;
}
-void PostInit();
-void CSQC_Demo_Camera();
float camera_mode;
const float CAMERA_FREE = 1;
const float CAMERA_CHASE = 2;
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;
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;
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";
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;
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';
{
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);
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);
}
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);
TargetMusic_Advance();
Fog_Force();
+ fpscounter_update();
if(drawtime == 0)
drawframetime = 0.01666667; // when we don't know fps yet, we assume 60fps
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
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;
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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);
#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>
#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>
}
}
-bool Projectile_isnade(int proj); // TODO: remove
-
void Projectile_Draw(entity this)
{
vector rot;
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
#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);
#ifdef GAMEQC
#include "physics/all.inc"
-#include "triggers/include.qc"
+#include "mapobjects/_mod.inc"
#include "viewloc.qc"
#endif
{
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;
}
}
#pragma once
-const int RANKINGS_CNT = 15;
+const int RANKINGS_CNT = 99;
///////////////////////////
// keys pressed
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) \
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) \
.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; \
/** 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);
#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;
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());
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
/**
}
#endif
+
#ifdef SVQC
COMMON_COMMAND(debugdraw_sv, "Dump all server entities")
{
#endif
#endif
+
GENERIC_COMMAND(bufstr_get, "Examine a string buffer object")
{
switch (request)
}
}
+
GENERIC_COMMAND(version, "Print the current version")
{
switch (request)
}
}
+
#ifdef CSQC
void(float bufhandle, string pattern, string antipattern) buf_cvarlist = #517;
#endif
}
}
+
#if ENABLE_DEBUGTRACE
REGISTER_STAT(TRACE_ENT, int)
#ifdef SVQC
#endif
#endif
+
GENERIC_COMMAND(find, "Search through entities for matching classname")
{
switch (request)
}
}
+
GENERIC_COMMAND(findat, "Search through entities for matching origin")
{
switch (request)
}
}
}
+
+
+// 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
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();
(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); }
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
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
#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); \
}
#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
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);
#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)
{
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;
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));
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();
#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
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);
}
/**
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);
{
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)
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)
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)
{
#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;
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)
{
#ifdef CSQC
entityclass(Rubble);
-class(Rubble).float creationtime;
+classfield(Rubble).float creationtime;
IntrusiveList g_rubble;
STATIC_INIT(g_rubble) { g_rubble = IL_NEW(); }
#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)
}
#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 */
{ 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); },
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);
}
// `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);
}
}
// 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>
// 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>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/assault/assault.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/assault/assault.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/clanarena/clanarena.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/clanarena/clanarena.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/ctf/ctf.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/ctf/ctf.qh>
--- /dev/null
+#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
--- /dev/null
+#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;
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/cts/cts.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/cts/cts.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/deathmatch/deathmatch.qh>
--- /dev/null
+#include "deathmatch.qh"
+
+// TODO: sv_deathmatch?
+#ifdef SVQC
+MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
+{
+ // announce remaining frags
+ return true;
+}
+#endif
--- /dev/null
+#pragma once
+
+#ifdef SVQC
+#include <common/mutators/base.qh>
+REGISTER_MUTATOR(dm, false)
+{
+ MUTATOR_STATIC();
+ return 0;
+}
+#endif
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/domination/domination.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/domination/domination.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/freezetag/freezetag.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/freezetag/freezetag.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/invasion/invasion.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/invasion/invasion.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keepaway/keepaway.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keepaway/keepaway.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keyhunt/keyhunt.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/keyhunt/keyhunt.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/lms/lms.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/lms/lms.qh>
--- /dev/null
+#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
--- /dev/null
+#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
}
#endif
#ifdef SVQC
-.float metertime = _STAT(NB_METERSTART);
-
.entity ballcarried;
int autocvar_g_nexball_goalleadlimit;
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);
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;
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;
}
}
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;
}
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);
{
.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';
}
}
}
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)
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);
}
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);
}
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;
}
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;
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;
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)
{
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);
_tmp = ReadByte();
- if(_tmp != this.health)
+ if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
cpicon_damage(this, _tmp);
- this.health = _tmp;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
}
}
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);
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();
_tmp = ReadByte();
- if(_tmp != this.health)
+ if(_tmp != GetResourceAmount(this, RESOURCE_HEALTH))
generator_damage(this, _tmp);
- this.health = _tmp;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, _tmp);
}
}
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();
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;
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);
{
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;
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);
{
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;
{
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);
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))
{
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)
{
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; }
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);
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);
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;
_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));
}
}
}
// 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);
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);
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))
{
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);
}
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);
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;
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)
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;
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
{
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;
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))
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;
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();
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;
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);
}
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);
}
}
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;
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;
});
{
// 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);
{
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;
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;
{
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; }
}
}
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/race/race.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/race/race.qh>
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tdm/tdm.qc>
--- /dev/null
+// generated file; do not modify
+#include <common/gamemodes/gamemode/tdm/tdm.qh>
--- /dev/null
+#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
--- /dev/null
+#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
#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);
#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))) {
#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.
.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
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__)
#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);
#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
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";
#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";
#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";
#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";
#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
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";
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
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
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
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
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
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
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
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
#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
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;
#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";
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);
#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;
#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;
{
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")
{
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")
{
}
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")
}
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")
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))
{
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))
{
--- /dev/null
+// 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>
--- /dev/null
+// 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>
--- /dev/null
+#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
--- /dev/null
+// 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>
--- /dev/null
+// 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>
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int BOBBING_XAXIS = BIT(0);
+const int BOBBING_YAXIS = BIT(1);
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int BUTTON_DONTACCUMULATEDMG = BIT(7);
--- /dev/null
+#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
--- /dev/null
+#pragma once
+#include "../defs.qh"
+
+IntrusiveList g_conveyed;
+STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+.float ladder_time;
+.entity ladder_entity;
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int RAINSNOW_SNOW = 0;
+const int RAINSNOW_RAIN = 1;
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int FUNC_ROTATING_XAXIS = BIT(2);
+const int FUNC_ROTATING_YAXIS = BIT(3);
+const int FUNC_ROTATING_STARTOFF = BIT(4);
--- /dev/null
+#include "stardust.qh"
+#ifdef SVQC
+spawnfunc(func_stardust)
+{
+ this.effects = EF_STARDUST;
+
+ CSQCMODEL_AUTOINIT(this);
+}
+#endif
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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;
--- /dev/null
+// 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>
--- /dev/null
+// 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>
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int FOLLOW_ATTACH = BIT(0);
+const int FOLLOW_LOCAL = BIT(1);
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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;
+}
--- /dev/null
+#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;
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+// 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>
--- /dev/null
+// 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>
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int CHANGELEVEL_MULTIPLAYER = BIT(1);
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+#ifdef SVQC
+.entity spawnpoint_targ;
+#endif
--- /dev/null
+#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
--- /dev/null
+#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);
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
+ }
+}
--- /dev/null
+#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
--- /dev/null
+// 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>
--- /dev/null
+// 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>
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int COUNTER_FIRE_AT_COUNT = BIT(2);
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int GRAVITY_STICKY = BIT(0); // keep gravity multiplier even after exiting the trigger_gravity
+const int GRAVITY_START_DISABLED = BIT(1);
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int HEAL_SOUND_ALWAYS = BIT(2);
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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;
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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);
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int MONOFLOP_FIXED = BIT(0);
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+#ifdef SVQC
+void multi_trigger(entity this);
+void multi_reset(entity this);
+
+spawnfunc(trigger_once);
+#endif
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int RELAYIF_NEGATE = BIT(0);
--- /dev/null
+#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
--- /dev/null
+#pragma once
+
+
+const int RELAYTEAMCHECK_NOTEAM = BIT(0);
+const int RELAYTEAMCHECK_INVERT = BIT(1);
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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)
--- /dev/null
+#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
--- /dev/null
+#pragma once
--- /dev/null
+#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
--- /dev/null
+#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
--- /dev/null
+#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); }
--- /dev/null
+#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
#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) \
// (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; \
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);
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;
}
case BD_TILE_BRICK1: return false;
}
- if(dozer.netname) { strunzone(dozer.netname); }
- dozer.netname = strzone(newpos);
+ strcpy(dozer.netname, newpos);
return true;
}
if(!piece)
return; // how?!
- if(piece.netname) { strunzone(piece.netname); }
+ strfree(piece.netname);
delete(piece);
minigame_server_sendflags(minigame,MINIG_SF_UPDATE);
return;
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;
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;
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);
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)
{
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)
{
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;
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;
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":
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;
{
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();
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;
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;
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);
}
}
if(existing)
{
- if(existing.netname) { strunzone(existing.netname); }
+ strfree(existing.netname);
delete(existing);
}
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;
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;
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);
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;
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;
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;
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;
delete(e);
}
- strunzone(minigame_session.netname);
+ strfree(minigame_session.netname);
delete(minigame_session);
}
#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);
}
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
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);
{
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;
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);
}
// 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);
}
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;
}
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));
}
});
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);
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;
});
}
- 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);
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); }
#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"));
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)
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);
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);
}
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;
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); }
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);
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);
});
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);
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); }
#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"));
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;
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,
{
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); }
#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"));
void M_Zombie_Attack_Leap_Touch(entity this, entity toucher)
{
- if (this.health <= 0)
+ if (GetResourceAmount(this, RESOURCE_HEALTH) <= 0)
return;
vector angles_face;
{
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;
}
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];
{
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();
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;
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); }
#include "sv_monsters.qh"
-#include <server/g_subs.qh>
#include <lib/warpzone/common.qh>
#include "../constants.qh"
#include "../teams.qh"
#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>
|| (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))
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
}
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;
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;
}
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;
}
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
// 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;
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
// 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)
{
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)
{
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;
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);
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);
_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;
}
}
-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;
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;
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;
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
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);
}
}
+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)
{
{
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!
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;
}
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; }
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))
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));
}
}
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;
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);
});
#pragma once
+
+.string spawnmob;
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__
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)
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();
#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__))
#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 { \
/**/ 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);
#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>
#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>
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;
}
}
// 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
}
#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
}
#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); \
}
#endif
string Buff_UndeprecateName(string buffname);
+entity buff_FirstFromFlags(int _buffs);
REGISTER_BUFF(Null);
BUFF_SPAWNFUNCS(random, BUFF_Null)
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;
}
}
#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");
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);
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);
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
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)
});
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;
WaypointSprite_UpdateBuildFinished(this.buff_waypoint, time + this.buff_activetime - frametime);
}
- this.oldbuffs = this.buffs;
+ this.oldbuffs = STAT(BUFFS, this);
}
if(!game_stopped)
}
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;
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";
else if (ent.spawnflags & 4)
ent.team = NUM_TEAM_2;
- ent.buffs = replacement.m_itemid;
+ STAT(BUFFS, ent) = replacement.m_itemid;
buff_Init(ent);
}
{
setorigin(ent, old.origin);
ent.angles = old.angles;
- ent.noalign = (old.noalign || (old.spawnflags & 1));
+ ent.noalign = Item_ShouldKeepPosition(old);
buff_Init(ent);
}
void buff_Vengeance_DelayedDamage(entity this)
{
if(this.enemy)
- Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, this.enemy.origin, '0 0 0');
+ Damage(this.enemy, this.owner, this.owner, this.dmg, DEATH_BUFF.m_id, DMG_NOWEP, this.enemy.origin, '0 0 0');
delete(this);
return;
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))
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;
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,
}
// 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))
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));
{
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;
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)
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;
}
{
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)
{
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;
}
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;
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;
}
}
// 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)
{
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)
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;
// 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;
}
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?
}
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;
});
}
- if(player.buffs & BUFF_AMMO.m_itemid)
+ if(STAT(BUFFS, player) & BUFF_AMMO.m_itemid)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
}
}
- 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)
{
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)
{
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;
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;
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);
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
}
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;
{
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;
#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;
);
}
- 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,
}
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;
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)
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()) ||
// 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
#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
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";
/// \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;
/// \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;
#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;
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)
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)
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;
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);
}
}
-.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)
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;
+ }
+}
+#include "sv_items.qh"
+
#include "items.qh"
/// \brief Time of ivisibility powerup in seconds.
/// \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)
{
}
-void powerup_speed_init(entity item)
+void powerup_speed_init(Pickup this, entity item)
{
if(!item.invincible_finished)
{
--- /dev/null
+#pragma once
{
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);
}
}
{
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;
}
}
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;
// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/kick_teamkiller/sv_kick_teamkiller.qh>
+#endif
+#include "sv_kick_teamkiller.qh"
float autocvar_g_kick_teamkiller_rate;
float autocvar_g_kick_teamkiller_lower_limit;
// 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);
--- /dev/null
+#pragma once
#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)
{
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:
+#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")
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);
+}
#include "nades.qh"
+#include "../overkill/okmachinegun.qh"
+
#ifdef SVQC
bool autocvar_g_nades_nade_small;
float autocvar_g_nades_spread = 0.04;
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;
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)
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;
#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);
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)
_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)
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);
}
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);
}
}
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');
}
}
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;
}
}
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;
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);
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;
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,
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;
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))
{
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)) {}
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
{
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)
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)
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);
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;
}
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)
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;
}
}
}
/** 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)
{
//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;
}
{
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
//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;
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;
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)
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
{
delete(player.fake_nade);
player.nade = player.fake_nade = NULL;
- player.nade_timer = 0;
+ STAT(NADE_TIMER, player) = 0;
}
MUTATOR_HOOKFUNCTION(nades, VehicleEnter)
{
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;
}
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);
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;
}
}
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);
}
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)
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)
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;
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);
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");
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)
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)) {
.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);
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
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;
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;
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);
*/
-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
{
.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;
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;
#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;
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
{
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];
}
// 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!
{
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;
}
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;
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;
}
}
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;
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);
}
}
}
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;
}
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qc>
+#endif
--- /dev/null
+// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh>
+#endif
--- /dev/null
+#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;
+}
--- /dev/null
+#pragma once
// 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
// 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>
{
MUTATOR_ONADD {
cvar_settemp("g_overkill", "1");
- WEP_SHOTGUN.mdl = "ok_shotgun";
- WEP_MACHINEGUN.mdl = "ok_mg";
- WEP_VORTEX.mdl = "ok_sniper";
}
}
+++ /dev/null
-#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)
--- /dev/null
+#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
--- /dev/null
+#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)
--- /dev/null
+#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
--- /dev/null
+#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)
--- /dev/null
+#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
--- /dev/null
+#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)
--- /dev/null
+#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
--- /dev/null
+#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)
--- /dev/null
+#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
--- /dev/null
+#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)
+++ /dev/null
-#include "overkill.qh"
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#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)
#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;
.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)
{
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;
}
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;
}
{
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);
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);
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;
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;
M_ARGV(0, string) = "Overkill";
return true;
}
+
#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;
+ }
+}
--- /dev/null
+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;
+ }
+}
}
}
-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))
#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)
{
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);
//============================ 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
// 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.
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 ====================================
.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);
}
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));
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);
//============================= 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");
/// \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.
/// \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));
#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)
{
// 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;
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
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
}
// 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));
// 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");
}
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");
}
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;
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);
}
#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)
{
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)));
}
}
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?!
}
}
/** 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);
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)
.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);
{
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
{
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)
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] */
int t = ReadByte();
if (t < 192)
{
- this.health = t / 191.0;
+ SetResourceAmountExplicit(this, RESOURCE_HEALTH, t / 191.0);
this.build_finished = 0;
}
else
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;
}
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);
}
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)
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;
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
}
// 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;
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;
{
// 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) {
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,
}
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();
}
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;
}
{
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;
}
#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;
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;
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);
// 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);
}
#pragma once
+
+float g_weaponarena_random_with_blaster;
+
+entity GiveFrags_randomweapons;
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
REGISTER_NET_LINKED(ENT_CLIENT_WALL)
#include <lib/csqcmodel/net.qh>
+
+REGISTER_NET_C2S(fpsreport)
#ifdef CSQC
void cl_notice_read();
+
+void cl_notice_run();
#endif
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)
_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
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);
}
#include <common/constants.qh>
#include <common/teams.qh>
#include <common/util.qh>
+#include <common/sounds/sound.qh>
#ifdef CSQC
#include <client/autocvars.qh>
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;
});
}
+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);
}
case MOVETYPE_FLY:
case MOVETYPE_FLY_WORLDONLY:
_Movetype_Physics_Toss(this, movedt);
+ if(wasfreed(this))
+ return;
_Movetype_LinkEdict(this, true);
break;
case MOVETYPE_PHYSICS:
#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)
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
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;
#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;
.float lastflags;
.float lastground;
.float wasFlying;
-#ifdef SVQC
-.float spectatorspeed = _STAT(SPECTATORSPEED);
-#elif defined(CSQC)
-.float spectatorspeed;
-#endif
.int buttons_old;
.vector movement_old;
#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)
#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
#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
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;
#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
}
}
- strunzone(p.playerstats_id);
- p.playerstats_id = string_null;
+ strfree(p.playerstats_id);
}
void PlayerStats_GameReport(float finished)
/// \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
{
REGISTER_SP(ELO);
+REGISTER_SP(FPS);
+
// TODO: move to common mutators
REGISTER_SP(RACE_TIME);
// 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;
} \
} 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()) \
+)
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);
ClientData_Attach(this);
accuracy_init(this);
entcs_attach(this);
- playerdemo_init(this);
anticheat_init(this);
W_HitPlotOpen(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);
bot_clientdisconnect(this);
anticheat_report_to_eventlog(this);
- playerdemo_shutdown(this);
entcs_detach(this);
}
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)
/** 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)
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;
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)
#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>
}
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))
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)
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;
}
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!
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);
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)
//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)
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;
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);
}
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)
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);
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);
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);
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;
//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,
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;
{
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;
{
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;
}
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);
}
}
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))
{
{
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)
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);
{
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);
}
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)
// 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;
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;
else
{
FOREACH(Weapons, it != WEP_Null, {
- if(!(player.weapons & (it.m_wepset)))
+ if(!(STAT(WEAPONS, player) & (it.m_wepset)))
continue;
switch(it.ammo_type)
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)
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)
{
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);
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
{
}
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);
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;
}
s = Buff_UndeprecateName(argv(j));
if(s == it.m_name)
{
- this.buffs |= (it.m_itemid);
+ STAT(BUFFS, this) |= (it.m_itemid);
break;
}
});
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;
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");
{
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);
}
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;
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)
{
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);
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,
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)
{
.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);
}
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;
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)
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-#ifdef SVQC
-spawnfunc(func_breakable);
-#endif
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-const int BUTTON_DONTACCUMULATEDMG = 128;
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-IntrusiveList g_conveyed;
-STATIC_INIT(g_conveyed) { g_conveyed = IL_NEW(); }
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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"
+++ /dev/null
-#pragma once
-
-#include "door.qh"
-#include "ladder.qh"
-#include "train.qh"
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-.float ladder_time;
-.entity ladder_entity;
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#include "stardust.qh"
-#ifdef SVQC
-spawnfunc(func_stardust)
-{
- this.effects = EF_STARDUST;
-
- CSQCMODEL_AUTOINIT(this);
-}
-#endif
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-#ifdef CSQC
-.float dmgtime;
-#endif
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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"
-
+++ /dev/null
-#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"
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#include "include.qh"
-#include "corner.qc"
-#include "follow.qc"
-#include "laser.qc"
-#include "teleport_dest.qc"
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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;
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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"
+++ /dev/null
-#pragma once
-
-#include "music.qh"
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
- }
-}
+++ /dev/null
-#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
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-// tZorks trigger impulse / gravity
-.float radius;
-.float falloff;
-.float strength;
-.float lastpushtime;
+++ /dev/null
-#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"
+++ /dev/null
-#pragma once
-
-#include "multi.qh"
-#include "jumppads.qh"
-#include "secret.qh"
-#include "swamp.qh"
-#include "keylock.qh"
-#include "impulse.qh"
-#include "viewloc.qh"
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
-
-#ifdef SVQC
-void multi_trigger(entity this);
-void multi_reset(entity this);
-
-spawnfunc(trigger_once);
-#endif
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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)
+++ /dev/null
-#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
+++ /dev/null
-#pragma once
+++ /dev/null
-#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
+++ /dev/null
-#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
+++ /dev/null
-#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); }
+++ /dev/null
-#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
this.tur_head.angles += dt * this.tur_head.avelocity;
- if (this.health < 127)
+ if (GetResourceAmount(this, RESOURCE_HEALTH) < 127)
{
dt = random();
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);
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)
{
}
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,
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);
{
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();
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();
}
_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;
}
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);
}
}
-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)
return;
}
- this.health -= damage;
+ TakeResource(this, RESOURCE_HEALTH, damage);
// thorw head slightly off aim when hit?
if (this.damage_flags & TFL_DMG_HEADSHAKE)
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);
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)
{
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;
{
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);
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));
}
{
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;
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;
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);
}
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);
}
PROJECTILE_MAKETRIGGER(proj);
if(_health)
{
- proj.health = _health;
+ SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
proj.takedamage = DAMAGE_YES;
proj.event_damage = turret_projectile_damage;
}
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;
#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");
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; }
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;
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;
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;
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)
if (this.pathcurrent)
{
-
this.moveto = this.pathcurrent.origin;
this.steerto = steerlib_attract2(this, this.moveto, 0.5, 500, 0.95);
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
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;
#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"));
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;
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);
}
#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);
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;
#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"));
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;
//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.
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
#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"));
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;
#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"));
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;
#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"));
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;
#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"));
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,
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);
#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)
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;
#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"));
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;
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);
}
#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"));
{
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;
}
}
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);
}
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);
}
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;
{
#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
}
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)
{
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)
{
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
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;
#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"));
// 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;
}
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
#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.
*/
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.");
}
}
{
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;
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;
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)
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;
#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
if(sf & 2)
{
- axh.origin_x = ReadCoord();
- axh.origin_y = ReadCoord();
- axh.origin_z = ReadCoord();
+ axh.origin = ReadVector();
}
if(sf & 4)
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)
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
}
}
// 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;
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);
}
{
proj.takedamage = DAMAGE_AIM;
proj.event_damage = vehicles_projectile_damage;
- proj.health = _health;
+ SetResourceAmountExplicit(proj, RESOURCE_HEALTH, _health);
}
else
proj.flags |= FL_NOTARGET;
_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();
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)
{
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;
}
}
+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)
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");
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);
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];
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".
}
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;
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;
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);
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
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;
.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;
const float VHSF_NORMAL = 0;
const float VHSF_FACTORY = 2;
-.int hud = _STAT(HUD);
.float dmg_time;
.float play_time;
.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;
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(); }
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)
{
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;
WriteAngle(MSG_ONE, 0); // roll
}
- CSQCVehicleSetup(player, player.hud);
+ CSQCVehicleSetup(player, STAT(HUD, player));
MUTATOR_CALLHOOK(VehicleEnter, player, gunner);
{
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);
}
}
+ }
}
}
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);
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;
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;
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;
}
#include "racer.qh"
#ifdef SVQC
-#include <common/triggers/trigger/impulse.qh>
+#include <common/mapobjects/trigger/impulse.qh>
bool autocvar_g_vehicle_racer = true;
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)
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
// 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);
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
#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)
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)
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);
}
{
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,
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)
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);
{
#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;
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,
}
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);
}
#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"));
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
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))
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);
{
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);
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;
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;
}
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;
}
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;
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) {
}
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)) {
_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);
}
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);
}
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);
}
#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"));
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"));
.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
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);
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;
}
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;
}
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);
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)
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,
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];
}
}
}
+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
case "minstanex": return "vaporizer";
case "grenadelauncher": return "mortar";
case "uzi": return "machinegun";
+ case "hmg": return "okhmg";
+ case "rpc": return "okrpc";
default: return s;
}
}
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)
{
result |= WepSet_FromWeapon(w);
remaining &= ~WepSet_FromWeapon(w);
}
- e.weapons = result;
+ return result;
}
string GetAmmoPicture(int ammotype)
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;
vecs.y = v.y;
vecs.z = v.z;
}
-#endif
else // just do the same as top
{
vecs = shotorg_adjustfromclient(vecs, y_is_right, algn);
// 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);
#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];
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);
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)
.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
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 */
// 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 */
#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;
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);
#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)
{
}
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
{
}
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);
}
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));
}
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);
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;
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');
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
||
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.
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"
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)
{
own,
rootdamage * coefficient * falloff,
WEP_ARC.m_id,
+ weaponentity,
hitorigin,
WEP_CVAR(arc, beam_force) * new_dir * coefficient * falloff
);
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) )
{
}
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);
#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))
{
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:
// 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,
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;
)
);
}
- if(this.beam_muzzleeffect)
+ if(this.beam_muzzleeffect && autocvar_r_drawviewmodel)
{
pointparticles(
this.beam_muzzleeffect,
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;
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
{
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
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
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;
}
.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
NULL,
this.blaster_force,
this.projectiledeathtype,
+ this.weaponentity_fld,
toucher
);
{
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);
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;
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
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;
.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
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);
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);
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)))))
{
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;
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;
.entity queuenext;
.entity queueprev;
+
+void W_Crylink_Dequeue(entity e);
#endif
NULL,
WEP_CVAR(devastator, force),
this.projectiledeathtype,
+ this.weaponentity_fld,
directhitentity
);
head,
(WEP_CVAR(devastator, remote_jump_force) ? WEP_CVAR(devastator, remote_jump_force) : 0),
this.projectiledeathtype | HITTYPE_BOUNCE,
+ this.weaponentity_fld,
NULL
);
break;
NULL,
WEP_CVAR(devastator, remote_force),
this.projectiledeathtype | HITTYPE_BOUNCE,
+ this.weaponentity_fld,
NULL
);
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
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);
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);
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);
// 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))
// 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");
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;
}
/* 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");
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
);
NULL,
WEP_CVAR_SEC(electro, force),
this.projectiledeathtype,
+ this.weaponentity_fld,
directhitentity
);
}
NULL,
WEP_CVAR_PRI(electro, force),
this.projectiledeathtype,
+ this.weaponentity_fld,
directhitentity
);
}
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);
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)
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;
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));
}
}
-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
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;
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
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;
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);
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);
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);
}
}
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);
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);
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);
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);
}
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;
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);
}
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);
}
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)
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));
}
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);
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;
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');
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);
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;
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');
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)
{
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;
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);
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);
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
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;
{
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
}
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)
{
}
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];
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);
}
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)
{
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);
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);
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);
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);
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);
}
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;
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');
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;
{
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;
}
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);
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))
{
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;
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;
}
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);
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;
// 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;
{
float machinegun_spread;
- if(!(fire & 1))
+ if(!(fire & 1) || !weapon_prepareattack_check(thiswep, actor, weaponentity, false, -1))
{
w_ready(thiswep, actor, weaponentity, fire);
return;
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;
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;
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;
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)
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)
}
}
-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);
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);
}
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);
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);
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
// 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");
}
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
}
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];
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);
}
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);
}
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);
}
{
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);
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');
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;
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);
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');
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;
/* 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");
#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) {
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)
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);
{
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;
.float porto_v_angle_held;
.vector right_vector;
.float porto_forbidden;
+
+void W_Porto_Fail(entity this, float failhard);
#endif
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);
}
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))
{
return false;
}
}
+METHOD(Rifle, wr_zoomdir, bool(entity thiswep))
+{
+ return button_attack2 && !WEP_CVAR(rifle, secondary);
+}
#endif
/* 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");
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);
}
-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);
}
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);
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);
{
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);
}
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);
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);
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);
}
{
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;
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);
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))
);
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
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));
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;
actor,
final_damage,
WEP_SHOCKWAVE.m_id,
+ weaponentity,
head.origin,
final_force
);
actor,
final_damage,
WEP_SHOCKWAVE.m_id,
+ weaponentity,
head.origin,
final_force
);
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();
#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)
+ (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);
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)))
{
//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));
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
}
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)
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);
}
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
{
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);
}
{
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);
}
}
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;
}
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)
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)
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)
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);
}
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);
#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
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);
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];
#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);
}
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);
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)
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);
}
{
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);
}
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);
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;
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);
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;
}
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)))
{
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)
{
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);
}
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;
}
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));
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) \
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);
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
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);
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);
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)
{
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
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);
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];
return false;
}
}
+METHOD(Vortex, wr_zoomdir, bool(entity thiswep))
+{
+ return button_attack2 && !WEP_CVAR(vortex, secondary);
+}
#endif
/* 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");
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) \
{ (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); }, \
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(); }) \
\
/**/
}
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)
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)) { \
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)
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)) { \
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
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);
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)) {
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);
// if(pointcontents(midpoint + '0 0 2') == CONTENT_WATER)
// { this.velocity_z = 70; }
}
- goto end;
+ sys_phys_postupdate(this);
+ return;
}
PM_check_slick(this);
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;
{
WarpZone_PlayerPhysics_FixVAngle(this);
Physics_UpdateStats(this);
+ PM_ClientMovement_UpdateStatus(this);
}
bool sys_phys_override(entity this, float dt)
void sys_phys_ai(entity this)
{
if (!IS_BOT_CLIENT(this)) { return; }
- if (playerdemo_read(this)) { return; }
bot_think(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)
|| 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;
#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"
#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>
#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>
#ifdef QCC_SUPPORT_ACCUMULATE
#define ACCUMULATE_FUNCTION(func, otherfunc) \
- [[accumulate]] void func() \
+ ACCUMULATE void func() \
{ \
otherfunc(); \
}
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';
}
}
#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
// 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
{
#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) \
// 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); \
} \
#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)
}
/// 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
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);
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;
}
#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)
#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__); \
#ifdef SVQC
const int MSG_ENTITY = 5;
- .int Version; // deprecated, use SendFlags
.int SendFlags;
IntrusiveList g_uncustomizables;
{
if (g_buf == "") return;
localcmd("\ncmd c2s \"", strreplace("$", "$$", g_buf), "\"\n");
- strunzone(g_buf);
- g_buf = string_null;
+ strfree(g_buf);
}
#endif
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()
ydec_single(g_buf, ret);
return ret;
}
+ int ReadShort()
+ {
+ return (ReadByte() << 8) | (ReadByte());
+ }
void WriteByte(int to, int b);
#endif
// 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)
#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 */
#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) */
#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; \
}
// Classes have a `spawn##cname(entity)` constructor
-// The parameter is used across [[accumulate]] functions
+// The parameter is used across ACCUMULATE functions
.bool transmute;
} \
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;
} \
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))
--- /dev/null
+#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
--- /dev/null
+#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
*/
#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))
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
#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);
#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); }, , )
// 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
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();
}
#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;
#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; \
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) { \
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) \
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) \
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) \
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) \
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) \
}
#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()
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)) \
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); \
/** 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)
#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)
{
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)
{
/** 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; \
} \
{
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;
}
{
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;
}
{
// an ERROR
e.url_ready(e, e.url_ready_pass, -fabs(status));
- strunzone(e.url_url);
+ strfree(e.url_url);
delete(e);
return 1;
}
{
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;
}
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;
}
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;
}
// 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);
}
}
{
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;
}
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;
}
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)
{
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)
{
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;
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)
{
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)
{
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)
{
#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>
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
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))
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;
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));
#include "../menu.qh"
#include "../item.qh"
-#include "../mutators/events.qh"
+#include <menu/mutators/_mod.qh>
#include <common/command/_mod.qh>
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();
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)
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))
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));
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)
{
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));
}
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
{
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));
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)
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)
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));
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)
{
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));
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;
}
}
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();
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));
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)
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));
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)
{
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));
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');
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
{
// 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))
{
menuTooltipOrigin.x = -1; // unallocated
- if (menuTooltipText) strunzone(menuTooltipText);
- menuTooltipText = strzone(gettooltip());
+ strcpy(menuTooltipText, gettooltip());
int i = 0;
float w = 0;
if (menuTooltipItem == NULL)
{
- if (menuTooltipText)
- {
- strunzone(menuTooltipText);
- menuTooltipText = string_null;
- }
+ strfree(menuTooltipText);
return;
}
else
{
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
// generated file; do not modify
+#include <menu/mutators/events.qc>
// generated file; do not modify
+#include <menu/mutators/events.qh>
--- /dev/null
+#include "events.qh"
#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;
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
#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>
#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>
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)
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);
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
#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);
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)
#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));
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);
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);
void DemoList_Filter_Change(entity box, entity me)
{
- if(me.filterString)
- strunzone(me.filterString);
+ strfree(me.filterString);
if(box.text != "")
{
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:")));
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);
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);
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);
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:")));
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);
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:")));
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);
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")));
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);
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:")));
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);
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:")));
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)
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);
}
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);
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:")));
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);
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")));
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);
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")));
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);
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);
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);
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:")));
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)
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);
}
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);
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:")));
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);
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:")));
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);
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:")));
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);
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:")));
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);
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);
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);
// 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);
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);
string WeaponArenaString()
{
string s;
- float n, i;
+ float n;
s = cvar_string("g_weaponarena");
if(s == "0")
return "";
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)
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;
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"),
_("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);
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:")));
#include "textlabel.qh"
#include "inputbox.qh"
#include "checkbox.qh"
+#include "commandbutton.qh"
#include "button.qh"
entity makeXonoticServerListTab()
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;
// ====================================
// 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
{
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)
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);
}
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");
{
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");
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);
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);
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);
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);
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);
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))
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));
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);
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);
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;
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);
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");
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");
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");
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"))
{
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 != "")
{
else
me.filterString = strzone(strcat("*", box.text, "*"));
}
- else
- me.filterString = string_null;
me.getHUDSkins(me);
}
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"));
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;
}
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);
#include "mainwindow.qh"
-#include "../mutators/events.qh"
+#include <menu/mutators/_mod.qh>
#include "nexposee.qh"
#include "inputbox.qh"
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);
);
}
}
- me.g_maplistCache = strzone(s);
+ strcpy(me.g_maplistCache, s);
if(gt != me.lastGametype || f != me.lastFeatures)
{
me.lastGametype = gt;
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);
}
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))
{
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)
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)
#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));
{
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')
{
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)
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));
void ScreenshotList_Filter_Change(entity box, entity me)
{
- if(me.filterString)
- strunzone(me.filterString);
+ strfree(me.filterString);
if(box.text != "")
{
else
me.filterString = strzone(strcat("*", box.text, "*"));
}
- else
- me.filterString = string_null;
ScreenshotList_Refresh_Click(NULL, me);
}
--- /dev/null
+#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
--- /dev/null
+#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)
} } \
if(catnum) \
{ \
- strunzone(categories[i].override_string); \
- categories[i].override_string = string_null; \
+ strfree(categories[i].override_string); \
categories[i].override_field = catnum; \
continue; \
} \
); \
} \
} \
- 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)
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);
}
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)
{
{
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;
}
// 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));
}
}
}
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, "");
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)
}
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)
{
}
}
- if(isSelected)
+ if(isSelected && !me.lockedSelectedItem)
draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);
else if(isFocused)
{
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));
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);
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);
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");
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();
}
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);
}
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;
}
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;
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;
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;
}
case "favorite-map":
{
order = 5;
- outstr = sprintf(_("%s_Favorite_Map:"), strtoupper(gametype));
- //data = sprintf(_("%d (unranked)"), data);
+ outstr = _("Favorite map:");
break;
}
#endif
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
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);
}
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);
}
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);
#include "util.qh"
+#include "dialog.qh"
#include "../item.qh"
theTooltip = string_null;
}
- if(e.tooltip)
- strunzone(e.tooltip);
+ strfree(e.tooltip);
e.tooltip = (theTooltip != "") ? strzone(theTooltip) : string_null;
}
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)
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;
}
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"));
}
}
.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;
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"), "");
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);
}
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)
{
#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>
#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>
#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>
#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>
#include <server/defs.qh>
#include <common/state.qh>
#include <common/vehicles/all.qh>
+ #include <lib/warpzone/common.qh>
#include "antilag.qh"
#endif
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);
+}
#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);
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;
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;
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;
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;
//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;
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;
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;
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;
#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,
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;
#include "../../race.qh"
#include <common/t_items.qh>
-#include "../../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
#include "../../weapons/accuracy.qh"
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';
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
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)
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;
#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>
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))
{
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;
// 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)
{
{
// 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;
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)
{
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
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)
{
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;
// 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;
#include <server/defs.qh>
#include <server/miscfunctions.qh>
#include <server/items.qh>
+#include <server/resources.qh>
#include "havocbot.qh"
#include "../cvars.qh"
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;
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)
{
#include <common/constants.qh>
#include <common/net_linked.qh>
-#include <common/triggers/trigger/jumppads.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
.float speed;
// 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)
{
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;
//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))
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
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);
}
}
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)
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) != "\'")
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":
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;
});
}
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;
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);
{
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))
{
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;
{
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;
if (sym && wp_sym)
{
e = wp_sym;
- if(order > 2)
- order--;
+ if(wp_num > 2)
+ wp_num--;
else
sym = false;
goto remove_wp;
}
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);
}
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");
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;
});
navigation_testtracewalk = 0;
this.wplinked = true;
+ this.dphitcontentsmask = dphitcontentsmask_save;
}
void waypoint_clearlinks(entity wp)
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;
bool parse_comments = true;
float ver = 0;
+ float sym = 0;
+ float sym_param1 = 0, sym_param2 = 0, sym_param3 = 0;
while ((s = fgets(file)))
{
{
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
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;
}
{
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))
// 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;
{
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");
#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; }
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;
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;
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.");
END_CHEAT_FUNCTION();
}
-void DragBox_Think(entity this);
float drag_lastcnt;
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();
// 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)
{
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)
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)
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);
#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"
#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"
#include "../lib/warpzone/server.qh"
+#include <common/mutators/mutator/overkill/oknex.qh>
+
STATIC_METHOD(Client, Add, void(Client this, int _team))
{
ClientConnect(this);
PutClientInServer(this);
}
-void PutObserverInServer(entity this);
-
STATIC_METHOD(Client, Remove, void(Client this))
{
TRANSMUTE(Observer, 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);
-
/*
=============
UpdatePlayerSounds(e);
}
-void FixPlayermodel(entity player);
/** putting a client as observer in the server */
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);
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;
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;
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)
{
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)
{
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,
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;
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;
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;
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));
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);
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;
}
}
-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)
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');
}
}
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
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;
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;
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);
}
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));
=============
*/
.entity chatbubbleentity;
-void ReadyCount();
void ClientDisconnect(entity this)
{
assert(IS_CLIENT(this), return);
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);
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;
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);
Fire_ApplyDamage(this);
Fire_ApplyEffect(this);
- if (!g_instagib)
+ if (!MUTATOR_IS_ENABLED(mutator_instagib))
{
if (this.items & ITEM_Strength.m_itemid)
{
}
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);
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))
{
else
{
this.superweapons_finished = 0;
- this.weapons &= ~WEPSET_SUPERWEAPONS;
+ STAT(WEAPONS, this) &= ~WEPSET_SUPERWEAPONS;
}
}
else
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))
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;
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;
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;
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;
}
}
+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) {
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)
{
{
.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;
return true;
}
+.bool would_spectate;
void ObserverThink(entity this)
{
if ( CS(this).impulse )
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);
}
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))) {
this.flags |= FL_CLIENT | FL_NOTARGET;
}
-void vehicles_enter (entity pl, entity veh);
void PlayerUseKey(entity this)
{
if (!IS_PLAYER(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
{
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);
}
}
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;
}
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);
}
{ // 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;
}
}
}
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);
}
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);
}
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;
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;
}
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
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); }
#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);
#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>
#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>
#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
}
}
-bool joinAllowed(entity this);
-void Join(entity this);
void ClientCommand_join(entity caller, float request)
{
switch (request)
{
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!
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;
}
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);
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;
}
#include <common/command/_mod.qh>
#include "../g_world.qh"
-#include "../g_subs.qh"
#include <common/util.qh>
#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)
{
}
}
-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)
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;
}
}
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); }
#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>
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;
}
// 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);
{
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");
}
// 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();
}
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":
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;
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");
}
}
void ReadyCount();
void ReadyRestart_force();
void VoteCount(float first_count);
+void Nagger_Init();
#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
//***********************
}
}
+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);
}
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;
#pragma once
+
+bool DoesQ3ARemoveThisEntity(entity this);
#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;
// 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;
// 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;
string gamemode_name;
-float startitem_failed;
-
string W_Apply_Weaponreplace(string in);
void FixIntermissionClient(entity e);
// WEAPONTODO: remove this
//WepSet weaponsInMap;
-#define weapons _STAT(WEAPONS)
-
.float respawn_countdown; // next number to count
float bot_waypoints_for_items;
.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;
// 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)
.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
.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
.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);
.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();
+}
#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"
#include "../common/vehicles/all.qh"
#include "../common/items/_mod.qh"
#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include "../common/mutators/mutator/buffs/buffs.qh"
#include "weapons/accuracy.qh"
#include "weapons/csqcprojectile.qh"
#include "weapons/selection.qh"
#include "../common/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"
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;
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;
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; }
}
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);
}
// ======
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;
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;
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);
}
LogDeath("accident", deathtype, targ, targ);
- GiveFrags(targ, targ, -1, deathtype);
+ GiveFrags(targ, targ, -1, deathtype, weaponentity);
if(GameRules_scoring_add(targ, SCORE, 0) == -5)
{
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))
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;
});
// 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;
}
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);
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;
// 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;
}
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;
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;
}
// 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);
{
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);
}
}
}
}
- if(!g_instagib)
+ if(!MUTATOR_IS_ENABLED(mutator_instagib))
{
// apply strength multiplier
if (attacker.items & ITEM_Strength.m_itemid)
// 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)
// 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)
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;
}
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);
}
}
}
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)
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;
#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>
// 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);
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;
RemoveHook(this);
}
-void GrapplingHookThink(entity this);
void GrapplingHook_Stop(entity this)
{
Send_Effect(EFFECT_HOOK_IMPACT, this.origin, '0 0 0', 1);
}
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;
}
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);
//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)
{
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;
//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
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;
// 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)
+++ /dev/null
-#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;
- }
-}
+++ /dev/null
-#pragma once
+++ /dev/null
-#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)
+++ /dev/null
-#pragma once
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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);
#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"
#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"
#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>
string redirection_target;
float world_initialized;
-string GetGametype();
-void ShuffleMaplist();
-
void SetDefaultAlpha()
{
if (!MUTATOR_CALLHOOK(SetDefaultAlpha))
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();
// 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");
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_");
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)
{
}
}
-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")));
next_pingtime = time + 5;
- detect_maptype();
-
// set up information replies for clients and server to use
maplist_reply = strzone(getmaplist());
lsmaps_reply = strzone(getlsmaps());
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;
}
// 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;
return -1;
}
-float() MaplistMethod_Repeat = // fallback method
+float MaplistMethod_Repeat() // fallback method
{
LOG_TRACE("Trying MaplistMethod_Repeat");
return -2;
}
-float() MaplistMethod_Random = // random map selection
+float MaplistMethod_Random() // random map selection
{
float i, imax;
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
{
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
}
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)
{
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
return true;
}
-void TargetMusic_RestoreGame();
void RestoreGame()
{
// Loaded from a save game
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();
#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;
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));
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);
#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"
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.
}
settouch(this, item_key_touch);
-};
+}
/*QUAKED item_key (0 .5 .8) (-16 -16 -24) (16 16 32) FLOATING
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.
this.classname = "item_key";
this.itemkeys = ITEM_KEY_BIT(0);
spawnfunc_item_key(this);
-};
+}
/// 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();
/// \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.
/// \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.
{
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]);
}
}
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;
#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>
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)
{
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;
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;
{
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
string s = func(this, strcat1(store.(field)));
if (s != store.(field))
{
- strunzone(store.(field));
- store.(field) = strzone(s);
+ strcpy(store.(field), s);
}
}
}
}
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;
}
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
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;
#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))
#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>
#define cvar_set_normal builtin_cvar_set
.vector dropped_origin;
-.float nottargeted;
entity eliminatedPlayers;
void EliminatedPlayers_Init(float(entity) isEliminated_func);
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();
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;
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");
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");
// generated file; do not modify
+#include <server/mutators/events.qc>
#include <server/mutators/loader.qc>
-
-#include <server/mutators/mutator/_mod.inc>
// generated file; do not modify
+#include <server/mutators/events.qh>
#include <server/mutators/loader.qh>
-
-#include <server/mutators/mutator/_mod.qh>
--- /dev/null
+#include "events.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 player becomes observer, after shared setup */
#define EV_MakePlayerObserver(i, o) \
/** player */ i(entity, MUTATOR_ARGV_0_entity) \
/**/
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) \
/** 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);
/**/
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) \
/** 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);
#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);
/**/
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) \
/**/
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) \
/**/
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);
+++ /dev/null
-#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);
+++ /dev/null
-#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>
+++ /dev/null
-// 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>
+++ /dev/null
-// 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>
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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);
+++ /dev/null
-#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";
-}
+++ /dev/null
-#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
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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;
+++ /dev/null
-#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();
-}
+++ /dev/null
-#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;
+++ /dev/null
-#include "gamemode_deathmatch.qh"
-
-MUTATOR_HOOKFUNCTION(dm, Scores_CountFragsRemaining)
-{
- // announce remaining frags
- return true;
-}
+++ /dev/null
-#pragma once
-
-#include "../gamemode.qh"
-
-REGISTER_MUTATOR(dm, false)
-{
- MUTATOR_STATIC();
- return 0;
-}
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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(); }
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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;
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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
+++ /dev/null
-#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();
-}
+++ /dev/null
-#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);
+++ /dev/null
-#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
-}
+++ /dev/null
-#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);
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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();
+++ /dev/null
-#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);
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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;
-}
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)
#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
}
#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
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;
#include "cheats.qh"
#include "g_damage.qh"
#include "handicap.qh"
-#include "g_subs.qh"
#include "miscfunctions.qh"
#include "portals.qh"
#include "teamplay.qh"
#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"
#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"
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;
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;
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;
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);
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;
void calculate_player_respawn_time(entity this)
{
- if(g_ca)
+ if(MUTATOR_CALLHOOK(CalculateRespawnTime, this))
return;
float gametype_setting_tmp;
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))
{
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;
}
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))
{
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);
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);
// 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);
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))
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);
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;
// 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);
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);
}
// 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
// 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);
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);
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
}
}
+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
{
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:
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
}
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.
/// \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);
+++ /dev/null
-#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;
-}
+++ /dev/null
-#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);
#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"
// 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;
}
toucher.effects += EF_BLUE - EF_RED;
}
-void Portal_Think(entity this);
void Portal_MakeBrokenPortal(entity portal)
{
portal.skin = 2;
}
}
-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);
}
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);
vector Portal_ApplyTransformToPlayerAngle(vector transform, vector vangle);
void Portal_ClearAll_PortalsOnly(entity own);
+
+void Portal_Think(entity this);
#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"
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));
const float MAX_CHECKPOINTS = 255;
-spawnfunc(target_checkpoint);
-
.float race_penalty;
.float race_penalty_accumulator;
.string race_penalty_reason;
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);
}
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)
{
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)
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); });
}
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');
}
}
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;
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, {
// scores
const float ST_RACE_LAPS = 1;
+int autocvar_g_cts_send_rankings_cnt = 15;
+
bool g_race_qualifying;
float speedaward_lastsent;
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);
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)
{
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);
}
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;
}
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)
#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.
/// \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).
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.
#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];
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;
});
if (result.x == 0 && strict)
- result.x = etof(t1.owner) - etof(t2.owner);
+ result.x = t1.owner.playerid - t2.owner.playerid;
return result.x;
}
}
}
- if(worldstatus)
- strunzone(worldstatus);
- worldstatus = strzone(s);
+ strcpy(worldstatus, s);
FOREACH_CLIENT(true, {
string s = "";
s = "-666";
}
- if(it.clientstatus)
- strunzone(it.clientstatus);
- it.clientstatus = strzone(s);
+ strcpy(it.clientstatus, s);
});
}
*/
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.
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));
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()
{
#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;
}
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)) )
// _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)
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;
});
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;
// 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)
**/
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);
}
**/
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;
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
-
-
-
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(); }
#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"
#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"
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
{
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);
}
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');
}
}
}
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');
}
}
bool game_delay_last;
bool autocvar_sv_autopause = false;
-float RedirectionThink();
void systems_update();
void sys_phys_update(entity this, float dt);
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] ...
}
return;
LABEL(cleanup)
- builtin_remove(this);
+ delete(this);
}
void WarpZone_PostInitialize_Callback()
}
delete(tracetest_ent);
}
+
+/*
+==================
+main
+
+unused but required by the engine
+==================
+*/
+void main ()
+{
+
+}
#pragma once
bool expr_evaluate(string s);
+
+/*
+==================
+main
+
+unused but required by the engine
+==================
+*/
+void main ();
#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)
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");
}
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)
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 != "") {
{
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');
}
void test_weapons_hurt(entity this)
{
- EXPECT_NE(100, this.health);
+ EXPECT_NE(100, GetResourceAmount(this, RESOURCE_HEALTH));
delete(this.enemy);
delete(this);
}
#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>
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
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;
#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);
#pragma once
+bool W_DualWielding(entity player);
void W_GiveWeapon (entity e, float wep);
.float prevstrengthsound;
.float prevstrengthsoundattempt;
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);
}
#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>
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)
{
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"));
}
}
.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);
// 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)
}
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)
{
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;
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;
// 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
{
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);
}
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);
}
#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>
}
}
+ if (!Item_IsDefinitionAllowed(wpn.m_pickup))
+ {
+ delete(this);
+ startitem_failed = true;
+ return;
+ }
+
if (!this.respawntime)
{
if (wpn.spawnflags & WEP_FLAG_SUPERWEAPON)
#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>
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)
{
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
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);
{
//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);
}
#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;
// 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');
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;
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);
}
// 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);
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);
// 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);
#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>
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
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;
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);
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;
// 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;
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);
}
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
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))
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() {
--- /dev/null
+// 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."
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."
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."
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."
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."
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
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."
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."
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."
--- /dev/null
+// ================
+// 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
--- /dev/null
+// ==================
+// 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
--- /dev/null
+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
--- /dev/null
+// ==============
+// 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
--- /dev/null
+exec xonotic-server.cfg
--- /dev/null
+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
+ }
+
+}
+
+
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"
--- /dev/null
+// 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."
--- /dev/null
+// 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"
--- /dev/null
+// 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"