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=eb10d49149a894afd1c3e8af610dc98f
+ - EXPECT=033546d32426e6409458fb39d0130f56
- 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 ..
-Fri Mar 2 07:24:40 CET 2018
+Sun Jun 3 07:24:16 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 ${* ?}"
// {{{ #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_animtime 0.2
set g_balance_crylink_secondary_bouncedamagefactor 0.5
set g_balance_crylink_secondary_bounces 0
-set g_balance_crylink_secondary_damage 10
-set g_balance_crylink_secondary_edgedamage 5
-set g_balance_crylink_secondary_force -250
+set g_balance_crylink_secondary_damage 8
+set g_balance_crylink_secondary_edgedamage 4
+set g_balance_crylink_secondary_force -200
set g_balance_crylink_secondary_joindelay 0
set g_balance_crylink_secondary_joinexplode 0
set g_balance_crylink_secondary_joinexplode_damage 0
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_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_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_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_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 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 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 2
+set g_pickup_respawntime_initial_random 1
set g_pickup_respawntimejitter_short 0
set g_pickup_respawntimejitter_medium 0
set g_pickup_respawntimejitter_long 0
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 1
+set g_balance_powerup_invincible_takeforce 0.33
set g_balance_powerup_invincible_time 30
set g_balance_powerup_strength_damage 3
set g_balance_powerup_strength_force 3
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
// }}}
// {{{ 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
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} \
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)"
# Martin Taibr <taibr.martin@gmail.com>, 2017
# Martin Taibr <taibr.martin@gmail.com>, 2017
# NONE <nechtom@gmail.com>, 2015
-# Tomáš Volavka <czheron@gmail.com>, 2015
+# Tomáš Volavka <czheron@gmail.com>, 2015,2018
# Tomáš Volavka <czheron@gmail.com>, 2015
msgid ""
msgstr ""
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 23:01+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-05-13 08:23+0000\n"
+"Last-Translator: Tomáš Volavka <czheron@gmail.com>\n"
"Language-Team: Czech (http://www.transifex.com/team-xonotic/xonotic/language/"
"cs/)\n"
"Language: cs\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+"Plural-Forms: nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n "
+"<= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;\n"
#: qcsrc/client/hud/hud_config.qc:239
#, c-format
#: 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
# 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
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 19:54+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-05-11 21:48+0000\n"
+"Last-Translator: starfire24680 <starfire24680@gmail.com>\n"
"Language-Team: Spanish (http://www.transifex.com/team-xonotic/xonotic/"
"language/es/)\n"
"Language: es\n"
#: 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: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: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)"
"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
"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
# This file is distributed under the same license as the PACKAGE package.
#
# Translators:
-# Nicky Rowe <nickyrowe@gmail.com>, 2016
+# Nicky Rowe <nicky@kernowlingo.com>, 2016,2018
+# Nicky Rowe <nicky@kernowlingo.com>, 2016
+# Nicky Rowe <nicky@kernowlingo.com>, 2016
msgid ""
msgstr ""
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-22 11:16+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-04-28 07:53+0000\n"
+"Last-Translator: Nicky Rowe <nicky@kernowlingo.com>\n"
"Language-Team: Cornish (http://www.transifex.com/team-xonotic/xonotic/"
"language/kw/)\n"
"Language: kw\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : "
-"3;\n"
+"Plural-Forms: nplurals=3; plural=(n == 1 ? 0 : n == 2 ? 1 : 2);\n"
#: qcsrc/client/hud/hud_config.qc:239
#, c-format
#: 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: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
--- /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"
# Kriss Chr <kriss7475@gmail.com>, 2017
# Piotr Kozica <koza91@gmail.com>, 2016
# Rafał Szymański <okavasly@gmail.com>, 2017
-# Robert Wolniak <robert.wolniak@gmail.com>, 2015
+# Robert Wolniak <robert.wolniak@gmail.com>, 2015,2018
# Sertomas, 2014
msgid ""
msgstr ""
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-20 00:10+0000\n"
-"Last-Translator: Rafał Szymański <okavasly@gmail.com>\n"
+"PO-Revision-Date: 2018-04-19 09:01+0000\n"
+"Last-Translator: Robert Wolniak <robert.wolniak@gmail.com>\n"
"Language-Team: Polish (http://www.transifex.com/team-xonotic/xonotic/"
"language/pl/)\n"
"Language: pl\n"
#: 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
#
# Translators:
# Ivan Paulos Tomé <greylica@gmail.com>, 2016
-# Jean Trindade Pereira <jean_trindade2@hotmail.com>, 2015-2017
+# Jean Trindade Pereira <jean_trindade2@hotmail.com>, 2015-2018
# Mirio <opivy@hotmail.de>, 2017
# NotThatPrivate Yes <henriqueferreira2009@gmail.com>, 2015
# Ricardo Manuel da Cruz Coelho da Silva <ricardo.mccs@gmail.com>, 2015
+# Rui <xymarior@yandex.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-12-21 15:23+0000\n"
-"Last-Translator: Jean Trindade Pereira <jean_trindade2@hotmail.com>\n"
+"PO-Revision-Date: 2018-05-02 10:54+0000\n"
+"Last-Translator: Rui <xymarior@yandex.com>\n"
"Language-Team: Portuguese (http://www.transifex.com/team-xonotic/xonotic/"
"language/pt/)\n"
"Language: pt\n"
#: qcsrc/client/hud/hud_config.qc:239
#, c-format
msgid "^2Successfully exported to %s! (Note: It's saved in data/data/)\n"
-msgstr "^2Exportado com sucesso para %s! (Nota: Foi salvo em data/data/)\n"
+msgstr "^2Exportado com sucesso para %s! (Nota: foi gravado em data/data/)\n"
#: qcsrc/client/hud/hud_config.qc:243
#, c-format
msgid "^1Couldn't write to %s\n"
-msgstr "^1Não foi possível escrever para %s\n"
+msgstr "^1Não foi possível gravar para %s\n"
#: qcsrc/client/hud/panel/chat.qc:82
msgid "^3Player^7: This is the chat area."
-msgstr "^3Jogador^7: Isto é a área do bate-papo."
+msgstr "^3Jogador^7: isto é a área doe conversação."
#: qcsrc/client/hud/panel/engineinfo.qc:69
#, c-format
#: qcsrc/client/hud/panel/infomessages.qc:100
#, c-format
msgid "^1Press ^3%s^1 to spectate"
-msgstr "^1Aperte ^3%s^1 para assistir"
+msgstr "^1Pressionar ^3%s^1 para assistir"
#: qcsrc/client/hud/panel/infomessages.qc:100
#: qcsrc/menu/xonotic/keybinder.qc:40
#: qcsrc/client/hud/panel/infomessages.qc:102
#, c-format
msgid "^1Press ^3%s^1 or ^3%s^1 for next or previous player"
-msgstr "^1Aperte ^3%s^1 ou ^3%s^1 para o jogador seguinte ou anterior"
+msgstr "^1Pressionar ^3%s^1 ou ^3%s^1 para o jogador seguinte ou anterior"
#: qcsrc/client/hud/panel/infomessages.qc:102
#: qcsrc/client/hud/panel/infomessages.qc:106
#: qcsrc/client/hud/panel/infomessages.qc:106
#, c-format
msgid "^1Use ^3%s^1 or ^3%s^1 to change the speed"
-msgstr "^1Use ^3%s^1 ou ^3%s^1 para alterar a velocidade"
+msgstr "^1Usar ^3%s^1 ou ^3%s^1 para alterar a velocidade"
#: qcsrc/client/hud/panel/infomessages.qc:108
#, c-format
msgid "^1Press ^3%s^1 to observe, ^3%s^1 to change camera mode"
-msgstr "^1Aperte ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmera"
+msgstr ""
+"^1Pressionar ^3%s^1 para observar e ^3%s^1 para alterar o modo da câmara"
#: qcsrc/client/hud/panel/infomessages.qc:108
#: qcsrc/common/vehicles/cl_vehicles.qc:192
#: qcsrc/client/hud/panel/infomessages.qc:111
#, c-format
msgid "^1Press ^3%s^1 for gamemode info"
-msgstr "^1Aperte ^3%s^1 para ver as informações do modo de jogo"
+msgstr "^1Pressionar ^3%s^1 para ver as informações do modo de jogo"
#: qcsrc/client/hud/panel/infomessages.qc:111
#: qcsrc/menu/xonotic/keybinder.qc:94
#: qcsrc/client/hud/panel/infomessages.qc:126
msgid "^1You have no more lives left"
-msgstr "^1Você não tem mais vidas sobrando"
+msgstr "^1Não tens mais vidas"
#: qcsrc/client/hud/panel/infomessages.qc:128
#: qcsrc/client/hud/panel/infomessages.qc:131
#, c-format
msgid "^1Press ^3%s^1 to join"
-msgstr "^1Aperte ^3%s^1 para entrar no jogo"
+msgstr "^1Pressionar ^3%s^1 para entrar no jogo"
#: qcsrc/client/hud/panel/infomessages.qc:128
#: qcsrc/client/hud/panel/infomessages.qc:131
#: qcsrc/client/hud/panel/infomessages.qc:139
#, c-format
msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1A partida iniciará em ^3%d^1 segundo(s)"
+msgstr "^1O jogo vai começar em ^3%d^1 segundo(s)"
#: qcsrc/client/hud/panel/infomessages.qc:145
msgid "^2Currently in ^1warmup^2 stage!"
-msgstr "^2Atualmente em fase de ^1aquecimento^2!"
+msgstr "^2Neste momento em fase de ^1aquecimento^2!"
#: qcsrc/client/hud/panel/infomessages.qc:160
#, c-format
msgid "%sPress ^3%s%s to end warmup"
-msgstr "%sAperte ^3%s%s para terminar o aquecimento"
+msgstr "%sPressionar ^3%s%s para terminar o aquecimento"
#: qcsrc/client/hud/panel/infomessages.qc:160
#: qcsrc/client/hud/panel/infomessages.qc:162
#: qcsrc/client/hud/panel/infomessages.qc:162
#, c-format
msgid "%sPress ^3%s%s once you are ready"
-msgstr "%sAperte ^3%s%s assim que estiver pronto"
+msgstr "%sPressionar ^3%s%s assim que estiveres pronto"
#: qcsrc/client/hud/panel/infomessages.qc:167
msgid "^2Waiting for others to ready up to end warmup..."
msgstr ""
-"^2Esperando que os outros jogadores estejam prontos para acabar o "
+"^2Á espera que os outros jogadores estejam prontos para acabar o "
"aquecimento..."
#: qcsrc/client/hud/panel/infomessages.qc:169
msgid "^2Waiting for others to ready up..."
-msgstr "^2Esperando que os outros jogadores estejam prontos..."
+msgstr "^2À espera que os outros jogadores estejam prontos..."
#: qcsrc/client/hud/panel/infomessages.qc:175
#, c-format
msgid "^2Press ^3%s^2 to end warmup"
-msgstr "^2Aperte ^3%s^2 para terminar o aquecimento"
+msgstr "^2Pressionar ^3%s^2 para terminar o aquecimento"
#: qcsrc/client/hud/panel/infomessages.qc:196
msgid "Teamnumbers are unbalanced!"
-msgstr "As equipes estão desequilibradas!"
+msgstr "As equipas estão desequilibradas!"
#: qcsrc/client/hud/panel/infomessages.qc:199
#, c-format
msgid " Press ^3%s%s to adjust"
-msgstr " Aperte ^3%s%s para ajustar"
+msgstr " Pressiona ^3%s%s para ajustar"
#: qcsrc/client/hud/panel/infomessages.qc:199
#: qcsrc/menu/xonotic/keybinder.qc:102
msgid "team menu"
-msgstr "menu de equipe"
+msgstr "menu de equipa"
#: qcsrc/client/hud/panel/infomessages.qc:209
msgid "^1Spectating this player:"
-msgstr "^1Também estão assistindo a este jogador:"
+msgstr "^1A assistir este jogador:"
#: qcsrc/client/hud/panel/infomessages.qc:209
msgid "^1Spectating you:"
-msgstr "^1Assistindo você:"
+msgstr "^1A assistir a ti:"
#: qcsrc/client/hud/panel/infomessages.qc:225
msgid "^7Press ^3ESC ^7to show HUD options."
-msgstr "^7Aperte ^3ESC ^7para exibir as opções de HUD."
+msgstr "^7Pressionar ^3ESC ^7para mostrar as opções de interface."
#: qcsrc/client/hud/panel/infomessages.qc:226
msgid "^3Doubleclick ^7a panel for panel-specific options."
msgstr ""
-"^3Clique duas vezes ^7em um painel para abrir sua janela de opções "
-"específicas."
+"^3Clica duas vezes ^7num painel para abrir a janela de opções específicas."
#: qcsrc/client/hud/panel/infomessages.qc:227
msgid "^3CTRL ^7to disable collision testing, ^3SHIFT ^7and"
-msgstr "^3CTRL ^7para desligar teste de colisão, ^3SHIFT ^7e"
+msgstr "^3CTRL ^7para desativar o teste de colisão, ^3SHIFT ^7e"
#: qcsrc/client/hud/panel/infomessages.qc:228
msgid "^3ALT ^7+ ^3ARROW KEYS ^7for fine adjustments."
#: 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:797
msgid "QMCMD^hi / good luck and have fun"
-msgstr "Olá / Boa sorte e divirta-se"
+msgstr "Olá / Boa sorte e diverte-te"
#: qcsrc/client/hud/panel/quickmenu.qc:802
#: qcsrc/client/hud/panel/quickmenu.qc:818
msgid "QMCMD^Team chat"
-msgstr "Bate-papo de equipe"
+msgstr "Conversação da equipa"
#: qcsrc/client/hud/panel/quickmenu.qc:803
msgid "QMCMD^quad soon"
#: 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:816
msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr "Arma solta %w^7 (l:%l^7)"
+msgstr "Arma largada %w^7 (l:%l^7)"
#: qcsrc/client/hud/panel/quickmenu.qc:817
msgid "QMCMD^drop flag/key, icon"
#: 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 bate-papo"
+msgstr "Som da conversação"
#: qcsrc/client/hud/panel/quickmenu.qc:840
#: qcsrc/client/hud/panel/quickmenu.qc:844
msgid "QMCMD^Spectator camera"
-msgstr "Câmera de espectador"
+msgstr "Câmara de espetador"
#: qcsrc/client/hud/panel/quickmenu.qc:841
msgid "QMCMD^1st person"
#: 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 do bate-papo"
+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"
"^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"
"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:1698
#, c-format
msgid "You are dead, wait ^3%s^7 before respawning"
-msgstr "Você morreu. Espere ^3%s^7 antes de ressurgir"
+msgstr "Morreste. Espera ^3%s^7 antes de ressurgir"
#: qcsrc/client/hud/panel/scoreboard.qc:1707
#, c-format
msgid "You are dead, press ^2%s^7 to respawn"
-msgstr "Você morreu. Aperte ^2%s^7 para ressurgir"
+msgstr "Morreste. Pressiona ^2%s^7 para ressurgir"
#: qcsrc/client/hud/panel/vote.qc:24
msgid "^1You must answer before entering hud configure mode\n"
msgstr ""
-"^1Você tem que responder antes de entrar no modo de configuração do HUD\n"
+"^1Tens que responder antes de entrar no modo de configuração da interface\n"
#: qcsrc/client/hud/panel/vote.qc:29
msgid "^2Name ^7instead of \"^1Anonymous player^7\" in stats"
-msgstr "^2Nome ^7em vez de \"^1Jogador anônimo^7\" nas estatísticas"
+msgstr "^2Nome ^7em vez de \"^1Jogador anónimo^7\" nas estatísticas"
#: qcsrc/client/hud/panel/vote.qc:115
msgid "A vote has been called for:"
-msgstr "Uma votação foi iniciada para:"
+msgstr "Foi iniciada uma votação para:"
#: qcsrc/client/hud/panel/vote.qc:117
msgid "Allow servers to store and display your name?"
-msgstr "Permitir que servidores armazenem e mostrem o seu nome?"
+msgstr "Permitir que os servidores armazenem e mostrem o teu nome?"
#: qcsrc/client/hud/panel/vote.qc:121
msgid "^1Configure the HUD"
-msgstr "^1Configurar o HUD"
+msgstr "^1Configurar a Interface"
#: qcsrc/client/hud/panel/vote.qc:125 qcsrc/menu/xonotic/dialog_firstrun.qc:82
#: qcsrc/menu/xonotic/dialog_multiplayer_media_demo_startconfirm.qc:18
#: 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"
#: qcsrc/common/mapinfo.qh:99
msgid "Score as many frags as you can"
-msgstr "Consiga o máximo de execuções que puder"
+msgstr "Consegue o máximo de execuções que puderes"
#: qcsrc/common/mapinfo.qh:111
msgid "Last Man Standing"
-msgstr "Last Man Standing"
+msgstr "Último Homem de Pé"
#: qcsrc/common/mapinfo.qh:111
msgid "Survive and kill until the enemies have no lives left"
-msgstr "Sobreviva e mate até que os inimigos não tenham vidas sobrando"
+msgstr "Sobrevive e mata até que os inimigos não tenham mais vidas"
#: qcsrc/common/mapinfo.qh:126
msgid "Race"
#: 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"
#: qcsrc/common/mapinfo.qh:160
msgid "Race for fastest time."
-msgstr "Corra pelo melhor tempo."
+msgstr "Corre pelo melhor tempo."
#: qcsrc/common/mapinfo.qh:184
msgid "Help your team score the most frags against the enemy team"
-msgstr "Ajude sua equipe a conseguir mais execuções do que a equipe inimiga"
+msgstr ""
+"Ajuda a tua equipa a conseguir mais execuções do que a equipa do inimigo"
#: qcsrc/common/mapinfo.qh:184
msgid "Team Deathmatch"
-msgstr "Mata-mata por Equipe"
+msgstr "Mata-mata por Equipa"
#: qcsrc/common/mapinfo.qh:220
msgid "Capture the Flag"
-msgstr "Capture a Bandeira"
+msgstr "Captura a Bandeira"
#: qcsrc/common/mapinfo.qh:220
msgid ""
"Find and bring the enemy flag to your base to capture it, defend your base "
"from the other team"
msgstr ""
-"Encontre e retorne a bandeira inimiga à sua base para capturá-la e defenda "
-"sua base da equipe oponente"
+"Encontra e retorna a bandeira inimiga à tua base para capturá-la e defende a "
+"tua base da equipa oponente"
#: qcsrc/common/mapinfo.qh:249
msgid "Clan Arena"
-msgstr "Clan Arena"
+msgstr "Clã Arena"
#: qcsrc/common/mapinfo.qh:249
msgid "Kill all enemy teammates to win the round"
-msgstr "Mate todos os inimigos para vencer a rodada"
+msgstr "Mata todos os inimigos para vencer a rodada"
#: qcsrc/common/mapinfo.qh:287
msgid "Capture and defend all the control points to win"
-msgstr "Capture e defenda todos os pontos de controle para vencer"
+msgstr "Captura e defende todos os pontos de controlo para vencer"
#: qcsrc/common/mapinfo.qh:287
msgid "Domination"
-msgstr "Domination"
+msgstr "Dominação"
#: qcsrc/common/mapinfo.qh:319
msgid "Gather all the keys to win the round"
-msgstr "Colete todas as chaves para vencer a rodada"
+msgstr "Recolhe todas as chaves para vencer a rodada"
#: qcsrc/common/mapinfo.qh:319
msgid "Key Hunt"
-msgstr "Key Hunt"
+msgstr "Caça as Chaves"
#: qcsrc/common/mapinfo.qh:353
msgid "Assault"
-msgstr "Assault"
+msgstr "Assalto"
#: qcsrc/common/mapinfo.qh:353
msgid ""
"Destroy obstacles to find and destroy the enemy power core before time runs "
"out"
msgstr ""
-"Destrua obstáculos para encontrar e destruir o núcleo de poder inimigo antes "
+"Destrói obstáculos para encontrar e destruir o núcleo de poder inimigo antes "
"que o tempo acabe"
#: qcsrc/common/mapinfo.qh:371
msgid "Capture control points to reach and destroy the enemy generator"
-msgstr "Capture pontos de controle para alcançar e destruir o gerador inimigo"
+msgstr ""
+"Captura os pontos de controlo para alcançar e destruir o gerador inimigo"
#: qcsrc/common/mapinfo.qh:371
msgid "Onslaught"
-msgstr "Onslaught"
+msgstr "Massacre"
#: qcsrc/common/mapinfo.qh:387
msgid "Nexball"
-msgstr "Nexball"
+msgstr "Bola Nex"
#: qcsrc/common/mapinfo.qh:387
msgid "Shoot and kick the ball into the enemies goal, keep your goal clean"
-msgstr "Atire e chute a bola no gol inimigo e mantenha seu gol limpo"
+msgstr "Atira e chuta a bola na baliza do inimigo e mantém a tua baliza limpa"
#: qcsrc/common/mapinfo.qh:408
msgid "Freeze Tag"
-msgstr "Freeze Tag"
+msgstr "Congela"
#: qcsrc/common/mapinfo.qh:408
msgid ""
"Kill enemies to freeze them, stand next to frozen teammates to revive them; "
"freeze all enemies to win"
msgstr ""
-"Mate inimigos para congelá-los. Fique perto de colegas para descongelá-los; "
-"congele todos os inimigos para vencer"
+"Mata os inimigos para congelá-los. Fica perto de colegas para descongelá-"
+"los; congela todos os inimigos para venceres"
#: qcsrc/common/mapinfo.qh:446
msgid "Hold the ball to get points for kills"
-msgstr "Segure a bola para ganhar pontos por cada jogador aniquilado"
+msgstr "Segura a bola para ganhar pontos por cada jogador aniquilado"
#: qcsrc/common/mapinfo.qh:446
msgid "Keepaway"
-msgstr "Keepaway"
+msgstr ""
#: qcsrc/common/mapinfo.qh:461
msgid "Invasion"
-msgstr "Invasion"
+msgstr "Invasão"
#: qcsrc/common/mapinfo.qh:461
msgid "Survive against waves of monsters"
-msgstr "Sobreviva contra ondas de monstros"
+msgstr "Sobrevive contra ondas de monstros"
#: qcsrc/common/minigames/cl_minigames.qc:383
msgid "It's your turn"
-msgstr "É a sua vez"
+msgstr "É a tua vez"
#: qcsrc/common/minigames/cl_minigames_hud.qc:331
#: qcsrc/menu/xonotic/dialog_quit.qh:6
#: qcsrc/common/minigames/cl_minigames_hud.qc:489
msgid "Minigames"
-msgstr "Minijogos"
+msgstr "Mini-jogos"
#: qcsrc/common/minigames/minigame/bd.qc:1168
msgid "Better luck next time!"
-msgstr "Mais sorte da próxima vez!"
+msgstr "Talvez tenhas mais sorte da próxima vez!"
#: qcsrc/common/minigames/minigame/bd.qc:1172
msgid "Tubular! Press \"Next Level\" to continue!"
-msgstr "Tubular! Clique em \"Próximo Mapa\" para continuar!"
+msgstr "Tubular! Clica em \"Próximo Mapa\" para continuar!"
#: qcsrc/common/minigames/minigame/bd.qc:1174
msgid "Wicked! Press \"Next Level\" to continue!"
-msgstr "Enfeitiçado! Clique em \"Próximo Mapa\" para continuar!"
+msgstr "Enfeitiçado! Clica em \"Próximo Mapa\" para continuar!"
#: qcsrc/common/minigames/minigame/bd.qc:1177
msgid "Press the space bar to change your currently selected tile"
msgstr ""
-"Aperte a barra de espaço para alterar a sua imagem de equipe atualmente "
-"selecionada"
+"Carrega na tecla de barra de espaços para alterar a tua imagem da equipa "
+"atualmente selecionada"
#: qcsrc/common/minigames/minigame/bd.qc:1180
msgid "Push the boulders onto the targets"
-msgstr "Empurre os pedregulhos em direção aos alvos"
+msgstr "Empurra os pedregulhos em direção aos alvos"
#: qcsrc/common/minigames/minigame/bd.qc:1404
msgid "Next Level"
#: 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 ""
-"Aperte ^1Iniciar Partida^7 para iniciar a partida com os jogadores atuais"
+"Pressiona ^1Iniciar Partida^7 para iniciar a partida com os jogadores atuais"
#: qcsrc/common/minigames/minigame/pong.qc:651
msgid "Start Match"
#: 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: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 bate-papo de espectador não serão enviadas aos "
+"^F4NOTA: ^BGas mensagens na conversação de espetador não serão enviadas aos "
"jogadores durante a partida"
#: qcsrc/common/notifications/all.inc:241
"^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
#: 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 "^BGAperte ^F2%s^BG para receber a bandeira de %s^BG"
+msgstr "^BGPressiona ^F2%s^BG para receber a bandeira de %s^BG"
#: qcsrc/common/notifications/all.inc:566
#, c-format
msgid "^BGRequesting %s^BG to pass you the flag"
-msgstr "^BGPedindo à %s^BG para que te passe a bandeira"
+msgstr "^BGA pedir a %s^BG para que te passe a bandeira"
#: qcsrc/common/notifications/all.inc:567
#, c-format
msgid "^BGYou passed the ^TC^TT^BG flag to %s"
-msgstr "^BGVocê passou a bandeira ^TC^TT^BG para %s"
+msgstr "^BGPassaste a bandeira ^TC^TT^BG para %s"
#: qcsrc/common/notifications/all.inc:568
#, c-format
msgid "^BGYou passed the flag to %s"
-msgstr "^BGVocê passou a bandeira para %s"
+msgstr "^BGPassaste a bandeira para %s"
#: qcsrc/common/notifications/all.inc:569
msgid "^BGYou got the ^TC^TT^BG flag!"
-msgstr "^BGVocê pegou a bandeira ^TC^TT^BG!"
+msgstr "^BGApanhaste a bandeira ^TC^TT^BG!"
#: qcsrc/common/notifications/all.inc:570
msgid "^BGYou got the flag!"
-msgstr "^BGVocê pegou a bandeira!"
+msgstr "^BGApanhaste a bandeira!"
#: qcsrc/common/notifications/all.inc:571
#, c-format
msgid "^BGYou got your %steam^BG's flag, return it!"
-msgstr "^BGVocê pegou a bandeira da sua %sequipe^BG, retorne-a!"
+msgstr "^BGApanhaste a bandeira da tua %sequipa^BG, retorna-a!"
#: qcsrc/common/notifications/all.inc:572
#, c-format
msgid "^BGYou got the %senemy^BG's flag, return it!"
-msgstr "^BGVocê pegou a bandeira da %sequipe inimiga^BG, retorne-a!"
+msgstr "^BGApanhaste a bandeira da %sequipa inimiga^BG, retorna-a!"
#: qcsrc/common/notifications/all.inc:573
#, c-format
msgid "^BGThe %senemy^BG got your flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a sua bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a tua bandeira! Recupera-a!"
#: qcsrc/common/notifications/all.inc:574
#, c-format
msgid "^BGThe %senemy (^BG%s%s)^BG got your flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a sua bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a tua bandeira! Recupera-a!"
#: qcsrc/common/notifications/all.inc:575
#, c-format
msgid "^BGThe %senemy^BG got the flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a bandeira! Recupera-a!"
#: qcsrc/common/notifications/all.inc:576
#, c-format
msgid "^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a bandeira! Recupera-a!"
#: qcsrc/common/notifications/all.inc:577
#, c-format
msgid "^BGThe %senemy^BG got their flag! Retrieve it!"
-msgstr "^BGO %sinimigo^BG pegou a bandeira deles! Recupere-a!"
+msgstr "^BGO %sinimigo^BG apanhou a bandeira deles! Recupera-a!"
#: qcsrc/common/notifications/all.inc:578
#, c-format
msgid "^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"
-msgstr "^BGO %sinimigo (^BG%s%s)^BG pegou a bandeira deles! Recupere-a!"
+msgstr "^BGO %sinimigo (^BG%s%s)^BG apanhou a bandeira deles! Recupera-a!"
#: qcsrc/common/notifications/all.inc:579
#, c-format
msgid "^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira ^TC^TT^BG! Proteja-o!"
+msgstr ""
+"^BGO teu %scolega de equipa^BG apanhou a bandeira ^TC^TT^BG! Protege-o!"
#: qcsrc/common/notifications/all.inc:580
#, c-format
msgid "^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"
msgstr ""
-"^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira ^TC^TT^BG! Proteja-"
-"o!"
+"^BGO teu %scolega de equipa (^BG%s%s)^BG apanhou a bandeira ^TC^TT^BG! "
+"Protege-o!"
#: qcsrc/common/notifications/all.inc:581
#, c-format
msgid "^BGYour %steam mate^BG got the flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe^BG pegou a bandeira! Proteja-o!"
+msgstr "^BGO teu %scolega de equipa^BG apanhou a bandeira! Protege-o!"
#: qcsrc/common/notifications/all.inc:582
#, c-format
msgid "^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"
-msgstr "^BGO seu %scolega de equipe (^BG%s%s)^BG pegou a bandeira! Proteja-o!"
+msgstr ""
+"^BGO teu %scolega de equipa (^BG%s%s)^BG apanhou a bandeira! Protege-o!"
#: qcsrc/common/notifications/all.inc:583
msgid "^BGEnemies can now see you on radar!"
-msgstr "^BGAgora os inimigos podem te ver no radar!"
+msgstr "^BGAgora os inimigos podem ver-te no radar!"
#: qcsrc/common/notifications/all.inc:584
msgid "^BGYou returned the ^TC^TT^BG flag!"
-msgstr "^BGVocê retornou a bandeira ^TC^TT^BG!"
+msgstr "^BGRetornaste a bandeira ^TC^TT^BG!"
#: qcsrc/common/notifications/all.inc:585
msgid "^BGStalemate! Enemies can now see you on radar!"
-msgstr "^BGCuidado! Agora os inimigos podem te ver no radar!"
+msgstr "^BGCuidado! Agora os inimigos podem ver-te no radar!"
#: qcsrc/common/notifications/all.inc:586
msgid "^BGStalemate! Flag carriers can now be seen by enemies on radar!"
msgstr ""
-"^BGCuidado! Agora portadores da bandeira podem ser vistos pelos inimigos no "
-"radar!"
+"^BGCuidado! Agora os portadores da bandeira podem ser vistos pelos inimigos "
+"no radar!"
#: qcsrc/common/notifications/all.inc:590
#, c-format
msgid "^K3%sYou fragged ^BG%s"
-msgstr "^K3%sVocê executou ^BG%s"
+msgstr "^K3%sExecutaste ^BG%s"
#: qcsrc/common/notifications/all.inc:591
#: qcsrc/common/notifications/all.inc:600
#: qcsrc/common/notifications/all.inc:609
#, c-format
msgid "^K3%sYou scored against ^BG%s"
-msgstr "^K3%sVocê pontuou contra ^BG%s"
+msgstr "^K3%sPontuaste contra ^BG%s"
#: qcsrc/common/notifications/all.inc:592
#, c-format
msgid "^K1%sYou were fragged by ^BG%s"
-msgstr "^K1%sVocê foi executado por ^BG%s"
+msgstr "^K1%sFoste executado por ^BG%s"
#: qcsrc/common/notifications/all.inc:593
#: qcsrc/common/notifications/all.inc:602
#: qcsrc/common/notifications/all.inc:611
#, c-format
msgid "^K1%sYou were scored against by ^BG%s"
-msgstr "^K1%sVocê foi pontuado contra por ^BG%s"
+msgstr "^K1%sFoste pontuado contra por ^BG%s"
#: qcsrc/common/notifications/all.inc:599
#, c-format
msgid "^K3%sYou burned ^BG%s"
-msgstr "^K3%sVocê queimou ^BG%s"
+msgstr "^K3%sQueimaste ^BG%s"
#: qcsrc/common/notifications/all.inc:601
#, c-format
msgid "^K1%sYou were burned by ^BG%s"
-msgstr "^K1%sVocê foi queimado por ^BG%s"
+msgstr "^K1%sFoste queimado por ^BG%s"
#: qcsrc/common/notifications/all.inc:608
#, c-format
msgid "^K3%sYou froze ^BG%s"
-msgstr "^K3%sVocê congelou ^BG%s"
+msgstr "^K3%sCongelaste ^BG%s"
#: qcsrc/common/notifications/all.inc:610
#, c-format
msgid "^K1%sYou were frozen by ^BG%s"
-msgstr "^K1%sVocê foi congelado por ^BG%s"
+msgstr "^K1%sFoste congelado por ^BG%s"
#: qcsrc/common/notifications/all.inc:617
#, c-format
msgid "^K1%sYou typefragged ^BG%s"
-msgstr "^K1%sVocê executou ^BG%s enquanto digitava"
+msgstr "^K1%sExecutaste ^BG%s enquanto escrevias"
#: qcsrc/common/notifications/all.inc:618
#, c-format
msgid "^K1%sYou scored against ^BG%s^K1 while they were typing"
-msgstr "^K1%sVocê pontuou contra ^BG%s^K1 enquanto estavam digitando"
+msgstr "^K1%sPontuaste contra ^BG%s^K1 enquanto estavam a escrever"
#: qcsrc/common/notifications/all.inc:619
#, c-format
msgid "^K1%sYou were typefragged by ^BG%s"
-msgstr "^K1%sVocê foi executado enquanto digitava por ^BG%s"
+msgstr "^K1%sFoste executado enquanto escrevias por ^BG%s"
#: qcsrc/common/notifications/all.inc:620
#, c-format
msgid "^K1%sYou were scored against by ^BG%s^K1 while typing"
-msgstr "^K1%sVocê foi pontuado contra enquanto digitava por ^BG%s^K1"
+msgstr "^K1%sFoste pontuado contra enquanto escrevias por ^BG%s^K1"
#: qcsrc/common/notifications/all.inc:626
#, c-format
msgid "^BGPress ^F2%s^BG again to toss the nade!"
-msgstr "^BGAperte ^F2%s^BG de novo para lançar a granada!"
+msgstr "^BGPressiona ^F2%s^BG de novo para lançar a granada!"
#: qcsrc/common/notifications/all.inc:627
msgid "^F2You got a ^K1BONUS GRENADE^F2!"
-msgstr "^F2Você pegou uma ^K1GRANADA BÔNUS^F2!"
+msgstr "^F2Apanhaste uma ^K1GRANADA BÓNUS^F2!"
#: qcsrc/common/notifications/all.inc:629
#, c-format
"^BGYou have been moved into a different team\n"
"You are now on: %s"
msgstr ""
-"^BGVocê foi movido para uma equipe diferente\n"
-"Agora você está na equipe: %s"
+"^BGFoste movido para uma equipa diferente\n"
+"Agora estás na equipa: %s"
#: qcsrc/common/notifications/all.inc:630
msgid "^K1Don't go against your team mates!"
-msgstr "^K1Não vá contra seus colegas de equipe!"
+msgstr "^K1Não vás contra os teus colegas de equipa!"
#: qcsrc/common/notifications/all.inc:630
msgid "^K1Don't shoot your team mates!"
-msgstr "^K1Não atire nos seus colegas de equipe!"
+msgstr "^K1Não atires nos teus colegas de equipa!"
#: qcsrc/common/notifications/all.inc:631
msgid "^K1Die camper!"
-msgstr "^K1Morra, camper!"
+msgstr "^K1Morre campista!"
#: qcsrc/common/notifications/all.inc:631
msgid "^K1Reconsider your tactics, camper!"
-msgstr "^K1Reconsidere suas táticas, camper!"
+msgstr "^K1Reconsidera as tuas táticas, campista!"
#: qcsrc/common/notifications/all.inc:632
msgid "^K1You unfairly eliminated yourself!"
-msgstr "^K1Você se matou injustamente!"
+msgstr "^K1Eliminaste-te injustamente!"
#: qcsrc/common/notifications/all.inc:633
#, c-format
msgid "^K1You were %s"
-msgstr "^K1Você foi %s"
+msgstr "^K1Foste %s"
#: qcsrc/common/notifications/all.inc:634
msgid "^K1You couldn't catch your breath!"
-msgstr "^K1Você não recuperou seu fôlego!"
+msgstr "^K1Não recuperaste o fôlego!"
#: qcsrc/common/notifications/all.inc:635
msgid "^K1You hit the ground with a crunch!"
-msgstr "^K1Você caiu no chão rigorosamente!"
+msgstr "^K1Caíste no chão rigorosamente!"
#: qcsrc/common/notifications/all.inc:636
msgid "^K1You felt a little too hot!"
-msgstr "^K1Você se sentiu um pouco quente!"
+msgstr "^K1Sentiste-te um pouco quente!"
#: qcsrc/common/notifications/all.inc:636
msgid "^K1You got a little bit too crispy!"
-msgstr "^K1Você ficou um pouco crocante demais!"
+msgstr "^K1Fiscaste um bocadinho estaladiço!"
#: qcsrc/common/notifications/all.inc:637
msgid "^K1You killed your own dumb self!"
-msgstr "^K1Você se matou, seu burro!"
+msgstr "^K1Mataste-te seu burro!"
#: qcsrc/common/notifications/all.inc:637
msgid "^K1You need to be more careful!"
-msgstr "^K1Você precisa ter mais cuidado!"
+msgstr "^K1tens de ter mais cuidado!"
#: qcsrc/common/notifications/all.inc:638
msgid "^K1You couldn't stand the heat!"
-msgstr "^K1Você não suportou o calor!"
+msgstr "^K1Não suportaste o calor!"
#: qcsrc/common/notifications/all.inc:639
msgid "^K1You need to watch out for monsters!"
-msgstr "^K1Você tem que se cuidar dos monstros!"
+msgstr "^K1Tens de ter um olho nos monstros!"
#: qcsrc/common/notifications/all.inc:639
msgid "^K1You were killed by a monster!"
-msgstr "^K1Você foi morto por um monstro!"
+msgstr "^K1Foste morto por um monstro!"
#: qcsrc/common/notifications/all.inc:640
msgid "^K1Tastes like chicken!"
-msgstr "^K1Tem gosto de frango!"
+msgstr "^K1Sabe a frango!"
#: qcsrc/common/notifications/all.inc:640
msgid "^K1You forgot to put the pin back in!"
-msgstr "^K1Você se esqueceu de pôr o pino de volta!"
+msgstr "^K1Esqueceste-te de tornar a pôr o pino!"
#: qcsrc/common/notifications/all.inc:641
msgid "^K1Hanging around a napalm explosion is bad!"
-msgstr "^K1Brincar no meio de uma explosão de napalm é errado!"
+msgstr "^K1Brincar no meio de uma explosão de napalm é perigoso!"
#: qcsrc/common/notifications/all.inc:642
msgid "^K1You felt a little chilly!"
-msgstr "^K1Você sentiu um pouco de frio!"
+msgstr "^K1Sentiste um pouco de frio!"
#: qcsrc/common/notifications/all.inc:642
msgid "^K1You got a little bit too cold!"
-msgstr "^K1Você ficou um pouco gelado demais!"
+msgstr "^K1Ficaste um pouco gelado!"
#: qcsrc/common/notifications/all.inc:643
msgid "^K1Your Healing Nade is a bit defective"
-msgstr "^K1Sua Granada de Cura está um pouco defeituosa"
+msgstr "^K1A tua Granada de Cura está um pouco defeituosa"
#: qcsrc/common/notifications/all.inc:644
msgid "^K1You are respawning for running out of ammo..."
-msgstr "^K1Você está ressurgindo por ficar sem munição..."
+msgstr "^K1Estás a ressurgir por ficares sem munições..."
#: qcsrc/common/notifications/all.inc:644
msgid "^K1You were killed for running out of ammo..."
-msgstr "^K1Você foi morto por ficar sem munição..."
+msgstr "^K1Foste morto por ficar sem munições..."
#: qcsrc/common/notifications/all.inc:645
msgid "^K1You grew too old without taking your medicine"
-msgstr "^K1Você ficou muito velho sem tomar o seu medicamento"
+msgstr "^K1Ficaste demasiado velho sem tomares o teu medicamento"
#: qcsrc/common/notifications/all.inc:645
msgid "^K1You need to preserve your health"
-msgstr "^K1Você precisa conservar sua saúde"
+msgstr "^K1Tens de conservar a tua saúde"
#: qcsrc/common/notifications/all.inc:646
msgid "^K1You became a shooting star!"
-msgstr "^K1Você virou uma estrela cadente!"
+msgstr "^K1Tornaste-te numa estrela cadente!"
#: qcsrc/common/notifications/all.inc:647
msgid "^K1You melted away in slime!"
-msgstr "^K1Você derreteu na lama!"
+msgstr "^K1Derreteste-te na lama!"
#: qcsrc/common/notifications/all.inc:648
msgid "^K1You committed suicide!"
-msgstr "^K1Você cometeu suicídio!"
+msgstr "^K1Cometeste suicídio!"
#: qcsrc/common/notifications/all.inc:648
msgid "^K1You ended it all!"
-msgstr "^K1Você acabou com tudo!"
+msgstr "^K1Acabaste com tudo!"
#: qcsrc/common/notifications/all.inc:649
msgid "^K1You got stuck in a swamp!"
-msgstr "^K1Você ficou preso em um pântano!"
+msgstr "^K1Ficaste preso num pântano!"
#: qcsrc/common/notifications/all.inc:650
#, c-format
msgid "^BGYou are now on: %s"
-msgstr "^BGVocê está agora em: %s"
+msgstr "^BGEstás agora em: %s"
#: qcsrc/common/notifications/all.inc:651
msgid "^K1You died in an accident!"
-msgstr "^K1Você morreu em um acidente!"
+msgstr "^K1Morreste num acidente!"
#: qcsrc/common/notifications/all.inc:652
msgid "^K1You had an unfortunate run in with a turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela!"
#: qcsrc/common/notifications/all.inc:652
msgid "^K1You were fragged by a turret!"
-msgstr "^K1Você foi executado por uma sentinela!"
+msgstr "^K1Foste executado por uma sentinela!"
#: qcsrc/common/notifications/all.inc:653
msgid "^K1You had an unfortunate run in with an eWheel turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela eWheel!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela eWheel!"
#: qcsrc/common/notifications/all.inc:653
msgid "^K1You were fragged by an eWheel turret!"
-msgstr "^K1Você foi executado por uma sentinela eWheel!"
+msgstr "^K1Foste executado por uma sentinela eWheel!"
#: qcsrc/common/notifications/all.inc:654
msgid "^K1You had an unfortunate run in with a Walker turret!"
-msgstr "^K1Você teve um encontro lamentável com uma sentinela Walker!"
+msgstr "^K1Tiveste um encontro lamentável com uma sentinela Walker!"
#: qcsrc/common/notifications/all.inc:654
msgid "^K1You were fragged by a Walker turret!"
-msgstr "^K1Você foi executado por uma sentinela Walker!"
+msgstr "^K1FOste executado por uma sentinela Walker!"
#: qcsrc/common/notifications/all.inc:655
msgid "^K1You got caught in the blast of a Bumblebee explosion!"
-msgstr "^K1Você foi pego pelo raio de uma explosão de Bumblebee!"
+msgstr "^K1Foste apanhado pelo raio de uma explosão de Bumblebee!"
#: qcsrc/common/notifications/all.inc:656
msgid "^K1You were crushed by a vehicle!"
-msgstr "^K1Você foi esmagado por um veículo!"
+msgstr "^K1Foste esmagado por um veículo!"
#: qcsrc/common/notifications/all.inc:657
msgid "^K1You were caught in a Raptor cluster bomb!"
-msgstr "^K1Você foi pego por uma bomba Raptor!"
+msgstr "^K1Foste apanhado por uma bomba Raptor!"
#: qcsrc/common/notifications/all.inc:658
msgid "^K1You got caught in the blast of a Raptor explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Raptor!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Raptor!"
#: qcsrc/common/notifications/all.inc:659
msgid "^K1You got caught in the blast of a Spiderbot explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Spiderbot!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Robô Aranha!"
#: qcsrc/common/notifications/all.inc:660
msgid "^K1You were blasted to bits by a Spiderbot rocket!"
-msgstr "^K1Você foi despedaçado por um foguete de Spiderbot!"
+msgstr "^K1Foste despedaçado por um míssil de Robô Aranha!"
#: qcsrc/common/notifications/all.inc:661
msgid "^K1You got caught in the blast of a Racer explosion!"
-msgstr "^K1Você foi pego no raio de uma explosão de Racer!"
+msgstr "^K1Foste apanhado no raio de uma explosão de Racer!"
#: qcsrc/common/notifications/all.inc:662
msgid "^K1You couldn't find shelter from a Racer rocket!"
-msgstr "^K1Você não conseguiu escapar do foguete de um Racer!"
+msgstr "^K1Não conseguiste escapar do míssil de um Racer!"
#: qcsrc/common/notifications/all.inc:663
msgid "^K1Watch your step!"
-msgstr "^K1Cuidado onde pisa!"
+msgstr "^K1Cuidado com o que pisas!"
#: qcsrc/common/notifications/all.inc:665
#, c-format
msgid "^K1Moron! You fragged ^BG%s^K1, a team mate!"
-msgstr "^K1Idiota! Você executou ^BG%s^K1, um colega de equipe!"
+msgstr "^K1Idiota! Executaste ^BG%s^K1, um colega de equipa!"
#: qcsrc/common/notifications/all.inc:665
#, c-format
msgid "^K1Moron! You went against ^BG%s^K1, a team mate!"
-msgstr "^K1Idiota! Você foi contra ^BG%s^K1, um colega de equipe!"
+msgstr "^K1Idiota! Foste contra ^BG%s^K1, um colega de equipa!"
#: qcsrc/common/notifications/all.inc:666
#, c-format
msgid "^K1You were fragged by ^BG%s^K1, a team mate"
-msgstr "^K1Você foi executado por ^BG%s^K1, um colega de equipe"
+msgstr "^K1Foste executado por ^BG%s^K1, um colega de equipa"
#: qcsrc/common/notifications/all.inc:666
#, c-format
msgid "^K1You were scored against by ^BG%s^K1, a team mate"
-msgstr "^K1Você foi pontuado contra por ^BG%s^K1, um colega de equipe"
+msgstr "^K1Foste pontuado contra por ^BG%s^K1, um colega de equipa"
#: qcsrc/common/notifications/all.inc:668
msgid ""
"^K1Stop idling!\n"
"^BGDisconnecting in ^COUNT..."
msgstr ""
-"^K1Pare de ficar AFK!\n"
-"^BGDesconectando em ^COUNT..."
+"^K1Para de ficar parado!\n"
+"^BGA desconectar em ^COUNT..."
#: qcsrc/common/notifications/all.inc:670
#, c-format
msgid "^BGYou need %s^BG!"
-msgstr "^BGVocê precisa %s^BG!"
+msgstr "^BGPrecisas de %s^BG!"
#: qcsrc/common/notifications/all.inc:671
#, c-format
msgid "^BGYou also need %s^BG!"
-msgstr "^BGVocê também precisa %s^BG!"
+msgstr "^BGTambém precisas de %s^BG!"
#: qcsrc/common/notifications/all.inc:672
msgid "^BGDoor unlocked!"
#: qcsrc/common/notifications/all.inc:674
msgid "^F2You picked up some extra lives"
-msgstr "^F2Você pegou algumas vidas extras"
+msgstr "^F2Apanhaste algumas vidas extra"
#: qcsrc/common/notifications/all.inc:676
#, c-format
msgid "^K3You revived ^BG%s"
-msgstr "^K3Você ressuscitou ^BG%s"
+msgstr "^K3Ressuscitaste ^BG%s"
#: qcsrc/common/notifications/all.inc:677
msgid "^K3You revived yourself"
-msgstr "^K3Você se ressuscitou"
+msgstr "^K3Ressuscitaste-te"
#: qcsrc/common/notifications/all.inc:678
#, c-format
msgid "^K3You were revived by ^BG%s"
-msgstr "^K3Você foi ressuscitado por ^BG%s"
+msgstr "^K3Foste ressuscitado por ^BG%s"
#: qcsrc/common/notifications/all.inc:679
#, c-format
msgid "^K3You were automatically revived after %s second(s)"
-msgstr "^K3Você foi automaticamente ressuscitado após %s segundo(s)"
+msgstr "^K3Foste automaticamente ressuscitado após %s segundo(s)"
#: qcsrc/common/notifications/all.inc:681
msgid "^BGThe generator is under attack!"
-msgstr "^BGO gerador está sobre ataque!"
+msgstr "^BGO gerador está a ser atacado!"
#: qcsrc/common/notifications/all.inc:683
msgid "^TC^TT^BG team loses the round"
-msgstr "A equipe ^TC^TT^BG perdeu a rodada"
+msgstr "A equipa ^TC^TT^BG perdeu a rodada"
#: qcsrc/common/notifications/all.inc:687
msgid "^K1You froze yourself"
-msgstr "^K1Você se congelou"
+msgstr "^K1Congelaste-te"
#: qcsrc/common/notifications/all.inc:688
msgid "^K1Round already started, you spawn as frozen"
-msgstr "^K1A rodada já começou, você surgiu congelado"
+msgstr "^K1A rodada já começou, surgiste congelado"
#: qcsrc/common/notifications/all.inc:690
#, c-format
#: 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 ""
"Hope your team can fix it..."
msgstr ""
"^K1Não há pontos de surgimento disponíveis!\n"
-"Tomara que sua equipe consiga consertar isso..."
+"Oxalá que a tua equipa consiga corrigir isso..."
#: qcsrc/common/notifications/all.inc:704
msgid ""
"^K1You may not join the game at this time.\n"
"The player limit reached maximum capacity."
msgstr ""
-"^K1Você não pode entrar no jogo neste momento.\n"
-"A capacidade máxima de jogadores foi alcançada."
+"^K1Não podes entrar no jogo neste momento.\n"
+"A capacidade máxima de jogadores foi atingida."
#: qcsrc/common/notifications/all.inc:708
msgid "^BGYou picked up the ball"
-msgstr "^BGVocê pegou a bola"
+msgstr "^BGApanhaste a bola"
#: qcsrc/common/notifications/all.inc:709
msgid "^BGKilling people while you don't have the ball gives no points!"
-msgstr "^BGMatar os outros enquanto você não tiver a bola não lhe dará pontos!"
+msgstr "^BGMatar os outros enquanto não tiveres a bola não ganharás pontos!"
#: qcsrc/common/notifications/all.inc:711
msgid ""
"^BGAll keys are in your team's hands!\n"
"Help the key carriers to meet!"
msgstr ""
-"^BGTodas as chaves estão com a sua equipe!\n"
-"Ajude os portadores das chaves a se encontrarem!"
+"^BGTodas as chaves estão com a tua equipa!\n"
+"Ajuda os portadores das chaves a encontrarem-se!"
#: qcsrc/common/notifications/all.inc:712
msgid ""
"^BGAll keys are in ^TC^TT team^BG's hands!\n"
"Interfere ^F4NOW^BG!"
msgstr ""
-"^BGTodas as chaves estão com a equipe ^TC^TT^BG!\n"
-"Interfira ^F4AGORA^BG!"
+"^BGTodas as chaves estão com a equipa ^TC^TT^BG!\n"
+"Interfere ^F4AGORA^BG!"
#: qcsrc/common/notifications/all.inc:713
msgid ""
"^BGAll keys are in your team's hands!\n"
"Meet the other key carriers ^F4NOW^BG!"
msgstr ""
-"^BGTodas as chaves estão com a sua equipe!\n"
-"Encontre-se com os outros portadores das chaves ^F4AGORA^BG!"
+"^BGTodas as chaves estão com a tua equipa!\n"
+"Encontra-te com os outros portadores das chaves ^F4AGORA^BG!"
#: qcsrc/common/notifications/all.inc:714
msgid "^F4Round will start in ^COUNT"
-msgstr "^F4A rodada iniciará em ^COUNT"
+msgstr "^F4A rodada vai começar dentro de ^COUNT"
#: qcsrc/common/notifications/all.inc:715
msgid "^BGScanning frequency range..."
-msgstr "^BGEscaneando alcance de frequência..."
+msgstr "^BGA varrer o alcance de frequência..."
#: qcsrc/common/notifications/all.inc:716
msgid "^BGYou are starting with the ^TC^TT Key"
-msgstr "^BGVocê está começando com a Chave ^TC^TT"
+msgstr "^BGEstás a começar com a Chave ^TC^TT"
#: qcsrc/common/notifications/all.inc:718
msgid "^BGYou have no lives left, you must wait until the next match"
-msgstr ""
-"^BGVocê não tem vidas sobrando, você terá que aguardar até a próxima partida"
+msgstr "^BGNão tens mais vidas, terás que esperar até à próxima partida"
#: qcsrc/common/notifications/all.inc:720
#, c-format
"^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 "^BGAperte ^F2%s^BG para se teletransportar"
+msgstr "^BGPressiona ^F2%s^BG para te teletransportares"
#: qcsrc/common/notifications/all.inc:740
#, c-format
msgid "^BGTeleporting disabled for %s"
-msgstr "^BGTeletransporte desabilitado para %s"
+msgstr "^BGTeletransporte desativado para %s"
#: qcsrc/common/notifications/all.inc:742
msgid ""
"^F2Now playing ^F4OVERTIME^F2!\n"
"Keep fragging until we have a winner!"
msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
-"Continue executando até que tenhamos um vencedor!"
+"^F2A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continua a executar até que tenhamos um vencedor!"
#: qcsrc/common/notifications/all.inc:742
msgid ""
"^F2Now playing ^F4OVERTIME^F2!\n"
"Keep scoring until we have a winner!"
msgstr ""
-"^F2Jogando agora nos ^F4ACRÉSCIMOS^F2!\n"
-"Continue pontuando até que tenhamos um vencedor!"
+"^A jogar agora nos ^F4ACRÉSCIMOS^F2!\n"
+"Continua a pontuar até que tenhamos um vencedor!"
#: qcsrc/common/notifications/all.inc:743
msgid ""
"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 "^BGAperte ^F2%s^BG para entrar/sair do veículo"
+msgstr "^BGPressiona ^F2%s^BG para entrar/sair do veículo"
#: qcsrc/common/notifications/all.inc:785
#, c-format
msgid "^BGPress ^F2%s^BG to enter the vehicle gunner"
-msgstr "^BGAperte ^F2%s^BG para usar a arma do veículo"
+msgstr "^BGPressiona ^F2%s^BG para usar a arma do veículo"
#: qcsrc/common/notifications/all.inc:786
#, c-format
msgid "^BGPress ^F2%s^BG to steal this vehicle"
-msgstr "^BGAperte ^F2%s^BG para roubar este veículo"
+msgstr "^BGPressiona ^F2%s^BG para roubar este veículo"
#: qcsrc/common/notifications/all.inc:787
msgid ""
"^F2The enemy is stealing one of your vehicles!\n"
"^F4Stop them!"
msgstr ""
-"^F2O inimigo está roubando um de seus veículos!\n"
-"^F4Impeça-os!"
+"^F2O inimigo está a roubar um dos teus veículos!\n"
+"^F4Impede-os!"
#: qcsrc/common/notifications/all.inc:788
msgid "^F2Intruder detected, disabling shields!"
-msgstr "^F2Intruso detectado, desativando escudos!"
+msgstr "^F2Intruso detetado, a desativar escudos!"
#: qcsrc/common/notifications/all.qh:188
msgid "Notification dump command only works with cl_cmd and sv_cmd.\n"
msgstr ""
-"Comando de despejo de notificação funciona apenas com cl_cmd e sv_cmd.\n"
+"O comando de notificação despejo funciona apenas com cl_cmd e sv_cmd.\n"
#: qcsrc/common/notifications/all.qh:399 qcsrc/common/notifications/all.qh:400
#, c-format
#: 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: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:595
#, c-format
msgid ", ending their %d frag spree"
-msgstr ", finalizando sua cadeia de %d execuções"
+msgstr ", a finalizar a sua cadeia de %d execuções"
#: qcsrc/common/notifications/all.qh:596
#, c-format
msgid ", ending their %d score spree"
-msgstr ", finalizando sua cadeia de %d pontuações"
+msgstr ", a finalizar a sua cadeia de %d pontuações"
#: qcsrc/common/notifications/all.qh:610
#, c-format
msgid ", losing their %d frag spree"
-msgstr ", perdendo sua cadeia de %d execuções"
+msgstr ", a perder a sua cadeia de %d execuções"
#: qcsrc/common/notifications/all.qh:611
#, c-format
msgid ", losing their %d score spree"
-msgstr ", perdendo sua cadeia de %d pontuações"
+msgstr ", a perder a sua cadeia de %d pontuações"
#: qcsrc/common/teams.qh:29
msgid "TEAM^Red"
#: 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 "Aperte %s"
+msgstr "Pressiona %s"
#: qcsrc/common/vehicles/vehicle/bumblebee.qc:950
msgid "No right gunner!"
-msgstr "Sem artilheiro na direita!"
+msgstr "Sem artilheiro à direita!"
#: qcsrc/common/vehicles/vehicle/bumblebee.qc:956
msgid "No left gunner!"
-msgstr "Sem artilheiro na esquerda!"
+msgstr "Sem artilheiro à esquerda!"
#: qcsrc/common/vehicles/vehicle/bumblebee.qh:19
msgid "Bumblebee"
-msgstr "Bumblebee"
+msgstr ""
#: qcsrc/common/vehicles/vehicle/racer.qh:19
msgid "Racer"
-msgstr "Racer"
+msgstr ""
#: qcsrc/common/vehicles/vehicle/racer_weapon.qh:9
msgid "Racer cannon"
#: 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:247
msgid "Polish"
-msgstr "Polônes "
+msgstr "Polaco"
#: qcsrc/menu/xonotic/credits.qc:255
msgid "Portuguese"
#: 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! 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 bate-papo:"
+msgstr "Entradas da conversação:"
#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:18
msgid "Chat size:"
-msgstr "Tamanho do bate-papo:"
+msgstr "Tamanho da conversação:"
#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:22
msgid "Chat lifetime:"
-msgstr "Tempo de vida do bate-papo:"
+msgstr "Tempo de vida da conversação:"
#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qc:26
msgid "Chat beep sound"
-msgstr "Som de aviso do bate-papo"
+msgstr "Som de aviso da conversação"
#: qcsrc/menu/xonotic/dialog_hudpanel_chat.qh:6
msgid "Chat Panel"
-msgstr "Painel do Bate-papo"
+msgstr "Painel da Conversação"
#: qcsrc/menu/xonotic/dialog_hudpanel_engineinfo.qc:14
msgid "Engine info:"
#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:15
msgid "Combine health and armor"
-msgstr "Combinar saúde e armadura"
+msgstr "Combinar vida e armadura"
#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:17
#: qcsrc/menu/xonotic/dialog_hudpanel_itemstime.qc:28
#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:15
msgid "Enable status bar"
-msgstr "Habilitar barra de status"
+msgstr "Ativar barra de estado"
#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:19
#: qcsrc/menu/xonotic/dialog_hudpanel_powerups.qc:17
msgid "Status bar alignment:"
-msgstr "Alinhamento da barra de status:"
+msgstr "Alinhamento da barra de estado:"
#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:27
#: qcsrc/menu/xonotic/dialog_hudpanel_healtharmor.qc:37
#: 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 Corrida/CTS"
+msgstr "Painel ativado apenas em Corrida/CTS"
#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:24
msgid "Status bar"
-msgstr "Barra de status"
+msgstr "Barra de estado"
#: qcsrc/menu/xonotic/dialog_hudpanel_physics.qc:26
#: qcsrc/menu/xonotic/dialog_settings_game_weapons.qc:68
#: 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_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 Corrida"
+msgstr "Painel do Cronómetro da Corrida"
#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:16
msgid "Panel enabled in teamgames"
-msgstr "Painel habilitado em jogos de equipe"
+msgstr "Painel ativado em jogos de equipa"
#: qcsrc/menu/xonotic/dialog_hudpanel_radar.qc:23
msgid "Radar:"
#: 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_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_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: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 aperte Ctrl+F para digitar uma palavra chave e buscar o mapa "
-"desejado. Você pode apertar Ctrl+Delete para apagar e Enter para confirmar."
+"Clica aqui ou pressiona Ctrl+F para digitar uma palavra-chave e diminuir a "
+"lista de mapas apresentados. Usar Ctrl+Delete para limpar e Enter para "
+"confirmar."
#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:207
msgid "Add shown"
-msgstr "Adicionar exibidos"
+msgstr "Adicionar mostrados"
#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:208
msgid "Add the maps shown in the list to your selection"
-msgstr "Adiciona os mapas exibidos na lista para a sua seleção"
+msgstr "Adiciona os mapas mostrados na lista para a tua seleção"
#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:211
msgid "Remove shown"
-msgstr "Remover exibidos"
+msgstr "Remover mostrados"
#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:212
msgid "Remove the maps shown in the list from your selection"
-msgstr "Remove os mapas exibidos na lista da sua seleção"
+msgstr "Remove os mapas mostrados na lista da tua seleção"
#: qcsrc/menu/xonotic/dialog_multiplayer_create.qc:217
msgid "Add all"
#: 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: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 surgem com o gancho"
+msgstr "Os jogadores surgem com o gancho"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:209
msgid "Players spawn with the jetpack"
-msgstr "Jogadores surgem com a mochila a jato"
+msgstr "Os jogadores surgem com a mochila a jato"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:225
msgid "Players will drop all weapons they possessed when they are killed"
msgstr ""
-"Ao morrerem, jogadores irão deixar cair no chão todas as armas que tinham"
+"Ao morrerem, os jogadores irão deixar cair no chão todas as armas que tinham"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:230
msgid "Weapons stay after they are picked up"
-msgstr "Armas permanecem no chão após serem coletadas"
+msgstr "As armas permanecem no chão após serem pegadas"
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:235
msgid "Regular (no arena)"
"as unlimited ammo, and disable all other weapon pickups."
msgstr ""
"Selecionar uma arena de armas concederá a todos os jogadores a arma "
-"selecionada ao surgirem bem como munição ilimitada. Todas as outras armas "
-"ficarão indisponíveis no mapa."
+"selecionada ao surgirem, bem como as munições ilimitadas. Todas as outras "
+"armas ficarão indisponíveis no mapa."
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:255
msgid "Most weapons"
"does not inflict any damage but is good for doing trickjumps."
msgstr ""
"Os jogadores terão uma arma, a qual pode instantaneamente matar o oponente "
-"com um único disparo. Se o jogador ficar sem munição, ele terá 10 segundos "
-"para encontrar alguma e se não conseguir fazer isso, irá morrer. O modo de "
+"com um único disparo. Se o jogador ficar sem munições, ele terá 10 segundos "
+"para encontrar munições e se não conseguir fazer isso, irá morrer. O modo de "
"disparo secundário não causa nenhum dano, mas é útil para executar truques "
"de movimento."
"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 de 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_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 bate-papo"
+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_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 potencializadores (padrão: desabilitado)"
+"Ativa efeitos especiais de pós-processamento ao receber dano, estar debaixo "
+"d'água ou ao usar potencializadores (padrão: desativado)"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:232
msgid "Motion blur strength - 0.4 recommended"
-msgstr "Intensidade do desfoque de movimento - 0.4 recomendado"
+msgstr "Intensidade da desfocagem de movimento - 0.4 recomendado"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:233
msgid "Motion blur:"
-msgstr "Desfoque de movimento:"
+msgstr "Desfocagem de movimento:"
#: qcsrc/menu/xonotic/dialog_settings_effects.qc:239
msgid "Particles"
"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 "Usar anéis para indicar status da arma"
+msgstr "Usar anéis para indicar estado da arma"
#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:93
msgid "Enable center crosshair dot"
-msgstr "Habilitar ponto no centro da mira"
+msgstr "Ativar ponto no centro da mira"
#: qcsrc/menu/xonotic/dialog_settings_game_crosshair.qc:111
msgid "Use normal crosshair color"
"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 ressurgimento"
+msgstr "Mostrar decimais na contagem de ressurgimento"
#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:57
msgid "Show accuracy underneath scoreboard"
-msgstr "Exibir precisão embaixo do placar"
+msgstr "Mostrar pontaria por baixo do placar de pontuação"
#: qcsrc/menu/xonotic/dialog_settings_game_hud.qc:61
msgid "Waypoints"
#: 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"
#: 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:67
msgid "Display capture times in Capture The Flag"
-msgstr "Exibir tempos de captura em Capture a Bandeira"
+msgstr "Mostrar tempos de captura em Capturar a Bandeira"
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:71
msgid "Display name of flag stealer in Capture The Flag"
-msgstr "Exibir nome do ladrão da bandeira em Capture a Bandeira"
+msgstr "Mostrar nome do ladrão da bandeira em Capturar a Bandeira"
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:76
#: qcsrc/menu/xonotic/dialog_settings_input.qc:91
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:78
msgid "Display console messages in the top left corner"
-msgstr "Exibir mensagens de console no canto superior esquerdo"
+msgstr "Mostrar mensagens da consola no canto superior esquerdo"
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:80
msgid "Display all info messages in the chatbox"
-msgstr "Exibir todas as mensagens de informação no bate-papo"
+msgstr "Mostrar todas as mensagens de informação na conversação"
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:82
msgid "Display player statuses in the chatbox"
-msgstr "Exibir status de jogadores no bate-papo"
+msgstr "Mostrar estado dos jogadores na conversação"
#: qcsrc/menu/xonotic/dialog_settings_game_messages.qc:86
msgid "Powerup notifications"
#: 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 ressurge"
+msgstr "Largar o zoom quando morro ou ressurgo"
#: qcsrc/menu/xonotic/dialog_settings_game_view.qc:120
msgid "Release zoom when you switch weapons"
-msgstr "Soltar o zoom quando você troca de arma"
+msgstr "Largar o zoom quando troco de arma"
#: qcsrc/menu/xonotic/dialog_settings_game_view.qh:7
#: qcsrc/menu/xonotic/keybinder.qc:76
#: 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"
#: 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 de que deseja redefinir todas as configurações para o padrão?"
+"Tens certeza de que queres redefinir todas as configurações para as "
+"originais?"
#: qcsrc/menu/xonotic/dialog_settings_misc_reset.qc:13
msgid "This will create a backup config in your data directory"
msgstr ""
-"Isso irá criar uma cópia da sua configuração na seguinte pasta: C:\\Users"
-"\\[usuário]\\Saved Games\\xonotic\\data"
+"Isto irá criar uma cópia da tua configuração na seguinte pasta: C:\\Users"
+"\\[utilizador]\\Saved Games\\xonotic\\data"
#: qcsrc/menu/xonotic/dialog_settings_user.qc:25
msgid "Menu Skins"
#: 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"
#: 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 "Bate-papo público"
+msgstr "Conversação pública"
#: qcsrc/menu/xonotic/keybinder.qc:87 qcsrc/menu/xonotic/keybinder.qc:100
msgid "team chat"
-msgstr "Bate-papo de equipe"
+msgstr "Conversação da equipa"
#: qcsrc/menu/xonotic/keybinder.qc:88
msgid "show chat history"
-msgstr "exibir histórico do bate-papo"
+msgstr "mostrar histórico da conversação"
#: qcsrc/menu/xonotic/keybinder.qc:89
msgid "vote YES"
#: 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 aperte este botão novamente!"
+msgstr "Não pressiones este botão outra vez!"
#: qcsrc/menu/xonotic/maplist.qc:291
msgid ""
"Huh? Can't play this (m is NULL). Refiltering so this won't happen again.\n"
msgstr ""
-"Huh? Não posso jogar isto (m é NULO). Refiltrando para que isso não ocorra "
+"Huh? Não posso jogar isto (m é NULO). Refiltrando para que isto não ocorra "
"novamente.\n"
#: qcsrc/menu/xonotic/maplist.qc:299
"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 "Bate-papo"
+#~ msgstr "Conversação"
#~ msgid "^BG%s%s^K1 got too close ^BG%s^K1's rocket%s%s"
-#~ msgstr "^BG%s%s^K1 chegou muito perto do foguete de ^BG%s^K1%s%s"
+#~ msgstr "^BG%s%s^K1 chegou muito perto do míssil de ^BG%s^K1%s%s"
--- /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: 2018-03-01 20:50+0000\n"
+"PO-Revision-Date: 2018-03-16 06:43+0000\n"
"Last-Translator: Andrei Stepanov\n"
"Language-Team: Russian (http://www.transifex.com/team-xonotic/xonotic/"
"language/ru/)\n"
#: qcsrc/client/hud/panel/infomessages.qc:108
#: qcsrc/menu/xonotic/keybinder.qc:41
msgid "secondary fire"
-msgstr "вÑ\82оÑ\80иÑ\87ный огонь"
+msgstr "алÑ\8cÑ\82еÑ\80наÑ\82ивный огонь"
#: qcsrc/client/hud/panel/infomessages.qc:111
#, c-format
#: qcsrc/client/hud/panel/infomessages.qc:139
#, c-format
msgid "^1Game starts in ^3%d^1 seconds"
-msgstr "^1Старт игры через ^3%d^1 секунд(ы)"
+msgstr "^1Старт игры через ^3%d^1 секунд"
#: qcsrc/client/hud/panel/infomessages.qc:145
msgid "^2Currently in ^1warmup^2 stage!"
#: 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/mapvoting.qc:382
#, c-format
msgid "%d seconds left"
-msgstr "Осталось %d секунд(ы)"
+msgstr "Осталось %d секунд"
#: qcsrc/client/mapvoting.qc:497
msgid ""
#: qcsrc/common/notifications/all.inc:246
msgid "^BGThe ^TC^TT^BG flag was returned to base by its owner"
-msgstr "^BG ^TC^TT^BG Флаг бÑ\8bл возвÑ\80аÑ\89Ñ\91н на базÑ\83 владелÑ\8cÑ\86ем"
+msgstr "^BG ^TC^TT^BG Флаг возвращён на базу владельцем"
#: qcsrc/common/notifications/all.inc:247
msgid "^BGThe flag was returned by its owner"
-msgstr "^BGФлаг бÑ\8bл возвÑ\80аÑ\89Ñ\91н на базÑ\83 владелÑ\8cÑ\86ем"
+msgstr "^BGФлаг возвращён на базу владельцем"
#: qcsrc/common/notifications/all.inc:248
msgid "^BGThe ^TC^TT^BG flag was destroyed and returned to base"
#: 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л немного подпалÑ\91н из ^BG%s^K1^K1%s%s"
+msgstr "^BG%s%s^K1 немного подпалён из ^BG%s^K1^K1%s%s"
#: qcsrc/common/notifications/all.inc:278
#, c-format
msgid "^BG%s%s^K1 was burnt up into a crisp by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 бÑ\8bл пÑ\80ожаÑ\80ен до Ñ\85Ñ\80Ñ\83Ñ\81Ñ\82Ñ\8fÑ\89ей коÑ\80оÑ\87ки ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 прожарен до хрустящей корочки ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:279
#, c-format
msgid "^BG%s%s^K1 was cooked by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 бÑ\8bл иÑ\81пеÑ\87Ñ\91н Ñ\81 помоÑ\89Ñ\8cÑ\8e ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 испечён с помощью ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:280
#, c-format
msgid "^BG%s%s^K1 was pushed in front of a monster by ^BG%s^K1%s%s"
-msgstr "^BG%s%s^K1 бÑ\8bл оÑ\82пÑ\80авлен к монÑ\81Ñ\82Ñ\80ам Ñ\80Ñ\83кой ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 отправлен к монстрам рукой ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:281
#, c-format
#: 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
#: qcsrc/common/notifications/all.inc:299
#, c-format
msgid "^BG%s%s^K1 was blasted to bits by ^BG%s^K1's Spiderbot%s%s"
-msgstr ""
-"^BG%s%s^K1 был разорван на куски Пауком-ботом, управляемым ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван на куски Пауком-ботом, управляемым ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:300
#, c-format
#: 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
#: qcsrc/common/notifications/all.inc:317
#, c-format
msgid "^BG%s^K1 was smashed by a Shambler%s%s"
-msgstr "^BG%s^K1 был раздавлен Шамблером%s%s"
+msgstr "^BG%s^K1 раздавлен Шамблером%s%s"
#: qcsrc/common/notifications/all.inc:318
#, c-format
msgid "^BG%s^K1 was zapped to death by a Shambler%s%s"
-msgstr "^BG%s^K1 был стёрт в порошок Шамблером%s%s"
+msgstr "^BG%s^K1 стёрт в порошок Шамблером%s%s"
#: qcsrc/common/notifications/all.inc:319
#, c-format
msgid "^BG%s^K1 was bitten by a Spider%s%s"
-msgstr "^BG%s^K1 бÑ\8bл побиÑ\82 Ð\9fаÑ\83ком%s%s"
+msgstr "^BG%s^K1 побит Пауком%s%s"
#: qcsrc/common/notifications/all.inc:320
#, c-format
msgid "^BG%s^K1 was fireballed by a Wyvern%s%s"
-msgstr "^BG%s^K1 бÑ\8bл поÑ\80ажÑ\91н огненнÑ\8bм Ñ\88аÑ\80ом Ð\92ивеÑ\80на%s%s"
+msgstr "^BG%s^K1 поражён огненным шаром Виверна%s%s"
#: qcsrc/common/notifications/all.inc:321
#, c-format
#: 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: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
#: 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: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
#: qcsrc/common/notifications/all.inc:347
#, c-format
msgid "^BG%s^K1 was impaled by a Walker turret%s%s"
-msgstr "^BG%s^K1 бÑ\8bл пÑ\80онзÑ\91н Ñ\82Ñ\83Ñ\80елÑ\8cÑ\8e ХодÑ\83на%s%s"
+msgstr "^BG%s^K1 пронзён турелью Ходуна%s%s"
#: qcsrc/common/notifications/all.inc:348
#, c-format
msgid "^BG%s^K1 was blasted away by a Walker turret%s%s"
-msgstr "^BG%s^K1 был разорван в клочья турелью Ходуна%s%s"
+msgstr "^BG%s^K1 разорван в клочья турелью Ходуна%s%s"
#: qcsrc/common/notifications/all.inc:349
#, c-format
#: 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
#: qcsrc/common/notifications/all.inc:354
#, c-format
msgid "^BG%s^K1 was blasted to bits by a Spiderbot rocket%s%s"
-msgstr "^BG%s^K1 был разорван на кусочки ракетой Паука-бота%s%s"
+msgstr "^BG%s^K1 разорван на кусочки ракетой Паука-бота%s%s"
#: qcsrc/common/notifications/all.inc:355
#, c-format
#: 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: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!"
#: 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
#: qcsrc/common/notifications/all.inc:465
#, c-format
msgid "^BG%s%s^K1 was blasted by ^BG%s^K1's Electro bolt%s%s"
-msgstr "^BG%s%s^K1 был разорван зарядом Электро от ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 разорван зарядом Электро ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:466
#, c-format
#: 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
#: qcsrc/common/notifications/all.inc:475
#, c-format
msgid "^BG%s%s^K1 was pummeled by ^BG%s^K1's Hagar rockets%s%s"
-msgstr "^BG%s%s^K1 обстрелян из Хагара со стороны ^BG%s^K1%s%s"
+msgstr "^BG%s%s^K1 обстрелян из Хагара ^BG%s^K1%s%s"
#: qcsrc/common/notifications/all.inc:476
#, c-format
#: 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: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
#: 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
#: 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:764
msgid "^BGSecondary fire inflicts no damage!"
-msgstr "^BGÐ\92Ñ\82оÑ\80иÑ\87ный режим огня не наносит урона!"
+msgstr "^BGÐ\90лÑ\8cÑ\82еÑ\80наÑ\82ивный режим огня не наносит урона!"
#: qcsrc/common/notifications/all.inc:766
msgid "^BGSequence completed!"
#: qcsrc/common/notifications/all.qh:407 qcsrc/common/notifications/all.qh:408
msgid "secondary"
-msgstr "вÑ\82оÑ\80иÑ\87ный"
+msgstr "алÑ\8cÑ\82еÑ\80наÑ\82ивный"
#: qcsrc/common/notifications/all.qh:410
msgid "point"
#: 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
msgstr ""
"Игроки получат только одно оружие, которое немедленно убьёт противника с "
"одного выстрела. Если игрок испытывает недостаток патронов, у него есть 10 "
-"Ñ\81екÑ\83нд, Ñ\87Ñ\82обÑ\8b найÑ\82и еÑ\89Ñ\91, инаÑ\87е он вÑ\81Ñ\82Ñ\80еÑ\82иÑ\82 Ñ\81меÑ\80Ñ\82Ñ\8c. Режим вÑ\82оÑ\80иÑ\87ного огнÑ\8f не "
-"наносит урона, но он хорош для трюков."
+"Ñ\81екÑ\83нд, Ñ\87Ñ\82обÑ\8b найÑ\82и еÑ\89Ñ\91, инаÑ\87е он вÑ\81Ñ\82Ñ\80еÑ\82иÑ\82 Ñ\81меÑ\80Ñ\82Ñ\8c. Режим алÑ\8cÑ\82еÑ\80наÑ\82ивного "
+"огнÑ\8f не наноÑ\81иÑ\82 Ñ\83Ñ\80она, но он Ñ\85оÑ\80оÑ\88 длÑ\8f Ñ\82Ñ\80Ñ\8eков."
#: qcsrc/menu/xonotic/dialog_multiplayer_create_mutators.qc:273
msgid ""
#: 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_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)"
"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
# Antoni Das <Antonidas159@gmail.com>, 2015,2017
# sapphireliu <balancedliu@gmail.com>, 2014
# kalawore <kalawore@outlook.com>, 2015
+# Losier Blackheath <losier.cc@gmail.com>, 2018
# sapphireliu <balancedliu@gmail.com>, 2014
+# 茂森 杜 <dumaosen_main01@outlook.com>, 2018
msgid ""
msgstr ""
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-07-09 00:35+0200\n"
-"PO-Revision-Date: 2017-09-19 23:30+0000\n"
-"Last-Translator: divVerent <divVerent@xonotic.org>\n"
+"PO-Revision-Date: 2018-06-02 05:39+0000\n"
+"Last-Translator: Losier Blackheath <losier.cc@gmail.com>\n"
"Language-Team: Chinese (China) (http://www.transifex.com/team-xonotic/"
"xonotic/language/zh_CN/)\n"
"Language: zh_CN\n"
#: 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: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: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_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:"
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
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"
// ==========================
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%
+zh_CN "Chinese (China)" "中文" 62%
de German "Deutsch"
de_CH German "Deutsch (Schweiz)"
en English "English"
en_AU English "English (Australia)" 86%
es Spanish "Español" 99%
fr French "Français"
-ga Irish "Irish" 32%
+ga Irish "Irish" 35%
it Italian "Italiano"
-hu Hungarian "Magyar" 53%
-nl Dutch "Nederlands" 67%
-pl Polish "Polski" 80%
+hu Hungarian "Magyar" 55%
+nl Dutch "Nederlands" 70%
+pl Polish "Polski" 81%
pt Portuguese "Português"
+pt_BR pt_BR "pt_BR" 99%
ro Romanian "Romana" 83%
-fi Finnish "Suomi" 31%
-zh_CN "Chinese (China)" "中文" 47%
-zh_TW "Chinese (Taiwan)" "國語" 67%
-ko Korean "한국의" 32%
-el Greek "Ελληνική" 32%
-be Belarusian "Беларуская" 59%
-bg Bulgarian "Български" 66%
+fi Finnish "Suomi" 33%
+zh_TW "Chinese (Taiwan)" "國語" 68%
+el Greek "Ελληνική" 33%
+be Belarusian "Беларуская" 61%
+bg Bulgarian "Български" 68%
ru Russian "Русский"
-sr Serbian "Српски" 69%
-uk Ukrainian "Українська" 57%
\ No newline at end of file
+sr Serbian "Српски" 71%
+uk Ukrainian "Українська" 57%
// overkill
// ==========
set g_overkill 0 "internal cvar, to enable overkill, use `exec ruleset-overkill.cfg`"
+set g_overkill_weapons 0 "Whether to enable overkill weapons outside of overkill ruleset."
set g_overkill_powerups_replace 1
set g_overkill_itemwaypoints 1
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_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"
// 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"
// =========
#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/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>
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);
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);
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);
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)
{
#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 default");
LOG_INFO(_("^2scoreboard_columns_set ^7field1 field2 ..."));
- LOG_INFO(_("The following field names are recognized (case insensitive):"));
LOG_INFO(_("You can use a ^3|^7 to start the right-aligned fields."));
+ LOG_INFO(_("The following field names are recognized (case insensitive):"));
LOG_INFO("");
- LOG_INFO(_("^3name^7 or ^3nick^7 Name of a player"));
- LOG_INFO(_("^3ping^7 Ping time"));
- LOG_INFO(_("^3pl^7 Packet loss"));
- LOG_INFO(_("^3elo^7 Player ELO"));
- LOG_INFO(_("^3kills^7 Number of kills"));
- LOG_INFO(_("^3deaths^7 Number of deaths"));
- LOG_INFO(_("^3suicides^7 Number of suicides"));
- LOG_INFO(_("^3frags^7 kills - suicides"));
- LOG_INFO(_("^3teamkills^7 Number of teamkills"));
- LOG_INFO(_("^3kd^7 The kill-death ratio"));
- LOG_INFO(_("^3dmg^7 The total damage done"));
- LOG_INFO(_("^3dmgtaken^7 The total damage taken"));
- LOG_INFO(_("^3sum^7 frags - deaths"));
- LOG_INFO(_("^3caps^7 How often a flag (CTF) or a key (KeyHunt) was captured"));
- LOG_INFO(_("^3pickups^7 How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up"));
- LOG_INFO(_("^3captime^7 Time of fastest cap (CTF)"));
- LOG_INFO(_("^3fckills^7 Number of flag carrier kills"));
- LOG_INFO(_("^3returns^7 Number of flag returns"));
- LOG_INFO(_("^3drops^7 Number of flag drops"));
- LOG_INFO(_("^3lives^7 Number of lives (LMS)"));
- LOG_INFO(_("^3rank^7 Player rank"));
- LOG_INFO(_("^3pushes^7 Number of players pushed into void"));
- LOG_INFO(_("^3destroyed^7 Number of keys destroyed by pushing them into void"));
- LOG_INFO(_("^3kckills^7 Number of keys carrier kills"));
- LOG_INFO(_("^3losses^7 Number of times a key was lost"));
- LOG_INFO(_("^3laps^7 Number of laps finished (race/cts)"));
- LOG_INFO(_("^3time^7 Total time raced (race/cts)"));
- LOG_INFO(_("^3fastest^7 Time of fastest lap (race/cts)"));
- LOG_INFO(_("^3ticks^7 Number of ticks (DOM)"));
- LOG_INFO(_("^3takes^7 Number of domination points taken (DOM)"));
- LOG_INFO(_("^3bckills^7 Number of ball carrier kills"));
- LOG_INFO(_("^3bctime^7 Total amount of time holding the ball in Keepaway"));
- LOG_INFO(_("^3score^7 Total score"));
+ LOG_INFO(strcat("^3name^7 ", _("Name of a player")));
+ LOG_INFO(strcat("^3nick^7 ", _("Name of a player")));
+ LOG_INFO(strcat("^3ping^7 ", _("Ping time")));
+ LOG_INFO(strcat("^3pl^7 ", _("Packet loss")));
+ LOG_INFO(strcat("^3elo^7 ", _("Player ELO")));
+ LOG_INFO(strcat("^3fps^7 ", _("Player FPS")));
+ LOG_INFO(strcat("^3kills^7 ", _("Number of kills")));
+ LOG_INFO(strcat("^3deaths^7 ", _("Number of deaths")));
+ LOG_INFO(strcat("^3suicides^7 ", _("Number of suicides")));
+ LOG_INFO(strcat("^3frags^7 ", _("kills - suicides")));
+ LOG_INFO(strcat("^3teamkills^7 ", _("Number of teamkills")));
+ LOG_INFO(strcat("^3kd^7 ", _("The kill-death ratio")));
+ LOG_INFO(strcat("^3dmg^7 ", _("The total damage done")));
+ LOG_INFO(strcat("^3dmgtaken^7 ", _("The total damage taken")));
+ LOG_INFO(strcat("^3sum^7 ", _("kills - deaths")));
+ LOG_INFO(strcat("^3caps^7 ", _("How often a flag (CTF) or a key (KeyHunt) was captured")));
+ LOG_INFO(strcat("^3pickups^7 ", _("How often a flag (CTF) or a key (KeyHunt) or a ball (Keepaway) was picked up")));
+ LOG_INFO(strcat("^3captime^7 ", _("Time of fastest cap (CTF)")));
+ LOG_INFO(strcat("^3fckills^7 ", _("Number of flag carrier kills")));
+ LOG_INFO(strcat("^3returns^7 ", _("Number of flag returns")));
+ LOG_INFO(strcat("^3drops^7 ", _("Number of flag drops")));
+ LOG_INFO(strcat("^3lives^7 ", _("Number of lives (LMS)")));
+ LOG_INFO(strcat("^3rank^7 ", _("Player rank")));
+ LOG_INFO(strcat("^3pushes^7 ", _("Number of players pushed into void")));
+ LOG_INFO(strcat("^3destroyed^7 ", _("Number of keys destroyed by pushing them into void")));
+ LOG_INFO(strcat("^3kckills^7 ", _("Number of keys carrier kills")));
+ LOG_INFO(strcat("^3losses^7 ", _("Number of times a key was lost")));
+ LOG_INFO(strcat("^3laps^7 ", _("Number of laps finished (race/cts)")));
+ LOG_INFO(strcat("^3time^7 ", _("Total time raced (race/cts)")));
+ LOG_INFO(strcat("^3fastest^7 ", _("Time of fastest lap (race/cts)")));
+ LOG_INFO(strcat("^3ticks^7 ", _("Number of ticks (DOM)")));
+ LOG_INFO(strcat("^3takes^7 ", _("Number of domination points taken (DOM)")));
+ LOG_INFO(strcat("^3bckills^7 ", _("Number of ball carrier kills")));
+ LOG_INFO(strcat("^3bctime^7 ", _("Total amount of time holding the ball in Keepaway")));
+ LOG_INFO(strcat("^3score^7 ", _("Total score")));
LOG_INFO("");
LOG_INFO(_("Before a field you can put a + or - sign, then a comma separated list\n"
"of game types, then a slash, to make the field show up only in these\n"
"or in all but these game types. You can also specify 'all' as a\n"
- "field to show all fields available for the current game mode.\n\n"));
+ "field to show all fields available for the current game mode."));
+ LOG_INFO("");
LOG_INFO(_("The special game type names 'teams' and 'noteams' can be used to\n"
- "include/exclude ALL teams/noteams game modes.\n\n"));
+ "include/exclude ALL teams/noteams game modes."));
+ LOG_INFO("");
LOG_INFO(_("Example: scoreboard_columns_set name ping pl | +ctf/field3 -dm/field4"));
- LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields"
- "right of the vertical bar aligned to the right.\n"));
- LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\nother gamemodes except DM.\n"));
+ LOG_INFO(_("will display name, ping and pl aligned to the left, and the fields\n"
+ "right of the vertical bar aligned to the right."));
+ LOG_INFO(_("'field3' will only be shown in CTF, and 'field4' will be shown in all\n"
+ "other gamemodes except DM."));
}
// NOTE: adding a gametype with ? to not warn for an optional field
// 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" \
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);
{
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;
}
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;
}
#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"));
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)
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;
}
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];
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;
#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;
#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();
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);
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;
float arc_heat = wepent.arc_heat_percent;
float vcharge = wepent.vortex_charge;
float vchargepool = wepent.vortex_chargepool_ammo;
+ float oknex_charge_ = wepent.oknex_charge;
+ float oknex_chargepool_ = wepent.oknex_chargepool_ammo;
if(vortex_charge_movingavg == 0) // this should only happen if we have just loaded up the game
vortex_charge_movingavg = vcharge;
ring_rgb = wcross_color;
ring_image = "gfx/crosshair_ring_nexgun.tga";
}
+ else if (autocvar_crosshair_ring && (wepent.activeweapon == WEP_OVERKILL_NEX) && oknex_charge_ && autocvar_crosshair_ring_vortex)
+ {
+ if (oknex_chargepool_ || use_vortex_chargepool) {
+ use_vortex_chargepool = 1;
+ ring_inner_value = oknex_chargepool_;
+ } else {
+ vortex_charge_movingavg = (1 - autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate) * vortex_charge_movingavg + autocvar_crosshair_ring_vortex_currentcharge_movingavg_rate * oknex_charge_;
+ ring_inner_value = bound(0, autocvar_crosshair_ring_vortex_currentcharge_scale * (oknex_charge_ - vortex_charge_movingavg), 1);
+ }
+
+ ring_inner_alpha = autocvar_crosshair_ring_vortex_inner_alpha;
+ ring_inner_rgb = eX * autocvar_crosshair_ring_vortex_inner_color_red + eY * autocvar_crosshair_ring_vortex_inner_color_green + eZ * autocvar_crosshair_ring_vortex_inner_color_blue;
+ ring_inner_image = "gfx/crosshair_ring_inner.tga";
+
+ // draw the outer ring to show the current charge of the weapon
+ ring_value = oknex_charge_;
+ ring_alpha = autocvar_crosshair_ring_vortex_alpha;
+ ring_rgb = wcross_color;
+ ring_image = "gfx/crosshair_ring_nexgun.tga";
+ }
else if (autocvar_crosshair_ring && wepent.activeweapon == WEP_MINE_LAYER && WEP_CVAR(minelayer, limit) && autocvar_crosshair_ring_minelayer)
{
ring_value = bound(0, wepent.minelayer_mines / WEP_CVAR(minelayer, limit), 1); // if you later need to use the count of bullets in another place, then add a float for it. For now, no need to.
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;
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
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 = ReadVector();
- setorigin(this, this.origin);
- }
-
- if(f & 4)
- {
- if(f & 0x10)
- {
- this.angles_x = ReadAngle();
- this.angles_y = ReadAngle();
- this.angles_z = ReadAngle();
- }
- else
- this.angles = '0 0 0';
- }
-
- if(f & 8)
- {
- if(f & 0x80)
- {
- this.lodmodelindex0 = ReadShort();
- this.loddistance1 = ReadShort();
- this.lodmodelindex1 = ReadShort();
- this.loddistance2 = ReadShort();
- this.lodmodelindex2 = ReadShort();
- }
- else
- {
- this.modelindex = ReadShort();
- this.loddistance1 = 0;
- this.loddistance2 = 0;
- }
- this.solid = ReadByte();
- this.scale = ReadShort() / 256.0;
- if(f & 0x20)
- {
- this.mins = ReadVector();
- this.maxs = ReadVector();
- }
- else
- this.mins = this.maxs = '0 0 0';
- setsize(this, this.mins, this.maxs);
-
- if(this.bgmscript)
- strunzone(this.bgmscript);
- this.bgmscript = ReadString();
- if(substring(this.bgmscript, 0, 1) == "<")
- {
- this.bgmscript = strzone(substring(this.bgmscript, 1, -1));
- this.bgmscriptangular = 1;
- }
- else
- {
- this.bgmscript = strzone(this.bgmscript);
- this.bgmscriptangular = 0;
- }
- if(this.bgmscript != "")
- {
- this.bgmscriptattack = ReadByte() / 64.0;
- this.bgmscriptdecay = ReadByte() / 64.0;
- this.bgmscriptsustain = ReadByte() / 255.0;
- this.bgmscriptrelease = ReadByte() / 64.0;
- this.movedir = ReadVector();
- this.lip = ReadByte() / 255.0;
- }
- this.fade_start = ReadByte();
- this.fade_end = ReadByte();
- this.alpha_max = ReadByte();
- this.alpha_min = ReadByte();
- this.inactive = ReadByte();
- this.fade_vertical_offset = ReadShort();
- BGMScript_InitEntity(this);
- }
-
- return = true;
-
- InterpolateOrigin_Note(this);
-
- this.saved = this.(fld);
-
- this.entremove = Ent_Wall_Remove;
- this.draw = Ent_Wall_Draw;
- if (isnew) IL_PUSH(g_drawables, this);
- setpredraw(this, Ent_Wall_PreDraw);
-}
+++ /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;
#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_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) \
/** 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);
}
DESTRUCTOR(DebugText3d) {
- strunzone(this.message);
+ strfree(this.message);
}
void DebugText3d_draw2d(DebugText3d this) {
#define debug_text_3d_5(pos, msg, align, dur, vel) debug_text_3d_fn(pos, msg, align, dur, vel)
ERASEABLE
-void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector velocity) {
+void debug_text_3d_fn(vector pos, string msg, float align, float duration, vector vel) {
WriteHeader(MSG_BROADCAST, debug_text_3d);
WriteVector(MSG_BROADCAST, pos);
WriteString(MSG_BROADCAST, msg);
WriteFloat(MSG_BROADCAST, align);
WriteFloat(MSG_BROADCAST, duration);
- WriteVector(MSG_BROADCAST, velocity);
+ WriteVector(MSG_BROADCAST, vel);
}
#endif // SVQC
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
#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)
{
#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
.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);
#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;
#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>
REGISTRY(EntCSProps, BITS(16) - 1)
#define EntCSProps_from(i) _EntCSProps_from(i, NULL)
/** 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 */
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
+ this.health = 100;
+ //print("^2Activated objective ", this.targetname, "=", etos(this), "\n");
+ //print("Activator is ", actor.classname, "\n");
+
+ IL_EACH(g_assault_objectivedecreasers, it.target == this.targetname,
+ {
+ target_objective_decrease_activate(it);
+ });
+}
+
+vector target_objective_spawn_evalfunc(entity this, entity player, entity spot, vector current)
+{
+ if(this.health < 0 || this.health >= ASSAULT_VALUE_INACTIVE)
+ return '-1 0 0';
+ return current;
+}
+
+// reset this objective. Used when spawning an objective
+// and when a new round starts
+void assault_objective_reset(entity this)
+{
+ this.health = ASSAULT_VALUE_INACTIVE;
+}
+
+// decrease the health of targeted objectives
+void assault_objective_decrease_use(entity this, entity actor, entity trigger)
+{
+ if(actor.team != assault_attacker_team)
+ {
+ // wrong team triggered decrease
+ return;
+ }
+
+ if(trigger.assault_sprite)
+ {
+ WaypointSprite_Disown(trigger.assault_sprite, waypointsprite_deadlifetime);
+ if(trigger.classname == "func_assault_destructible")
+ trigger.sprite = NULL; // TODO: just unsetting it?!
+ }
+ else
+ return; // already activated! cannot activate again!
+
+ if(this.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ if(this.enemy.health - this.dmg > 0.5)
+ {
+ GameRules_scoring_add_team(actor, SCORE, this.dmg);
+ this.enemy.health = this.enemy.health - this.dmg;
+ }
+ else
+ {
+ GameRules_scoring_add_team(actor, SCORE, this.enemy.health);
+ GameRules_scoring_add_team(actor, ASSAULT_OBJECTIVES, 1);
+ this.enemy.health = -1;
+
+ if(this.enemy.message)
+ FOREACH_CLIENT(IS_PLAYER(it), { centerprint(it, this.enemy.message); });
+
+ SUB_UseTargets(this.enemy, this, trigger);
+ }
+ }
+}
+
+void assault_setenemytoobjective(entity this)
+{
+ IL_EACH(g_assault_objectives, it.targetname == this.target,
+ {
+ if(this.enemy == NULL)
+ this.enemy = it;
+ else
+ objerror(this, "more than one objective as target - fix the map!");
+ break;
+ });
+
+ if(this.enemy == NULL)
+ objerror(this, "no objective as target - fix the map!");
+}
+
+bool assault_decreaser_sprite_visible(entity this, entity player, entity view)
+{
+ if(this.assault_decreaser.enemy.health >= ASSAULT_VALUE_INACTIVE)
+ return false;
+
+ return true;
+}
+
+void target_objective_decrease_activate(entity this)
+{
+ entity spr;
+ this.owner = NULL;
+ FOREACH_ENTITY_STRING(target, this.targetname,
+ {
+ if(it.assault_sprite != NULL)
+ {
+ WaypointSprite_Disown(it.assault_sprite, waypointsprite_deadlifetime);
+ if(it.classname == "func_assault_destructible")
+ it.sprite = NULL; // TODO: just unsetting it?!
+ }
+
+ spr = WaypointSprite_SpawnFixed(WP_AssaultDefend, 0.5 * (it.absmin + it.absmax), it, assault_sprite, RADARICON_OBJECTIVE);
+ spr.assault_decreaser = this;
+ spr.waypointsprite_visible_for_player = assault_decreaser_sprite_visible;
+ spr.classname = "sprite_waypoint";
+ WaypointSprite_UpdateRule(spr, assault_attacker_team, SPRITERULE_TEAMPLAY);
+ if(it.classname == "func_assault_destructible")
+ {
+ WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultDestroy, WP_AssaultDestroy);
+ WaypointSprite_UpdateMaxHealth(spr, it.max_health);
+ WaypointSprite_UpdateHealth(spr, it.health);
+ it.sprite = spr;
+ }
+ else
+ WaypointSprite_UpdateSprites(spr, WP_AssaultDefend, WP_AssaultPush, WP_AssaultPush);
+ });
+}
+
+void target_objective_decrease_findtarget(entity this)
+{
+ assault_setenemytoobjective(this);
+}
+
+void target_assault_roundend_reset(entity this)
+{
+ //print("round end reset\n");
+ ++this.cnt; // up round counter
+ this.winning = false; // up round
+}
+
+void target_assault_roundend_use(entity this, entity actor, entity trigger)
+{
+ this.winning = 1; // round has been won by attackers
+}
+
+void assault_roundstart_use(entity this, entity actor, entity trigger)
+{
+ SUB_UseTargets(this, this, trigger);
+
+ //(Re)spawn all turrets
+ IL_EACH(g_turrets, true,
+ {
+ // Swap turret teams
+ if(it.team == NUM_TEAM_1)
+ it.team = NUM_TEAM_2;
+ else
+ it.team = NUM_TEAM_1;
+
+ // Doubles as teamchange
+ turret_respawn(it);
+ });
+}
+void assault_roundstart_use_this(entity this)
+{
+ assault_roundstart_use(this, NULL, NULL);
+}
+
+void assault_wall_think(entity this)
+{
+ if(this.enemy.health < 0)
+ {
+ this.model = "";
+ this.solid = SOLID_NOT;
+ }
+ else
+ {
+ this.model = this.mdl;
+ this.solid = SOLID_BSP;
+ }
+
+ this.nextthink = time + 0.2;
+}
+
+// trigger new round
+// reset objectives, toggle spawnpoints, reset triggers, ...
+void assault_new_round(entity this)
+{
+ //bprint("ASSAULT: new round\n");
+
+ // up round counter
+ this.winning = this.winning + 1;
+
+ // swap attacker/defender roles
+ if(assault_attacker_team == NUM_TEAM_1)
+ assault_attacker_team = NUM_TEAM_2;
+ else
+ assault_attacker_team = NUM_TEAM_1;
+
+ IL_EACH(g_saved_team, !IS_CLIENT(it),
+ {
+ if(it.team_saved == NUM_TEAM_1)
+ it.team_saved = NUM_TEAM_2;
+ else if(it.team_saved == NUM_TEAM_2)
+ it.team_saved = NUM_TEAM_1;
+ });
+
+ // reset the level with a countdown
+ cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
+ ReadyRestart_force(); // sets game_starttime
+}
+
+entity as_round;
+.entity ent_winning;
+void as_round_think()
+{
+ game_stopped = false;
+ assault_new_round(as_round.ent_winning);
+ delete(as_round);
+ as_round = NULL;
+}
+
+// Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
+// they win. Otherwise the defending team wins once the timelimit passes.
+int WinningCondition_Assault()
+{
+ if(as_round)
+ return WINNING_NO;
+
+ WinningConditionHelper(NULL); // set worldstatus
+
+ int status = WINNING_NO;
+ // as the timelimit has not yet passed just assume the defending team will win
+ if(assault_attacker_team == NUM_TEAM_1)
+ {
+ SetWinners(team, NUM_TEAM_2);
+ }
+ else
+ {
+ SetWinners(team, NUM_TEAM_1);
+ }
+
+ entity ent;
+ ent = find(NULL, classname, "target_assault_roundend");
+ if(ent)
+ {
+ if(ent.winning) // round end has been triggered by attacking team
+ {
+ bprint("Assault: round completed.\n");
+ SetWinners(team, assault_attacker_team);
+
+ TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
+
+ if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round
+ {
+ status = WINNING_YES;
+ }
+ else
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
+ as_round = new(as_round);
+ as_round.think = as_round_think;
+ as_round.ent_winning = ent;
+ as_round.nextthink = time + AS_ROUND_DELAY;
+ game_stopped = true;
+
+ // make sure timelimit isn't hit while the game is blocked
+ if(autocvar_timelimit > 0)
+ if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
+ cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
+ }
+ }
+ }
+
+ return status;
+}
+
+// spawnfuncs
+spawnfunc(info_player_attacker)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.team = NUM_TEAM_1; // red, gets swapped every round
+ spawnfunc_info_player_deathmatch(this);
+}
+
+spawnfunc(info_player_defender)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.team = NUM_TEAM_2; // blue, gets swapped every round
+ spawnfunc_info_player_deathmatch(this);
+}
+
+spawnfunc(target_objective)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.classname = "target_objective";
+ IL_PUSH(g_assault_objectives, this);
+ this.use = assault_objective_use;
+ this.reset = assault_objective_reset;
+ this.reset(this);
+ this.spawn_evalfunc = target_objective_spawn_evalfunc;
+}
+
+spawnfunc(target_objective_decrease)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.classname = "target_objective_decrease";
+ IL_PUSH(g_assault_objectivedecreasers, this);
+
+ if(!this.dmg)
+ this.dmg = 101;
+
+ this.use = assault_objective_decrease_use;
+ this.health = ASSAULT_VALUE_INACTIVE;
+ this.max_health = ASSAULT_VALUE_INACTIVE;
+ this.enemy = NULL;
+
+ InitializeEntity(this, target_objective_decrease_findtarget, INITPRIO_FINDTARGET);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+spawnfunc(func_breakable);
+spawnfunc(func_assault_destructible)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.spawnflags = 3;
+ this.classname = "func_assault_destructible";
+ IL_PUSH(g_assault_destructibles, this);
+
+ if(assault_attacker_team == NUM_TEAM_1)
+ this.team = NUM_TEAM_2;
+ else
+ this.team = NUM_TEAM_1;
+
+ spawnfunc_func_breakable(this);
+}
+
+spawnfunc(func_assault_wall)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.classname = "func_assault_wall";
+ this.mdl = this.model;
+ _setmodel(this, this.mdl);
+ this.solid = SOLID_BSP;
+ setthink(this, assault_wall_think);
+ this.nextthink = time;
+ InitializeEntity(this, assault_setenemytoobjective, INITPRIO_FINDTARGET);
+}
+
+spawnfunc(target_assault_roundend)
+{
+ if (!g_assault) { delete(this); return; }
+
+ this.winning = 0; // round not yet won by attackers
+ this.classname = "target_assault_roundend";
+ this.use = target_assault_roundend_use;
+ this.cnt = 0; // first round
+ this.reset = target_assault_roundend_reset;
+}
+
+spawnfunc(target_assault_roundstart)
+{
+ if (!g_assault) { delete(this); return; }
+
+ assault_attacker_team = NUM_TEAM_1;
+ this.classname = "target_assault_roundstart";
+ this.use = assault_roundstart_use;
+ this.reset2 = assault_roundstart_use_this;
+ InitializeEntity(this, assault_roundstart_use_this, INITPRIO_FINDTARGET);
+}
+
+// legacy bot code
+void havocbot_goalrating_ast_targets(entity this, float ratingscale)
+{
+ IL_EACH(g_assault_destructibles, it.bot_attack,
+ {
+ if (it.target == "")
+ continue;
+
+ bool found = false;
+ entity destr = it;
+ IL_EACH(g_assault_objectivedecreasers, it.targetname == destr.target,
+ {
+ if(it.enemy.health > 0 && it.enemy.health < ASSAULT_VALUE_INACTIVE)
+ {
+ found = true;
+ break;
+ }
+ });
+
+ if(!found)
+ continue;
+
+ vector p = 0.5 * (it.absmin + it.absmax);
+
+ // Find and rate waypoints around it
+ found = false;
+ entity best = NULL;
+ float bestvalue = 99999999999;
+ entity des = it;
+ for(float radius = 0; radius < 1500 && !found; radius += 500)
+ {
+ FOREACH_ENTITY_RADIUS(p, radius, it.classname == "waypoint" && !(it.wpflags & WAYPOINTFLAG_GENERATED),
+ {
+ if(checkpvs(it.origin, des))
+ {
+ found = true;
+ if(it.cnt < bestvalue)
+ {
+ best = it;
+ bestvalue = it.cnt;
+ }
+ }
+ });
+ }
+
+ if(best)
+ {
+ /// dprint("waypoints around target were found\n");
+ // te_lightning2(NULL, '0 0 0', best.origin);
+ // te_knightspike(best.origin);
+
+ navigation_routerating(this, best, ratingscale, 4000);
+ best.cnt += 1;
+
+ this.havocbot_attack_time = 0;
+
+ if(checkpvs(this.origin + this.view_ofs, it))
+ if(checkpvs(this.origin + this.view_ofs, best))
+ {
+ // dprint("increasing attack time for this target\n");
+ this.havocbot_attack_time = time + 2;
+ }
+ }
+ });
+}
+
+void havocbot_role_ast_offense(entity this)
+{
+ if(IS_DEAD(this))
+ {
+ this.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(this);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 120;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(this);
+ return;
+ }
+
+ if(this.havocbot_attack_time>time)
+ return;
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_enemyplayers(this, 20000, this.origin, 650);
+ havocbot_goalrating_ast_targets(this, 20000);
+ havocbot_goalrating_items(this, 15000, this.origin, 10000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ast_defense(entity this)
+{
+ if(IS_DEAD(this))
+ {
+ this.havocbot_attack_time = 0;
+ havocbot_ast_reset_role(this);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 120;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ast_reset_role(this);
+ return;
+ }
+
+ if(this.havocbot_attack_time>time)
+ return;
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_enemyplayers(this, 20000, this.origin, 3000);
+ havocbot_goalrating_ast_targets(this, 20000);
+ havocbot_goalrating_items(this, 15000, this.origin, 10000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ast_setrole(entity this, float role)
+{
+ switch(role)
+ {
+ case HAVOCBOT_AST_ROLE_DEFENSE:
+ this.havocbot_role = havocbot_role_ast_defense;
+ this.havocbot_role_flags = HAVOCBOT_AST_ROLE_DEFENSE;
+ this.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_AST_ROLE_OFFENSE:
+ this.havocbot_role = havocbot_role_ast_offense;
+ this.havocbot_role_flags = HAVOCBOT_AST_ROLE_OFFENSE;
+ this.havocbot_role_timeout = 0;
+ break;
+ }
+}
+
+void havocbot_ast_reset_role(entity this)
+{
+ if(IS_DEAD(this))
+ return;
+
+ if(this.team == assault_attacker_team)
+ havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_OFFENSE);
+ else
+ havocbot_role_ast_setrole(this, HAVOCBOT_AST_ROLE_DEFENSE);
+}
+
+// mutator hooks
+MUTATOR_HOOKFUNCTION(as, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.team == assault_attacker_team)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_ATTACKING);
+ else
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_ASSAULT_DEFENDING);
+}
+
+MUTATOR_HOOKFUNCTION(as, TurretSpawn)
+{
+ entity turret = M_ARGV(0, entity);
+
+ if(!turret.team || turret.team == FLOAT_MAX)
+ turret.team = 5; // this gets reversed when match starts?
+}
+
+MUTATOR_HOOKFUNCTION(as, VehicleInit)
+{
+ entity veh = M_ARGV(0, entity);
+
+ veh.nextthink = time + 0.5;
+}
+
+MUTATOR_HOOKFUNCTION(as, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ havocbot_ast_reset_role(bot);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, PlayHitsound)
+{
+ entity frag_victim = M_ARGV(0, entity);
+
+ return (frag_victim.classname == "func_assault_destructible");
+}
+
+MUTATOR_HOOKFUNCTION(as, CheckAllowedTeams)
+{
+ // assault always has 2 teams
+ c1 = c2 = 0;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, CheckRules_World)
+{
+ M_ARGV(0, float) = WinningCondition_Assault();
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(as, ReadLevelCvars)
+{
+ // incompatible
+ warmup_stage = 0;
+ sv_ready_restart_after_countdown = 0;
+}
+
+MUTATOR_HOOKFUNCTION(as, OnEntityPreSpawn)
+{
+ entity ent = M_ARGV(0, entity);
+
+ switch(ent.classname)
+ {
+ case "info_player_team1":
+ case "info_player_team2":
+ case "info_player_team3":
+ case "info_player_team4":
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
+{
+ // readyrestart not supported (yet)
+ return true;
+}
+#endif
--- /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 (round_handler_IsActive())
+ if (round_handler_IsRoundStarted())
+ {
+ entity pl = ca_LastPlayerForTeam(this);
+ if (pl)
+ Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerDies)
+{
+ entity frag_target = M_ARGV(2, entity);
+
+ ca_LastPlayerForTeam_Notify(frag_target);
+ if (!allowed_to_spawn)
+ {
+ frag_target.respawn_flags = RESPAWN_SILENT;
+ // prevent unwanted sudden rejoin as spectator and movement of spectator camera
+ frag_target.respawn_time = time + 2;
+ }
+ frag_target.respawn_flags |= RESPAWN_FORCE;
+ if (!warmup_stage)
+ eliminatedPlayers.SendFlags |= 1;
+ if(IS_BOT_CLIENT(frag_target))
+ bot_clear(frag_target);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ if (player.caplayer == 1)
+ ca_LastPlayerForTeam_Notify(player);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ if (!IS_DEAD(player))
+ ca_LastPlayerForTeam_Notify(player);
+ if (player.killindicator_teamchange == -2) // player wants to spectate
+ player.caplayer = 0;
+ if (player.caplayer)
+ player.frags = FRAGS_LMS_LOSER;
+ if (!warmup_stage)
+ eliminatedPlayers.SendFlags |= 1;
+ if (!player.caplayer)
+ return false; // allow team reset
+ return true; // prevent team reset
+}
+
+MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon)
+{
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+ M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SetStartItems)
+{
+ start_items &= ~IT_UNLIMITED_AMMO;
+ start_health = warmup_start_health = cvar("g_lms_start_health");
+ start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor");
+ start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells");
+ start_ammo_nails = warmup_start_ammo_nails = cvar("g_lms_start_ammo_nails");
+ start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+ start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells");
+ start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma");
+ start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
+}
+
+MUTATOR_HOOKFUNCTION(ca, Damage_Calculate)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_deathtype = M_ARGV(3, float);
+ float frag_damage = M_ARGV(4, float);
+ float frag_mirrordamage = M_ARGV(5, float);
+
+ if (IS_PLAYER(frag_target))
+ if (!IS_DEAD(frag_target))
+ if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
+ frag_damage = 0;
+
+ frag_mirrordamage = 0;
+
+ M_ARGV(4, float) = frag_damage;
+ M_ARGV(5, float) = frag_mirrordamage;
+}
+
+MUTATOR_HOOKFUNCTION(ca, FilterItem)
+{
+ entity item = M_ARGV(0, entity);
+
+ if (autocvar_g_powerups <= 0)
+ if (item.flags & FL_POWERUP)
+ return true;
+
+ if (autocvar_g_pickup_items <= 0)
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_damage = M_ARGV(7, float);
+ float damage_take = M_ARGV(4, float);
+ float damage_save = M_ARGV(5, float);
+
+ float excess = max(0, frag_damage - damage_take - damage_save);
+
+ if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
+ GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
+}
+
+MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
+{
+ // no respawn calculations needed, player is forced to spectate anyway
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
+{
+ // no regeneration in CA
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
+{
+ // announce remaining frags
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectateSet)
+{
+ entity client = M_ARGV(0, entity);
+ entity targ = M_ARGV(1, entity);
+
+ if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+ if (DIFF_TEAM(targ, client))
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectateNext)
+{
+ entity client = M_ARGV(0, entity);
+
+ if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+ {
+ entity targ = M_ARGV(1, entity);
+ M_ARGV(1, entity) = CA_SpectateNext(client, targ);
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
+{
+ entity client = M_ARGV(0, entity);
+ entity targ = M_ARGV(1, entity);
+ entity first = M_ARGV(2, entity);
+
+ if (!autocvar_g_ca_spectate_enemies && client.caplayer)
+ {
+ do { targ = targ.chain; }
+ while(targ && DIFF_TEAM(targ, client));
+
+ if (!targ)
+ {
+ for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain);
+
+ if (targ == client.enemy)
+ return MUT_SPECPREV_RETURN;
+ }
+ }
+
+ M_ARGV(1, entity) = targ;
+
+ return MUT_SPECPREV_FOUND;
+}
+
+MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
+{
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+ if (IS_PLAYER(it) || it.caplayer == 1)
+ ++M_ARGV(0, int);
+ ++M_ARGV(1, int);
+ });
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
+{
+ entity player = M_ARGV(0, entity);
+
+ if (player.caplayer)
+ {
+ // they're going to spec, we can do other checks
+ if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
+ Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
+ return MUT_SPECCMD_FORCE;
+ }
+
+ return MUT_SPECCMD_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(ca, WantWeapon)
+{
+ M_ARGV(2, bool) = true; // all weapons
+}
+
+MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
+{
+ return true; // doesn't work well with the whole spectator as player thing
+}
+
+MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus)
+{
+ entity player = M_ARGV(0, entity);
+
+ return player.caplayer == 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
+{
+ // most weapons arena
+ if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
+}
+#endif
--- /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(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+ WaypointSprite_UpdateTeamRadar(player.wps_flagcarrier, RADARICON_FLAGCARRIER, WPCOLOR_FLAGCARRIER(player.team));
+
+ if(player.flagcarried && CTF_SAMETEAM(player, player.flagcarried))
+ {
+ if(!player.wps_enemyflagcarrier)
+ {
+ entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, player, FLAG_WAYPOINT_OFFSET, NULL, 0, player, wps_enemyflagcarrier, true, RADARICON_FLAG);
+ wp.colormod = WPCOLOR_ENEMYFC(player.team);
+ setcefc(wp, ctf_Stalemate_Customize);
+
+ if(IS_REAL_CLIENT(player) && !ctf_stalemate)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_VISIBLE);
+ }
+
+ if(!player.wps_flagreturn)
+ {
+ entity owp = WaypointSprite_SpawnFixed(WP_FlagReturn, player.flagcarried.ctf_spawnorigin + FLAG_WAYPOINT_OFFSET, player, wps_flagreturn, RADARICON_FLAG);
+ owp.colormod = '0 0.8 0.8';
+ //WaypointSprite_UpdateTeamRadar(player.wps_flagreturn, RADARICON_FLAG, ((player.team) ? colormapPaletteColor(player.team - 1, false) : '1 1 1'));
+ setcefc(owp, ctf_Return_Customize);
+ }
+ }
+}
+
+void ctf_CalculatePassVelocity(entity flag, vector to, vector from, float turnrate)
+{
+ float current_distance = vlen((('1 0 0' * to.x) + ('0 1 0' * to.y)) - (('1 0 0' * from.x) + ('0 1 0' * from.y))); // for the sake of this check, exclude Z axis
+ float initial_height = min(autocvar_g_ctf_pass_arc_max, (flag.pass_distance * tanh(autocvar_g_ctf_pass_arc)));
+ float current_height = (initial_height * min(1, (current_distance / flag.pass_distance)));
+ //print("current_height = ", ftos(current_height), ", initial_height = ", ftos(initial_height), ".\n");
+
+ vector targpos;
+ if(current_height) // make sure we can actually do this arcing path
+ {
+ targpos = (to + ('0 0 1' * current_height));
+ WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+ if(trace_fraction < 1)
+ {
+ //print("normal arc line failed, trying to find new pos...");
+ WarpZone_TraceLine(to, targpos, MOVE_NOMONSTERS, flag);
+ targpos = (trace_endpos + FLAG_PASS_ARC_OFFSET);
+ WarpZone_TraceLine(flag.origin, targpos, MOVE_NOMONSTERS, flag);
+ if(trace_fraction < 1) { targpos = to; /* print(" ^1FAILURE^7, reverting to original direction.\n"); */ }
+ /*else { print(" ^3SUCCESS^7, using new arc line.\n"); } */
+ }
+ }
+ else { targpos = to; }
+
+ //flag.angles = normalize(('0 1 0' * to_y) - ('0 1 0' * from_y));
+
+ vector desired_direction = normalize(targpos - from);
+ if(turnrate) { flag.velocity = (normalize(normalize(flag.velocity) + (desired_direction * autocvar_g_ctf_pass_turnrate)) * autocvar_g_ctf_pass_velocity); }
+ else { flag.velocity = (desired_direction * autocvar_g_ctf_pass_velocity); }
+}
+
+bool ctf_CheckPassDirection(vector head_center, vector passer_center, vector passer_angle, vector nearest_to_passer)
+{
+ if(autocvar_g_ctf_pass_directional_max || autocvar_g_ctf_pass_directional_min)
+ {
+ // directional tracing only
+ float spreadlimit;
+ makevectors(passer_angle);
+
+ // find the closest point on the enemy to the center of the attack
+ float h; // hypotenuse, which is the distance between attacker to head
+ float a; // adjacent side, which is the distance between attacker and the point on w_shotdir that is closest to head.origin
+
+ h = vlen(head_center - passer_center);
+ a = h * (normalize(head_center - passer_center) * v_forward);
+
+ vector nearest_on_line = (passer_center + a * v_forward);
+ float distance_from_line = vlen(nearest_to_passer - nearest_on_line);
+
+ spreadlimit = (autocvar_g_ctf_pass_radius ? min(1, (vlen(passer_center - nearest_on_line) / autocvar_g_ctf_pass_radius)) : 1);
+ spreadlimit = (autocvar_g_ctf_pass_directional_min * (1 - spreadlimit) + autocvar_g_ctf_pass_directional_max * spreadlimit);
+
+ if(spreadlimit && (distance_from_line <= spreadlimit) && ((vlen(normalize(head_center - passer_center) - v_forward) * RAD2DEG) <= 90))
+ { return true; }
+ else
+ { return false; }
+ }
+ else { return true; }
+}
+
+
+// =======================
+// CaptureShield Functions
+// =======================
+
+bool ctf_CaptureShield_CheckStatus(entity p)
+{
+ int s, s2, s3, s4, se, se2, se3, se4, sr, ser;
+ int players_worseeq, players_total;
+
+ if(ctf_captureshield_max_ratio <= 0)
+ return false;
+
+ s = GameRules_scoring_add(p, CTF_CAPS, 0);
+ s2 = GameRules_scoring_add(p, CTF_PICKUPS, 0);
+ s3 = GameRules_scoring_add(p, CTF_RETURNS, 0);
+ s4 = GameRules_scoring_add(p, CTF_FCKILLS, 0);
+
+ sr = ((s - s2) + (s3 + s4));
+
+ if(sr >= -ctf_captureshield_min_negscore)
+ return false;
+
+ players_total = players_worseeq = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ if(DIFF_TEAM(it, p))
+ continue;
+ se = GameRules_scoring_add(it, CTF_CAPS, 0);
+ se2 = GameRules_scoring_add(it, CTF_PICKUPS, 0);
+ se3 = GameRules_scoring_add(it, CTF_RETURNS, 0);
+ se4 = GameRules_scoring_add(it, CTF_FCKILLS, 0);
+
+ ser = ((se - se2) + (se3 + se4));
+
+ if(ser <= sr)
+ ++players_worseeq;
+ ++players_total;
+ });
+
+ // player is in the worse half, if >= half the players are better than him, or consequently, if < half of the players are worse
+ // use this rule here
+
+ if(players_worseeq >= players_total * ctf_captureshield_max_ratio)
+ return false;
+
+ return true;
+}
+
+void ctf_CaptureShield_Update(entity player, bool wanted_status)
+{
+ bool updated_status = ctf_CaptureShield_CheckStatus(player);
+ if((wanted_status == player.ctf_captureshielded) && (updated_status != wanted_status)) // 0: shield only, 1: unshield only
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((updated_status) ? CENTER_CTF_CAPTURESHIELD_SHIELDED : CENTER_CTF_CAPTURESHIELD_FREE));
+ player.ctf_captureshielded = updated_status;
+ }
+}
+
+bool ctf_CaptureShield_Customize(entity this, entity client)
+{
+ if(!client.ctf_captureshielded) { return false; }
+ if(CTF_SAMETEAM(this, client)) { return false; }
+
+ return true;
+}
+
+void ctf_CaptureShield_Touch(entity this, entity toucher)
+{
+ if(!toucher.ctf_captureshielded) { return; }
+ if(CTF_SAMETEAM(this, toucher)) { return; }
+
+ vector mymid = (this.absmin + this.absmax) * 0.5;
+ vector theirmid = (toucher.absmin + toucher.absmax) * 0.5;
+
+ Damage(toucher, this, this, 0, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, mymid, normalize(theirmid - mymid) * ctf_captureshield_force);
+ if(IS_REAL_CLIENT(toucher)) { Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
+}
+
+void ctf_CaptureShield_Spawn(entity flag)
+{
+ entity shield = new(ctf_captureshield);
+
+ shield.enemy = flag;
+ shield.team = flag.team;
+ settouch(shield, ctf_CaptureShield_Touch);
+ setcefc(shield, ctf_CaptureShield_Customize);
+ shield.effects = EF_ADDITIVE;
+ set_movetype(shield, MOVETYPE_NOCLIP);
+ shield.solid = SOLID_TRIGGER;
+ shield.avelocity = '7 0 11';
+ shield.scale = 0.5;
+
+ setorigin(shield, flag.origin);
+ setmodel(shield, MDL_CTF_SHIELD);
+ setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
+}
+
+
+// ====================
+// Drop/Pass/Throw Code
+// ====================
+
+void ctf_Handle_Drop(entity flag, entity player, int droptype)
+{
+ // declarations
+ player = (player ? player : flag.pass_sender);
+
+ // main
+ set_movetype(flag, MOVETYPE_TOSS);
+ flag.takedamage = DAMAGE_YES;
+ flag.angles = '0 0 0';
+ flag.health = flag.max_flag_health;
+ flag.ctf_droptime = time;
+ flag.ctf_dropper = player;
+ flag.ctf_status = FLAG_DROPPED;
+
+ // messages and sounds
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
+ ctf_EventLog("dropped", player.team, player);
+
+ // scoring
+ GameRules_scoring_add_team(player, SCORE, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
+ GameRules_scoring_add(player, CTF_DROPS, 1);
+
+ // waypoints
+ if(autocvar_g_ctf_flag_dropped_waypoint) {
+ entity wp = WaypointSprite_Spawn(WP_FlagDropped, 0, 0, flag, FLAG_WAYPOINT_OFFSET, NULL, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG);
+ wp.colormod = WPCOLOR_DROPPEDFLAG(flag.team);
+ }
+
+ if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
+ {
+ WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
+ WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
+ }
+
+ player.throw_antispam = time + autocvar_g_ctf_pass_wait;
+
+ if(droptype == DROP_PASS)
+ {
+ flag.pass_distance = 0;
+ flag.pass_sender = NULL;
+ flag.pass_target = NULL;
+ }
+}
+
+void ctf_Handle_Retrieve(entity flag, entity player)
+{
+ entity sender = flag.pass_sender;
+
+ // transfer flag to player
+ flag.owner = player;
+ flag.owner.flagcarried = flag;
+ GameRules_scoring_vip(player, true);
+
+ // reset flag
+ if(player.vehicle)
+ {
+ setattachment(flag, player.vehicle, "");
+ setorigin(flag, VEHICLE_FLAG_OFFSET);
+ flag.scale = VEHICLE_FLAG_SCALE;
+ }
+ else
+ {
+ setattachment(flag, player, "");
+ setorigin(flag, FLAG_CARRY_OFFSET);
+ }
+ set_movetype(flag, MOVETYPE_NONE);
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_NOT;
+ flag.angles = '0 0 0';
+ flag.ctf_status = FLAG_CARRY;
+
+ // messages and sounds
+ _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
+ ctf_EventLog("receive", flag.team, player);
+
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
+ if(it == sender)
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
+ else if(it == player)
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
+ else if(SAME_TEAM(it, sender))
+ Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
+ });
+
+ // create new waypoint
+ ctf_FlagcarrierWaypoints(player);
+
+ sender.throw_antispam = time + autocvar_g_ctf_pass_wait;
+ player.throw_antispam = sender.throw_antispam;
+
+ flag.pass_distance = 0;
+ flag.pass_sender = NULL;
+ flag.pass_target = NULL;
+}
+
+void ctf_Handle_Throw(entity player, entity receiver, int droptype)
+{
+ entity flag = player.flagcarried;
+ vector targ_origin, flag_velocity;
+
+ if(!flag) { return; }
+ if((droptype == DROP_PASS) && !receiver) { return; }
+
+ if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
+
+ // reset the flag
+ setattachment(flag, NULL, "");
+ setorigin(flag, player.origin + FLAG_DROP_OFFSET);
+ flag.owner.flagcarried = NULL;
+ GameRules_scoring_vip(flag.owner, false);
+ flag.owner = NULL;
+ flag.solid = SOLID_TRIGGER;
+ flag.ctf_dropper = player;
+ flag.ctf_droptime = time;
+ navigation_dynamicgoal_set(flag);
+
+ flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
+
+ switch(droptype)
+ {
+ case DROP_PASS:
+ {
+ // warpzone support:
+ // for the examples, we assume player -> wz1 -> ... -> wzn -> receiver
+ // findradius has already put wzn ... wz1 into receiver's warpzone parameters!
+ WarpZone_RefSys_Copy(flag, receiver);
+ WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
+ targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
+
+ flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' * player.origin.x) + ('0 1 0' * player.origin.y))); // for the sake of this check, exclude Z axis
+ ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
+
+ // main
+ set_movetype(flag, MOVETYPE_FLY);
+ flag.takedamage = DAMAGE_NO;
+ flag.pass_sender = player;
+ flag.pass_target = receiver;
+ flag.ctf_status = FLAG_PASSING;
+
+ // other
+ _sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+ WarpZone_TrailParticles(NULL, _particleeffectnum(flag.passeffect), player.origin, targ_origin);
+ ctf_EventLog("pass", flag.team, player);
+ break;
+ }
+
+ case DROP_THROW:
+ {
+ makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
+
+ flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
+ flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
+ ctf_Handle_Drop(flag, player, droptype);
+ break;
+ }
+
+ case DROP_RESET:
+ {
+ flag.velocity = '0 0 0'; // do nothing
+ break;
+ }
+
+ default:
+ case DROP_NORMAL:
+ {
+ flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
+ ctf_Handle_Drop(flag, player, droptype);
+ break;
+ }
+ }
+
+ // kill old waypointsprite
+ WaypointSprite_Ping(player.wps_flagcarrier);
+ WaypointSprite_Kill(player.wps_flagcarrier);
+
+ if(player.wps_enemyflagcarrier)
+ WaypointSprite_Kill(player.wps_enemyflagcarrier);
+
+ if(player.wps_flagreturn)
+ WaypointSprite_Kill(player.wps_flagreturn);
+
+ // captureshield
+ ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
+}
+
+void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
+{
+ return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
+}
+
+// ==============
+// Event Handlers
+// ==============
+
+void nades_GiveBonus(entity player, float score);
+
+void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
+{
+ entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
+ entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
+ entity player_team_flag = NULL, tmp_entity;
+ float old_time, new_time;
+
+ if(!player) { return; } // without someone to give the reward to, we can't possibly cap
+ if(CTF_DIFFTEAM(player, flag)) { return; }
+ if((flag.cnt || enemy_flag.cnt) && flag.cnt != enemy_flag.cnt) { return; } // this should catch some edge cases (capturing grouped flag at ungrouped flag disallowed etc)
+
+ if (toucher.goalentity == flag.bot_basewaypoint)
+ toucher.goalentity_lock_timeout = 0;
+
+ if(ctf_oneflag)
+ for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+ if(SAME_TEAM(tmp_entity, player))
+ {
+ player_team_flag = tmp_entity;
+ break;
+ }
+
+ nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
+
+ player.throw_prevtime = time;
+ player.throw_count = 0;
+
+ // messages and sounds
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE));
+ ctf_CaptureRecord(enemy_flag, player);
+ _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
+
+ switch(capturetype)
+ {
+ case CAPTURE_NORMAL: ctf_EventLog("capture", enemy_flag.team, player); break;
+ case CAPTURE_DROPPED: ctf_EventLog("droppedcapture", enemy_flag.team, player); break;
+ default: break;
+ }
+
+ // scoring
+ float pscore = 0;
+ if(enemy_flag.score_capture || flag.score_capture)
+ pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5);
+ GameRules_scoring_add_team(player, SCORE, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
+ float capscore = 0;
+ if(enemy_flag.score_team_capture || flag.score_team_capture)
+ capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5);
+ GameRules_scoring_add_team(player, CTF_CAPS, ((capscore) ? capscore : 1));
+
+ old_time = GameRules_scoring_add(player, CTF_CAPTIME, 0);
+ new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
+ if(!old_time || new_time < old_time)
+ GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
+
+ // effects
+ Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
+ //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
+
+ // other
+ if(capturetype == CAPTURE_NORMAL)
+ {
+ WaypointSprite_Kill(player.wps_flagcarrier);
+ if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
+
+ if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
+ { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
+ }
+
+ flag.enemy = toucher;
+
+ // reset the flag
+ player.next_take_time = time + autocvar_g_ctf_flag_collect_delay;
+ ctf_RespawnFlag(enemy_flag);
+}
+
+void ctf_Handle_Return(entity flag, entity player)
+{
+ // messages and sounds
+ if(IS_MONSTER(player))
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name);
+ }
+ else if(flag.team)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
+ }
+ _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
+ ctf_EventLog("return", flag.team, player);
+
+ // scoring
+ if(IS_PLAYER(player))
+ {
+ GameRules_scoring_add_team(player, SCORE, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
+ GameRules_scoring_add(player, CTF_RETURNS, 1); // add to count of returns
+
+ nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
+ }
+
+ TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
+
+ if(flag.ctf_dropper)
+ {
+ GameRules_scoring_add(flag.ctf_dropper, SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
+ ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag
+ flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
+ }
+
+ // other
+ if(player.flagcarried == flag)
+ WaypointSprite_Kill(player.wps_flagcarrier);
+
+ flag.enemy = player;
+
+ // reset the flag
+ ctf_RespawnFlag(flag);
+}
+
+void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
+{
+ // declarations
+ float pickup_dropped_score; // used to calculate dropped pickup score
+
+ // attach the flag to the player
+ flag.owner = player;
+ player.flagcarried = flag;
+ GameRules_scoring_vip(player, true);
+ if(player.vehicle)
+ {
+ setattachment(flag, player.vehicle, "");
+ setorigin(flag, VEHICLE_FLAG_OFFSET);
+ flag.scale = VEHICLE_FLAG_SCALE;
+ }
+ else
+ {
+ setattachment(flag, player, "");
+ setorigin(flag, FLAG_CARRY_OFFSET);
+ }
+
+ // flag setup
+ set_movetype(flag, MOVETYPE_NONE);
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_NOT;
+ flag.angles = '0 0 0';
+ flag.ctf_status = FLAG_CARRY;
+
+ switch(pickuptype)
+ {
+ case PICKUP_BASE: flag.ctf_pickuptime = time; break; // used for timing runs
+ case PICKUP_DROPPED: flag.health = flag.max_flag_health; break; // reset health/return timelimit
+ default: break;
+ }
+
+ // messages and sounds
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
+ if(ctf_stalemate)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
+ if(!flag.team)
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
+ else if(CTF_DIFFTEAM(player, flag))
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
+ else
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
+
+ Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+
+ if(!flag.team)
+ FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
+
+ if(flag.team)
+ FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
+ if(CTF_SAMETEAM(flag, it))
+ if(SAME_TEAM(player, it))
+ Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
+ else
+ Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
+ });
+
+ _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
+
+ // scoring
+ GameRules_scoring_add(player, CTF_PICKUPS, 1);
+ nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
+ switch(pickuptype)
+ {
+ case PICKUP_BASE:
+ {
+ GameRules_scoring_add_team(player, SCORE, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
+ ctf_EventLog("steal", flag.team, player);
+ break;
+ }
+
+ case PICKUP_DROPPED:
+ {
+ pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
+ pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
+ LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
+ GameRules_scoring_add_team(player, SCORE, pickup_dropped_score);
+ ctf_EventLog("pickup", flag.team, player);
+ break;
+ }
+
+ default: break;
+ }
+
+ // speedrunning
+ if(pickuptype == PICKUP_BASE)
+ {
+ flag.speedrunning = player.speedrunning; // if speedrunning, flag will flag-return and teleport the owner back after the record
+ if((player.speedrunning) && (ctf_captimerecord))
+ ctf_FakeTimeLimit(player, time + ctf_captimerecord);
+ }
+
+ // effects
+ Send_Effect_(flag.toucheffect, player.origin, '0 0 0', 1);
+
+ // waypoints
+ if(pickuptype == PICKUP_DROPPED) { WaypointSprite_Kill(flag.wps_flagdropped); }
+ ctf_FlagcarrierWaypoints(player);
+ WaypointSprite_Ping(player.wps_flagcarrier);
+}
+
+
+// ===================
+// Main Flag Functions
+// ===================
+
+void ctf_CheckFlagReturn(entity flag, int returntype)
+{
+ if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
+ {
+ if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
+
+ if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
+ {
+ switch(returntype)
+ {
+ case RETURN_DROPPED:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break;
+ case RETURN_DAMAGE:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
+ case RETURN_SPEEDRUN:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), TIME_ENCODE(ctf_captimerecord)); break;
+ case RETURN_NEEDKILL:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
+ default:
+ case RETURN_TIMEOUT:
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break;
+ }
+ _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
+ ctf_EventLog("returned", flag.team, NULL);
+ flag.enemy = NULL;
+ ctf_RespawnFlag(flag);
+ }
+ }
+}
+
+bool ctf_Stalemate_Customize(entity this, entity client)
+{
+ // make spectators see what the player would see
+ entity e = WaypointSprite_getviewentity(client);
+ entity wp_owner = this.owner;
+
+ // team waypoints
+ //if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
+ if(SAME_TEAM(wp_owner, e)) { return false; }
+ if(!IS_PLAYER(e)) { return false; }
+
+ return true;
+}
+
+void ctf_CheckStalemate()
+{
+ // declarations
+ int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
+ entity tmp_entity;
+
+ entity ctf_staleflaglist = NULL; // reset the list, we need to build the list each time this function runs
+
+ // build list of stale flags
+ for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+ {
+ if(autocvar_g_ctf_stalemate)
+ if(tmp_entity.ctf_status != FLAG_BASE)
+ if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time || !tmp_entity.team) // instant stalemate in oneflag
+ {
+ tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist
+ ctf_staleflaglist = tmp_entity;
+
+ switch(tmp_entity.team)
+ {
+ case NUM_TEAM_1: ++stale_red_flags; break;
+ case NUM_TEAM_2: ++stale_blue_flags; break;
+ case NUM_TEAM_3: ++stale_yellow_flags; break;
+ case NUM_TEAM_4: ++stale_pink_flags; break;
+ default: ++stale_neutral_flags; break;
+ }
+ }
+ }
+
+ if(ctf_oneflag)
+ stale_flags = (stale_neutral_flags >= 1);
+ else
+ stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
+
+ if(ctf_oneflag && stale_flags == 1)
+ ctf_stalemate = true;
+ else if(stale_flags >= 2)
+ ctf_stalemate = true;
+ else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
+ { ctf_stalemate = false; wpforenemy_announced = false; }
+ else if(stale_flags < 2 && autocvar_g_ctf_stalemate_endcondition == 1)
+ { ctf_stalemate = false; wpforenemy_announced = false; }
+
+ // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
+ if(ctf_stalemate)
+ {
+ for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
+ {
+ if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
+ {
+ entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, NULL, 0, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG);
+ wp.colormod = WPCOLOR_ENEMYFC(tmp_entity.owner.team);
+ setcefc(tmp_entity.owner.wps_enemyflagcarrier, ctf_Stalemate_Customize);
+ }
+ }
+
+ if (!wpforenemy_announced)
+ {
+ FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); });
+
+ wpforenemy_announced = true;
+ }
+ }
+}
+
+void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if(ITEM_DAMAGE_NEEDKILL(deathtype))
+ {
+ if(autocvar_g_ctf_flag_return_damage_delay)
+ this.ctf_flagdamaged_byworld = true;
+ else
+ {
+ this.health = 0;
+ ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
+ }
+ return;
+ }
+ if(autocvar_g_ctf_flag_return_damage)
+ {
+ // reduce health and check if it should be returned
+ this.health = this.health - damage;
+ ctf_CheckFlagReturn(this, RETURN_DAMAGE);
+ return;
+ }
+}
+
+void ctf_FlagThink(entity this)
+{
+ // declarations
+ entity tmp_entity;
+
+ this.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
+
+ // captureshield
+ if(this == ctf_worldflaglist) // only for the first flag
+ FOREACH_CLIENT(true, { ctf_CaptureShield_Update(it, 1); }); // release shield only
+
+ // sanity checks
+ if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
+ LOG_TRACE("wtf the flag got squashed?");
+ tracebox(this.origin, this.m_mins, this.m_maxs, this.origin, MOVE_NOMONSTERS, this);
+ if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
+ setsize(this, this.m_mins, this.m_maxs);
+ }
+
+ // main think method
+ switch(this.ctf_status)
+ {
+ case FLAG_BASE:
+ {
+ if(autocvar_g_ctf_dropped_capture_radius)
+ {
+ for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+ if(tmp_entity.ctf_status == FLAG_DROPPED)
+ if(vdist(this.origin - tmp_entity.origin, <, autocvar_g_ctf_dropped_capture_radius))
+ if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
+ ctf_Handle_Capture(this, tmp_entity, CAPTURE_DROPPED);
+ }
+ return;
+ }
+
+ case FLAG_DROPPED:
+ {
+ this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
+
+ if(autocvar_g_ctf_flag_dropped_floatinwater)
+ {
+ vector midpoint = ((this.absmin + this.absmax) * 0.5);
+ if(pointcontents(midpoint) == CONTENT_WATER)
+ {
+ this.velocity = this.velocity * 0.5;
+
+ if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
+ { this.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
+ else
+ { set_movetype(this, MOVETYPE_FLY); }
+ }
+ else if(this.move_movetype == MOVETYPE_FLY) { set_movetype(this, MOVETYPE_TOSS); }
+ }
+ if(autocvar_g_ctf_flag_return_dropped)
+ {
+ if((vdist(this.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_dropped)) || (autocvar_g_ctf_flag_return_dropped == -1))
+ {
+ this.health = 0;
+ ctf_CheckFlagReturn(this, RETURN_DROPPED);
+ return;
+ }
+ }
+ if(this.ctf_flagdamaged_byworld)
+ {
+ this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
+ ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
+ return;
+ }
+ else if(autocvar_g_ctf_flag_return_time)
+ {
+ this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
+ ctf_CheckFlagReturn(this, RETURN_TIMEOUT);
+ return;
+ }
+ return;
+ }
+
+ case FLAG_CARRY:
+ {
+ if(this.speedrunning && ctf_captimerecord && (time >= this.ctf_pickuptime + ctf_captimerecord))
+ {
+ this.health = 0;
+ ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
+
+ CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
+ ImpulseCommands(this.owner);
+ }
+ if(autocvar_g_ctf_stalemate)
+ {
+ if(time >= wpforenemy_nextthink)
+ {
+ ctf_CheckStalemate();
+ wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
+ }
+ }
+ if(CTF_SAMETEAM(this, this.owner) && this.team)
+ {
+ if(autocvar_g_ctf_flag_return) // drop the flag if reverse status has changed
+ ctf_Handle_Throw(this.owner, NULL, DROP_THROW);
+ else if(vdist(this.owner.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_carried_radius))
+ ctf_Handle_Return(this, this.owner);
+ }
+ return;
+ }
+
+ case FLAG_PASSING:
+ {
+ vector targ_origin = ((this.pass_target.absmin + this.pass_target.absmax) * 0.5);
+ targ_origin = WarpZone_RefSys_TransformOrigin(this.pass_target, this, targ_origin); // origin of target as seen by the flag (us)
+ WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
+
+ if((this.pass_target == NULL)
+ || (IS_DEAD(this.pass_target))
+ || (this.pass_target.flagcarried)
+ || (vdist(this.origin - targ_origin, >, autocvar_g_ctf_pass_radius))
+ || ((trace_fraction < 1) && (trace_ent != this.pass_target))
+ || (time > this.ctf_droptime + autocvar_g_ctf_pass_timelimit))
+ {
+ // give up, pass failed
+ ctf_Handle_Drop(this, NULL, DROP_PASS);
+ }
+ else
+ {
+ // still a viable target, go for it
+ ctf_CalculatePassVelocity(this, targ_origin, this.origin, true);
+ }
+ return;
+ }
+
+ default: // this should never happen
+ {
+ LOG_TRACE("ctf_FlagThink(): Flag exists with no status?");
+ return;
+ }
+ }
+}
+
+METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
+{
+ return = false;
+ if(game_stopped) return;
+ if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
+
+ bool is_not_monster = (!IS_MONSTER(toucher));
+
+ // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
+ if(ITEM_TOUCH_NEEDKILL())
+ {
+ if(!autocvar_g_ctf_flag_return_damage_delay)
+ {
+ flag.health = 0;
+ ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
+ }
+ if(!flag.ctf_flagdamaged_byworld) { return; }
+ }
+
+ // special touch behaviors
+ if(STAT(FROZEN, toucher)) { return; }
+ else if(IS_VEHICLE(toucher))
+ {
+ if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
+ toucher = toucher.owner; // the player is actually the vehicle owner, not other
+ else
+ return; // do nothing
+ }
+ else if(IS_MONSTER(toucher))
+ {
+ if(!autocvar_g_ctf_allow_monster_touch)
+ return; // do nothing
+ }
+ else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
+ {
+ if(time > flag.wait) // if we haven't in a while, play a sound/effect
+ {
+ Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
+ _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
+ flag.wait = time + FLAG_TOUCHRATE;
+ }
+ return;
+ }
+ else if(IS_DEAD(toucher)) { return; }
+
+ switch(flag.ctf_status)
+ {
+ case FLAG_BASE:
+ {
+ if(ctf_oneflag)
+ {
+ if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
+ else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
+ }
+ else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
+ ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
+ else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
+ {
+ ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // now pickup the flag
+ }
+ else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
+ ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
+ break;
+ }
+
+ case FLAG_DROPPED:
+ {
+ if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
+ ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
+ else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
+ break;
+ }
+
+ case FLAG_CARRY:
+ {
+ LOG_TRACE("Someone touched a flag even though it was being carried?");
+ break;
+ }
+
+ case FLAG_PASSING:
+ {
+ if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
+ {
+ if(DIFF_TEAM(toucher, flag.pass_sender))
+ {
+ if(ctf_Immediate_Return_Allowed(flag, toucher))
+ ctf_Handle_Return(flag, toucher);
+ else if(is_not_monster && (!toucher.flagcarried))
+ ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
+ }
+ else if(!toucher.flagcarried)
+ ctf_Handle_Retrieve(flag, toucher);
+ }
+ break;
+ }
+ }
+}
+
+.float last_respawn;
+void ctf_RespawnFlag(entity flag)
+{
+ // check for flag respawn being called twice in a row
+ if(flag.last_respawn > time - 0.5)
+ { backtrace("flag respawn called twice quickly! please notify Samual about this..."); }
+
+ flag.last_respawn = time;
+
+ // reset the player (if there is one)
+ if((flag.owner) && (flag.owner.flagcarried == flag))
+ {
+ WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
+ WaypointSprite_Kill(flag.owner.wps_flagreturn);
+ WaypointSprite_Kill(flag.wps_flagcarrier);
+
+ flag.owner.flagcarried = NULL;
+ GameRules_scoring_vip(flag.owner, false);
+
+ if(flag.speedrunning)
+ ctf_FakeTimeLimit(flag.owner, -1);
+ }
+
+ if((flag.owner) && (flag.owner.vehicle))
+ flag.scale = FLAG_SCALE;
+
+ if(flag.ctf_status == FLAG_DROPPED)
+ { WaypointSprite_Kill(flag.wps_flagdropped); }
+
+ // reset the flag
+ setattachment(flag, NULL, "");
+ setorigin(flag, flag.ctf_spawnorigin);
+
+ set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
+ flag.takedamage = DAMAGE_NO;
+ flag.health = flag.max_flag_health;
+ flag.solid = SOLID_TRIGGER;
+ flag.velocity = '0 0 0';
+ flag.angles = flag.mangle;
+ flag.flags = FL_ITEM | FL_NOTARGET;
+
+ flag.ctf_status = FLAG_BASE;
+ flag.owner = NULL;
+ flag.pass_distance = 0;
+ flag.pass_sender = NULL;
+ flag.pass_target = NULL;
+ flag.ctf_dropper = NULL;
+ flag.ctf_pickuptime = 0;
+ flag.ctf_droptime = 0;
+ flag.ctf_flagdamaged_byworld = false;
+ navigation_dynamicgoal_unset(flag);
+
+ ctf_CheckStalemate();
+}
+
+void ctf_Reset(entity this)
+{
+ if(this.owner && IS_PLAYER(this.owner))
+ ctf_Handle_Throw(this.owner, NULL, DROP_RESET);
+
+ this.enemy = NULL;
+ ctf_RespawnFlag(this);
+}
+
+bool ctf_FlagBase_Customize(entity this, entity client)
+{
+ entity e = WaypointSprite_getviewentity(client);
+ entity wp_owner = this.owner;
+ entity flag = e.flagcarried;
+ if(flag && CTF_SAMETEAM(e, flag))
+ return false;
+ if(flag && (flag.cnt || wp_owner.cnt) && wp_owner.cnt != flag.cnt)
+ return false;
+ return true;
+}
+
+void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map by ctf_FlagSetup()
+{
+ // bot waypoints
+ waypoint_spawnforitem_force(this, this.origin);
+ navigation_dynamicgoal_init(this, true);
+
+ // waypointsprites
+ entity basename;
+ switch (this.team)
+ {
+ case NUM_TEAM_1: basename = WP_FlagBaseRed; break;
+ case NUM_TEAM_2: basename = WP_FlagBaseBlue; break;
+ case NUM_TEAM_3: basename = WP_FlagBaseYellow; break;
+ case NUM_TEAM_4: basename = WP_FlagBasePink; break;
+ default: basename = WP_FlagBaseNeutral; break;
+ }
+
+ entity wp = WaypointSprite_SpawnFixed(basename, this.origin + FLAG_WAYPOINT_OFFSET, this, wps_flagbase, RADARICON_FLAG);
+ wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 1 1');
+ WaypointSprite_UpdateTeamRadar(this.wps_flagbase, RADARICON_FLAG, ((this.team) ? colormapPaletteColor(this.team - 1, false) : '1 1 1'));
+ setcefc(wp, ctf_FlagBase_Customize);
+
+ // captureshield setup
+ ctf_CaptureShield_Spawn(this);
+}
+
+.bool pushable;
+
+void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
+{
+ // main setup
+ flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist
+ ctf_worldflaglist = flag;
+
+ setattachment(flag, NULL, "");
+
+ flag.netname = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
+ flag.team = teamnumber;
+ flag.classname = "item_flag_team";
+ flag.target = "###item###"; // wut?
+ flag.flags = FL_ITEM | FL_NOTARGET;
+ IL_PUSH(g_items, flag);
+ flag.solid = SOLID_TRIGGER;
+ flag.takedamage = DAMAGE_NO;
+ flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
+ flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
+ flag.health = flag.max_flag_health;
+ flag.event_damage = ctf_FlagDamage;
+ flag.pushable = true;
+ flag.teleportable = TELEPORT_NORMAL;
+ flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
+ flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
+ flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
+ if(flag.damagedbycontents)
+ IL_PUSH(g_damagedbycontents, flag);
+ flag.velocity = '0 0 0';
+ flag.mangle = flag.angles;
+ flag.reset = ctf_Reset;
+ settouch(flag, ctf_FlagTouch);
+ setthink(flag, ctf_FlagThink);
+ flag.nextthink = time + FLAG_THINKRATE;
+ flag.ctf_status = FLAG_BASE;
+
+ // crudely force them all to 0
+ if(autocvar_g_ctf_score_ignore_fields)
+ flag.cnt = flag.score_assist = flag.score_team_capture = flag.score_capture = flag.score_drop = flag.score_pickup = flag.score_return = 0;
+
+ string teamname = Static_Team_ColorName_Lower(teamnumber);
+ // appearence
+ if(!flag.scale) { flag.scale = FLAG_SCALE; }
+ if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
+ if(flag.model == "") { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
+ if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
+ if (flag.passeffect == "") { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
+ if (flag.capeffect == "") { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
+
+ // sounds
+#define X(s,b) \
+ if(flag.s == "") flag.s = b; \
+ precache_sound(flag.s);
+
+ X(snd_flag_taken, strzone(SND(CTF_TAKEN(teamnumber))))
+ X(snd_flag_returned, strzone(SND(CTF_RETURNED(teamnumber))))
+ X(snd_flag_capture, strzone(SND(CTF_CAPTURE(teamnumber))))
+ X(snd_flag_dropped, strzone(SND(CTF_DROPPED(teamnumber))))
+ X(snd_flag_respawn, strzone(SND(CTF_RESPAWN)))
+ X(snd_flag_touch, strzone(SND(CTF_TOUCH)))
+ X(snd_flag_pass, strzone(SND(CTF_PASS)))
+#undef X
+
+ // precache
+ precache_model(flag.model);
+
+ // appearence
+ _setmodel(flag, flag.model); // precision set below
+ setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
+ flag.m_mins = flag.mins; // store these for squash checks
+ flag.m_maxs = flag.maxs;
+ setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
+
+ if(autocvar_g_ctf_flag_glowtrails)
+ {
+ switch(teamnumber)
+ {
+ case NUM_TEAM_1: flag.glow_color = 251; break;
+ case NUM_TEAM_2: flag.glow_color = 210; break;
+ case NUM_TEAM_3: flag.glow_color = 110; break;
+ case NUM_TEAM_4: flag.glow_color = 145; break;
+ default: flag.glow_color = 254; break;
+ }
+ flag.glow_size = 25;
+ flag.glow_trail = 1;
+ }
+
+ flag.effects |= EF_LOWPRECISION;
+ if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
+ if(autocvar_g_ctf_dynamiclights)
+ {
+ switch(teamnumber)
+ {
+ case NUM_TEAM_1: flag.effects |= EF_RED; break;
+ case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
+ case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
+ case NUM_TEAM_4: flag.effects |= EF_RED; break;
+ default: flag.effects |= EF_DIMLIGHT; break;
+ }
+ }
+
+ // flag placement
+ if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
+ {
+ flag.dropped_origin = flag.origin;
+ flag.noalign = true;
+ set_movetype(flag, MOVETYPE_NONE);
+ }
+ else // drop to floor, automatically find a platform and set that as spawn origin
+ {
+ flag.noalign = false;
+ droptofloor(flag);
+ set_movetype(flag, MOVETYPE_NONE);
+ }
+
+ InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+// NOTE: LEGACY CODE, needs to be re-written!
+
+void havocbot_ctf_calculate_middlepoint()
+{
+ entity f;
+ vector s = '0 0 0';
+ vector fo = '0 0 0';
+ int n = 0;
+
+ f = ctf_worldflaglist;
+ while (f)
+ {
+ fo = f.origin;
+ s = s + fo;
+ f = f.ctf_worldflagnext;
+ n++;
+ }
+ if(!n)
+ return;
+
+ havocbot_middlepoint = s / n;
+ havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
+
+ havocbot_symmetry_axis_m = 0;
+ havocbot_symmetry_axis_q = 0;
+ if(n == 2)
+ {
+ // for symmetrical editing of waypoints
+ entity f1 = ctf_worldflaglist;
+ entity f2 = f1.ctf_worldflagnext;
+ float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
+ float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
+ havocbot_symmetry_axis_m = m;
+ havocbot_symmetry_axis_q = q;
+ }
+ havocbot_symmetry_origin_order = n;
+}
+
+
+entity havocbot_ctf_find_flag(entity bot)
+{
+ entity f;
+ f = ctf_worldflaglist;
+ while (f)
+ {
+ if (CTF_SAMETEAM(bot, f))
+ return f;
+ f = f.ctf_worldflagnext;
+ }
+ return NULL;
+}
+
+entity havocbot_ctf_find_enemy_flag(entity bot)
+{
+ entity f;
+ f = ctf_worldflaglist;
+ while (f)
+ {
+ if(ctf_oneflag)
+ {
+ if(CTF_DIFFTEAM(bot, f))
+ {
+ if(f.team)
+ {
+ if(bot.flagcarried)
+ return f;
+ }
+ else if(!bot.flagcarried)
+ return f;
+ }
+ }
+ else if (CTF_DIFFTEAM(bot, f))
+ return f;
+ f = f.ctf_worldflagnext;
+ }
+ return NULL;
+}
+
+int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
+{
+ if (!teamplay)
+ return 0;
+
+ int c = 0;
+
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
+ continue;
+
+ if(vdist(it.origin - org, <, tc_radius))
+ ++c;
+ });
+
+ return c;
+}
+
+// unused
+#if 0
+void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale)
+{
+ entity head;
+ head = ctf_worldflaglist;
+ while (head)
+ {
+ if (CTF_SAMETEAM(this, head))
+ break;
+ head = head.ctf_worldflagnext;
+ }
+ if (head)
+ navigation_routerating(this, head, ratingscale, 10000);
+}
+#endif
+
+void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale)
+{
+ entity head;
+ head = ctf_worldflaglist;
+ while (head)
+ {
+ if (CTF_SAMETEAM(this, head))
+ {
+ if (this.flagcarried)
+ if ((this.flagcarried.cnt || head.cnt) && this.flagcarried.cnt != head.cnt)
+ {
+ head = head.ctf_worldflagnext; // skip base if it has a different group
+ continue;
+ }
+ break;
+ }
+ head = head.ctf_worldflagnext;
+ }
+ if (!head)
+ return;
+
+ navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale)
+{
+ entity head;
+ head = ctf_worldflaglist;
+ while (head)
+ {
+ if(ctf_oneflag)
+ {
+ if(CTF_DIFFTEAM(this, head))
+ {
+ if(head.team)
+ {
+ if(this.flagcarried)
+ break;
+ }
+ else if(!this.flagcarried)
+ break;
+ }
+ }
+ else if(CTF_DIFFTEAM(this, head))
+ break;
+ head = head.ctf_worldflagnext;
+ }
+ if (head)
+ navigation_routerating(this, head, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_enemybase(entity this, float ratingscale)
+{
+ if (!bot_waypoints_for_items)
+ {
+ havocbot_goalrating_ctf_enemyflag(this, ratingscale);
+ return;
+ }
+
+ entity head;
+
+ head = havocbot_ctf_find_enemy_flag(this);
+
+ if (!head)
+ return;
+
+ navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_ourstolenflag(entity this, float ratingscale)
+{
+ entity mf;
+
+ mf = havocbot_ctf_find_flag(this);
+
+ if(mf.ctf_status == FLAG_BASE)
+ return;
+
+ if(mf.tag_entity)
+ navigation_routerating(this, mf.tag_entity, ratingscale, 10000);
+}
+
+void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector org, float df_radius)
+{
+ entity head;
+ head = ctf_worldflaglist;
+ while (head)
+ {
+ // flag is out in the field
+ if(head.ctf_status != FLAG_BASE)
+ if(head.tag_entity==NULL) // dropped
+ {
+ if(df_radius)
+ {
+ if(vdist(org - head.origin, <, df_radius))
+ navigation_routerating(this, head, ratingscale, 10000);
+ }
+ else
+ navigation_routerating(this, head, ratingscale, 10000);
+ }
+
+ head = head.ctf_worldflagnext;
+ }
+}
+
+void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
+{
+ IL_EACH(g_items, it.bot_pickup,
+ {
+ // gather health and armor only
+ if (it.solid)
+ if (it.health || it.armorvalue)
+ if (vdist(it.origin - org, <, sradius))
+ {
+ // get the value of the item
+ float t = it.bot_pickupevalfunc(this, it) * 0.0001;
+ if (t > 0)
+ navigation_routerating(this, it, t * ratingscale, 500);
+ }
+ });
+}
+
+void havocbot_ctf_reset_role(entity this)
+{
+ float cdefense, cmiddle, coffense;
+ entity mf, ef;
+ float c;
+
+ if(IS_DEAD(this))
+ return;
+
+ // Check ctf flags
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ mf = havocbot_ctf_find_flag(this);
+ ef = havocbot_ctf_find_enemy_flag(this);
+
+ // Retrieve stolen flag
+ if(mf.ctf_status!=FLAG_BASE)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+ return;
+ }
+
+ // If enemy flag is taken go to the middle to intercept pursuers
+ if(ef.ctf_status!=FLAG_BASE)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+ return;
+ }
+
+ // if there is only me on the team switch to offense
+ c = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
+
+ if(c==1)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
+ return;
+ }
+
+ // Evaluate best position to take
+ // Count mates on middle position
+ cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
+
+ // Count mates on defense position
+ cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
+
+ // Count mates on offense position
+ coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
+
+ if(cdefense<=coffense)
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
+ else if(coffense<=cmiddle)
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
+ else
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+}
+
+void havocbot_role_ctf_carrier(entity this)
+{
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried == NULL)
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+
+ if(ctf_oneflag)
+ havocbot_goalrating_ctf_enemybase(this, 50000);
+ else
+ havocbot_goalrating_ctf_ourbase(this, 50000);
+
+ if(this.health<100)
+ havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+
+ entity head = ctf_worldflaglist;
+ while (head)
+ {
+ if (this.goalentity == head.bot_basewaypoint)
+ {
+ this.goalentity_lock_timeout = time + 5;
+ break;
+ }
+ head = head.ctf_worldflagnext;
+ }
+
+ if (this.goalentity)
+ this.havocbot_cantfindflag = time + 10;
+ else if (time > this.havocbot_cantfindflag)
+ {
+ // Can't navigate to my own base, suicide!
+ // TODO: drop it and wander around
+ Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ return;
+ }
+ }
+}
+
+void havocbot_role_ctf_escort(entity this)
+{
+ entity mf, ef;
+
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ // If enemy flag is back on the base switch to previous role
+ ef = havocbot_ctf_find_enemy_flag(this);
+ if(ef.ctf_status==FLAG_BASE)
+ {
+ this.havocbot_role = this.havocbot_previous_role;
+ this.havocbot_role_timeout = 0;
+ return;
+ }
+
+ // If the flag carrier reached the base switch to defense
+ mf = havocbot_ctf_find_flag(this);
+ if(mf.ctf_status!=FLAG_BASE)
+ if(vdist(ef.origin - mf.dropped_origin, <, 300))
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!this.havocbot_role_timeout)
+ {
+ this.havocbot_role_timeout = time + random() * 30 + 60;
+ }
+
+ // If nothing happened just switch to previous role
+ if (time > this.havocbot_role_timeout)
+ {
+ this.havocbot_role = this.havocbot_previous_role;
+ this.havocbot_role_timeout = 0;
+ return;
+ }
+
+ // Chase the flag carrier
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+
+ havocbot_goalrating_ctf_enemyflag(this, 30000);
+ havocbot_goalrating_ctf_ourstolenflag(this, 40000);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ctf_offense(entity this)
+{
+ entity mf, ef;
+ vector pos;
+
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ // Check flags
+ mf = havocbot_ctf_find_flag(this);
+ ef = havocbot_ctf_find_enemy_flag(this);
+
+ // Own flag stolen
+ if(mf.ctf_status!=FLAG_BASE)
+ {
+ if(mf.tag_entity)
+ pos = mf.tag_entity.origin;
+ else
+ pos = mf.origin;
+
+ // Try to get it if closer than the enemy base
+ if(vlen2(this.origin-ef.dropped_origin)>vlen2(this.origin-pos))
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+ return;
+ }
+ }
+
+ // Escort flag carrier
+ if(ef.ctf_status!=FLAG_BASE)
+ {
+ if(ef.tag_entity)
+ pos = ef.tag_entity.origin;
+ else
+ pos = ef.origin;
+
+ if(vdist(pos - mf.dropped_origin, >, 700))
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_ESCORT);
+ return;
+ }
+ }
+
+ // About to fail, switch to middlefield
+ if(this.health<50)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
+ return;
+ }
+
+ // Set the role timeout if necessary
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 120;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+
+ havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+ havocbot_goalrating_ctf_enemybase(this, 20000);
+ havocbot_goalrating_items(this, 5000, this.origin, 1000);
+ havocbot_goalrating_items(this, 1000, this.origin, 10000);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+// Retriever (temporary role):
+void havocbot_role_ctf_retriever(entity this)
+{
+ entity mf;
+
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ // If flag is back on the base switch to previous role
+ mf = havocbot_ctf_find_flag(this);
+ if(mf.ctf_status==FLAG_BASE)
+ {
+ if (mf.enemy == this) // did this bot return the flag?
+ navigation_goalrating_timeout_force(this);
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 20;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ float rt_radius;
+ rt_radius = 10000;
+
+ navigation_goalrating_start(this);
+
+ havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+ havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
+ havocbot_goalrating_ctf_enemybase(this, 30000);
+ havocbot_goalrating_items(this, 500, this.origin, rt_radius);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ctf_middle(entity this)
+{
+ entity mf;
+
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ mf = havocbot_ctf_find_flag(this);
+ if(mf.ctf_status!=FLAG_BASE)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+ return;
+ }
+
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 10;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ vector org;
+
+ org = havocbot_middlepoint;
+ org.z = this.origin.z;
+
+ navigation_goalrating_start(this);
+
+ havocbot_goalrating_ctf_ourstolenflag(this, 50000);
+ havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
+ havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
+ havocbot_goalrating_items(this, 2500, this.origin, 10000);
+ havocbot_goalrating_ctf_enemybase(this, 2500);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ctf_defense(entity this)
+{
+ entity mf;
+
+ if(IS_DEAD(this))
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+
+ if (this.flagcarried)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
+ return;
+ }
+
+ // If own flag was captured
+ mf = havocbot_ctf_find_flag(this);
+ if(mf.ctf_status!=FLAG_BASE)
+ {
+ havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
+ return;
+ }
+
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + 30;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ havocbot_ctf_reset_role(this);
+ return;
+ }
+ if (navigation_goalrating_timeout(this))
+ {
+ vector org = mf.dropped_origin;
+
+ navigation_goalrating_start(this);
+
+ // if enemies are closer to our base, go there
+ entity closestplayer = NULL;
+ float distance, bestdistance = 10000;
+ FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
+ distance = vlen(org - it.origin);
+ if(distance<bestdistance)
+ {
+ closestplayer = it;
+ bestdistance = distance;
+ }
+ });
+
+ if(closestplayer)
+ if(DIFF_TEAM(closestplayer, this))
+ if(vdist(org - this.origin, >, 1000))
+ if(checkpvs(this.origin,closestplayer)||random()<0.5)
+ havocbot_goalrating_ctf_ourbase(this, 30000);
+
+ havocbot_goalrating_ctf_ourstolenflag(this, 20000);
+ havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
+ havocbot_goalrating_items(this, 5000, this.origin, 10000);
+
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ctf_setrole(entity bot, int role)
+{
+ string s = "(null)";
+ switch(role)
+ {
+ case HAVOCBOT_CTF_ROLE_CARRIER:
+ s = "carrier";
+ bot.havocbot_role = havocbot_role_ctf_carrier;
+ bot.havocbot_role_timeout = 0;
+ bot.havocbot_cantfindflag = time + 10;
+ if (bot.havocbot_previous_role != bot.havocbot_role)
+ navigation_goalrating_timeout_force(bot);
+ break;
+ case HAVOCBOT_CTF_ROLE_DEFENSE:
+ s = "defense";
+ bot.havocbot_role = havocbot_role_ctf_defense;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_CTF_ROLE_MIDDLE:
+ s = "middle";
+ bot.havocbot_role = havocbot_role_ctf_middle;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_CTF_ROLE_OFFENSE:
+ s = "offense";
+ bot.havocbot_role = havocbot_role_ctf_offense;
+ bot.havocbot_role_timeout = 0;
+ break;
+ case HAVOCBOT_CTF_ROLE_RETRIEVER:
+ s = "retriever";
+ bot.havocbot_previous_role = bot.havocbot_role;
+ bot.havocbot_role = havocbot_role_ctf_retriever;
+ bot.havocbot_role_timeout = time + 10;
+ if (bot.havocbot_previous_role != bot.havocbot_role)
+ navigation_goalrating_timeout_expire(bot, 2);
+ break;
+ case HAVOCBOT_CTF_ROLE_ESCORT:
+ s = "escort";
+ bot.havocbot_previous_role = bot.havocbot_role;
+ bot.havocbot_role = havocbot_role_ctf_escort;
+ bot.havocbot_role_timeout = time + 30;
+ if (bot.havocbot_previous_role != bot.havocbot_role)
+ navigation_goalrating_timeout_expire(bot, 2);
+ break;
+ }
+ LOG_TRACE(bot.netname, " switched to ", s);
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
+{
+ entity player = M_ARGV(0, entity);
+
+ int t = 0, t2 = 0, t3 = 0;
+ bool b1 = false, b2 = false, b3 = false, b4 = false, b5 = false; // TODO: kill this, we WANT to show the other flags, somehow! (note: also means you don't see if you're FC)
+
+ // initially clear items so they can be set as necessary later.
+ STAT(CTF_FLAGSTATUS, player) &= ~(CTF_RED_FLAG_CARRYING | CTF_RED_FLAG_TAKEN | CTF_RED_FLAG_LOST
+ | CTF_BLUE_FLAG_CARRYING | CTF_BLUE_FLAG_TAKEN | CTF_BLUE_FLAG_LOST
+ | CTF_YELLOW_FLAG_CARRYING | CTF_YELLOW_FLAG_TAKEN | CTF_YELLOW_FLAG_LOST
+ | CTF_PINK_FLAG_CARRYING | CTF_PINK_FLAG_TAKEN | CTF_PINK_FLAG_LOST
+ | CTF_NEUTRAL_FLAG_CARRYING | CTF_NEUTRAL_FLAG_TAKEN | CTF_NEUTRAL_FLAG_LOST
+ | CTF_FLAG_NEUTRAL | CTF_SHIELDED | CTF_STALEMATE);
+
+ // scan through all the flags and notify the client about them
+ for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+ {
+ if(flag.team == NUM_TEAM_1 && !b1) { b1 = true; t = CTF_RED_FLAG_CARRYING; t2 = CTF_RED_FLAG_TAKEN; t3 = CTF_RED_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_2 && !b2) { b2 = true; t = CTF_BLUE_FLAG_CARRYING; t2 = CTF_BLUE_FLAG_TAKEN; t3 = CTF_BLUE_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_3 && !b3) { b3 = true; t = CTF_YELLOW_FLAG_CARRYING; t2 = CTF_YELLOW_FLAG_TAKEN; t3 = CTF_YELLOW_FLAG_LOST; }
+ if(flag.team == NUM_TEAM_4 && !b4) { b4 = true; t = CTF_PINK_FLAG_CARRYING; t2 = CTF_PINK_FLAG_TAKEN; t3 = CTF_PINK_FLAG_LOST; }
+ if(flag.team == 0 && !b5) { b5 = true; t = CTF_NEUTRAL_FLAG_CARRYING; t2 = CTF_NEUTRAL_FLAG_TAKEN; t3 = CTF_NEUTRAL_FLAG_LOST; STAT(CTF_FLAGSTATUS, player) |= CTF_FLAG_NEUTRAL; }
+
+ switch(flag.ctf_status)
+ {
+ case FLAG_PASSING:
+ case FLAG_CARRY:
+ {
+ if((flag.owner == player) || (flag.pass_sender == player))
+ STAT(CTF_FLAGSTATUS, player) |= t; // carrying: player is currently carrying the flag
+ else
+ STAT(CTF_FLAGSTATUS, player) |= t2; // taken: someone else is carrying the flag
+ break;
+ }
+ case FLAG_DROPPED:
+ {
+ STAT(CTF_FLAGSTATUS, player) |= t3; // lost: the flag is dropped somewhere on the map
+ break;
+ }
+ }
+ }
+
+ // item for stopping players from capturing the flag too often
+ if(player.ctf_captureshielded)
+ STAT(CTF_FLAGSTATUS, player) |= CTF_SHIELDED;
+
+ if(ctf_stalemate)
+ STAT(CTF_FLAGSTATUS, player) |= CTF_STALEMATE;
+
+ // update the health of the flag carrier waypointsprite
+ if(player.wps_flagcarrier)
+ WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
+}
+
+MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_damage = M_ARGV(4, float);
+ vector frag_force = M_ARGV(6, vector);
+
+ if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
+ {
+ if(frag_target == frag_attacker) // damage done to yourself
+ {
+ frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor;
+ frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor;
+ }
+ else // damage done to everyone else
+ {
+ frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor;
+ frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
+ }
+
+ M_ARGV(4, float) = frag_damage;
+ M_ARGV(6, vector) = frag_force;
+ }
+ else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
+ {
+ if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
+ if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
+ {
+ frag_target.wps_helpme_time = time;
+ WaypointSprite_HelpMePing(frag_target.wps_flagcarrier);
+ }
+ // todo: add notification for when flag carrier needs help?
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+
+ if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
+ {
+ GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
+ GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
+ }
+
+ if(frag_target.flagcarried)
+ {
+ entity tmp_entity = frag_target.flagcarried;
+ ctf_Handle_Throw(frag_target, NULL, DROP_NORMAL);
+ tmp_entity.ctf_dropper = NULL;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
+{
+ M_ARGV(2, float) = 0; // frag score
+ return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true
+}
+
+void ctf_RemovePlayer(entity player)
+{
+ if(player.flagcarried)
+ { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
+
+ for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+ {
+ if(flag.pass_sender == player) { flag.pass_sender = NULL; }
+ if(flag.pass_target == player) { flag.pass_target = NULL; }
+ if(flag.ctf_dropper == player) { flag.ctf_dropper = NULL; }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ ctf_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ ctf_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, ClientConnect)
+{
+ if(!autocvar_g_ctf_leaderboard)
+ return;
+
+ entity player = M_ARGV(0, entity);
+
+ if(IS_REAL_CLIENT(player))
+ {
+ int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+ race_send_rankings_cnt(MSG_ONE);
+ for (int i = 1; i <= m; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GetPressedKeys)
+{
+ if(!autocvar_g_ctf_leaderboard)
+ return;
+
+ entity player = M_ARGV(0, entity);
+
+ if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
+ {
+ if (!player.stored_netname)
+ player.stored_netname = strzone(uid2name(player.crypto_idfp));
+ if(player.stored_netname != player.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
+ strcpy(player.stored_netname, player.netname);
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.flagcarried)
+ if(!autocvar_g_ctf_portalteleport)
+ { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
+{
+ if(MUTATOR_RETURNVALUE || game_stopped) return;
+
+ entity player = M_ARGV(0, entity);
+
+ if((time > player.throw_antispam) && !IS_DEAD(player) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
+ {
+ // pass the flag to a team mate
+ if(autocvar_g_ctf_pass)
+ {
+ entity head, closest_target = NULL;
+ head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
+
+ while(head) // find the closest acceptable target to pass to
+ {
+ if(IS_PLAYER(head) && !IS_DEAD(head))
+ if(head != player && SAME_TEAM(head, player))
+ if(!head.speedrunning && !head.vehicle)
+ {
+ // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
+ vector head_center = WarpZone_UnTransformOrigin(head, CENTER_OR_VIEWOFS(head));
+ vector passer_center = CENTER_OR_VIEWOFS(player);
+
+ if(ctf_CheckPassDirection(head_center, passer_center, player.v_angle, head.WarpZone_findradius_nearest))
+ {
+ if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried)
+ {
+ if(IS_BOT_CLIENT(head))
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
+ ctf_Handle_Throw(head, player, DROP_PASS);
+ }
+ else
+ {
+ Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname);
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
+ }
+ player.throw_antispam = time + autocvar_g_ctf_pass_wait;
+ return true;
+ }
+ else if(player.flagcarried && !head.flagcarried)
+ {
+ if(closest_target)
+ {
+ vector closest_target_center = WarpZone_UnTransformOrigin(closest_target, CENTER_OR_VIEWOFS(closest_target));
+ if(vlen2(passer_center - head_center) < vlen2(passer_center - closest_target_center))
+ { closest_target = head; }
+ }
+ else { closest_target = head; }
+ }
+ }
+ }
+ head = head.chain;
+ }
+
+ if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
+ }
+
+ // throw the flag in front of you
+ if(autocvar_g_ctf_throw && player.flagcarried)
+ {
+ if(player.throw_count == -1)
+ {
+ if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_delay)
+ {
+ player.throw_prevtime = time;
+ player.throw_count = 1;
+ ctf_Handle_Throw(player, NULL, DROP_THROW);
+ return true;
+ }
+ else
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
+ return false;
+ }
+ }
+ else
+ {
+ if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_time) { player.throw_count = 1; }
+ else { player.throw_count += 1; }
+ if(player.throw_count >= autocvar_g_ctf_throw_punish_count) { player.throw_count = -1; }
+
+ player.throw_prevtime = time;
+ ctf_Handle_Throw(player, NULL, DROP_THROW);
+ return true;
+ }
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, HelpMePing)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
+ {
+ player.wps_helpme_time = time;
+ WaypointSprite_HelpMePing(player.wps_flagcarrier);
+ }
+ else // create a normal help me waypointsprite
+ {
+ WaypointSprite_Spawn(WP_Helpme, waypointsprite_deployed_lifetime, waypointsprite_limitedrange, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_helpme, false, RADARICON_HELPME);
+ WaypointSprite_Ping(player.wps_helpme);
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, VehicleEnter)
+{
+ entity player = M_ARGV(0, entity);
+ entity veh = M_ARGV(1, entity);
+
+ if(player.flagcarried)
+ {
+ if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
+ {
+ ctf_Handle_Throw(player, NULL, DROP_NORMAL);
+ }
+ else
+ {
+ player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
+ setattachment(player.flagcarried, veh, "");
+ setorigin(player.flagcarried, VEHICLE_FLAG_OFFSET);
+ player.flagcarried.scale = VEHICLE_FLAG_SCALE;
+ //player.flagcarried.angles = '0 0 0';
+ }
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, VehicleExit)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.flagcarried)
+ {
+ setattachment(player.flagcarried, player, "");
+ setorigin(player.flagcarried, FLAG_CARRY_OFFSET);
+ player.flagcarried.scale = FLAG_SCALE;
+ player.flagcarried.angles = '0 0 0';
+ player.flagcarried.nodrawtoclient = NULL;
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.flagcarried)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN));
+ ctf_RespawnFlag(player.flagcarried);
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, MatchEnd)
+{
+ entity flag; // temporary entity for the search method
+
+ for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
+ {
+ switch(flag.ctf_status)
+ {
+ case FLAG_DROPPED:
+ case FLAG_PASSING:
+ {
+ // lock the flag, game is over
+ set_movetype(flag, MOVETYPE_NONE);
+ flag.takedamage = DAMAGE_NO;
+ flag.solid = SOLID_NOT;
+ flag.nextthink = false; // stop thinking
+
+ //dprint("stopping the ", flag.netname, " from moving.\n");
+ break;
+ }
+
+ default:
+ case FLAG_BASE:
+ case FLAG_CARRY:
+ {
+ // do nothing for these flags
+ break;
+ }
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ havocbot_ctf_reset_role(bot);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
+{
+ //M_ARGV(0, float) = ctf_teams;
+ M_ARGV(1, string) = "ctf_team";
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
+{
+ entity spectatee = M_ARGV(0, entity);
+ entity client = M_ARGV(1, entity);
+
+ STAT(CTF_FLAGSTATUS, client) = STAT(CTF_FLAGSTATUS, spectatee);
+}
+
+MUTATOR_HOOKFUNCTION(ctf, GetRecords)
+{
+ int record_page = M_ARGV(0, int);
+ string ret_string = M_ARGV(1, string);
+
+ for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+ {
+ if (MapInfo_Get_ByID(i))
+ {
+ float r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
+
+ if(!r)
+ continue;
+
+ // TODO: uid2name
+ string h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
+ ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
+ }
+ }
+
+ M_ARGV(1, string) = ret_string;
+}
+
+bool superspec_Spectate(entity this, entity targ); // TODO
+void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel); // TODO
+MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
+{
+ entity player = M_ARGV(0, entity);
+ string cmd_name = M_ARGV(1, string);
+ int cmd_argc = M_ARGV(2, int);
+
+ if(IS_PLAYER(player) || MUTATOR_RETURNVALUE || !cvar("g_superspectate")) { return false; }
+
+ if(cmd_name == "followfc")
+ {
+ if(!g_ctf)
+ return true;
+
+ int _team = 0;
+ bool found = false;
+
+ if(cmd_argc == 2)
+ {
+ switch(argv(1))
+ {
+ case "red": if(ctf_teams & BIT(0)) _team = NUM_TEAM_1; break;
+ case "blue": if(ctf_teams & BIT(1)) _team = NUM_TEAM_2; break;
+ case "yellow": if(ctf_teams & BIT(2)) _team = NUM_TEAM_3; break;
+ case "pink": if(ctf_teams & BIT(3)) _team = NUM_TEAM_4; break;
+ }
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ if(it.flagcarried && (it.team == _team || _team == 0))
+ {
+ found = true;
+ if(_team == 0 && IS_SPEC(player) && player.enemy == it)
+ continue; // already spectating this fc, try another
+ return superspec_Spectate(player, it);
+ }
+ });
+
+ if(!found)
+ superspec_msg("", "", player, "No active flag carrier\n", 1);
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
+{
+ entity frag_target = M_ARGV(0, entity);
+
+ if(frag_target.flagcarried)
+ ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
+}
+
+
+// ==========
+// Spawnfuncs
+// ==========
+
+/*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team one (Red).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team1)
+{
+ if(!g_ctf) { delete(this); return; }
+
+ ctf_FlagSetup(NUM_TEAM_1, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team two (Blue).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red and blue as skins 0 and 1...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team2)
+{
+ if(!g_ctf) { delete(this); return; }
+
+ ctf_FlagSetup(NUM_TEAM_2, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team3 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team three (Yellow).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team3)
+{
+ if(!g_ctf) { delete(this); return; }
+
+ ctf_FlagSetup(NUM_TEAM_3, this);
+}
+
+/*QUAKED spawnfunc_item_flag_team4 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag for team four (Pink).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_team4)
+{
+ if(!g_ctf) { delete(this); return; }
+
+ ctf_FlagSetup(NUM_TEAM_4, this);
+}
+
+/*QUAKED spawnfunc_item_flag_neutral (0 0.5 0.8) (-48 -48 -37) (48 48 37)
+CTF flag (Neutral).
+Keys:
+"angle" Angle the flag will point (minus 90 degrees)...
+"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
+"noise" sound played when flag is picked up...
+"noise1" sound played when flag is returned by a teammate...
+"noise2" sound played when flag is captured...
+"noise3" sound played when flag is lost in the field and respawns itself...
+"noise4" sound played when flag is dropped by a player...
+"noise5" sound played when flag touches the ground... */
+spawnfunc(item_flag_neutral)
+{
+ if(!g_ctf) { delete(this); return; }
+ if(!cvar("g_ctf_oneflag")) { delete(this); return; }
+
+ ctf_FlagSetup(0, this);
+}
+
+/*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
+Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
+Note: If you use spawnfunc_ctf_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too.
+Keys:
+"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
+"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
+spawnfunc(ctf_team)
+{
+ if(!g_ctf) { delete(this); return; }
+
+ this.classname = "ctf_team";
+ this.team = this.cnt + 1;
+}
+
+// compatibility for quake maps
+spawnfunc(team_CTF_redflag) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_CTF_blueflag) { spawnfunc_item_flag_team2(this); }
+spawnfunc(info_player_team1);
+spawnfunc(team_CTF_redplayer) { spawnfunc_info_player_team1(this); }
+spawnfunc(team_CTF_redspawn) { spawnfunc_info_player_team1(this); }
+spawnfunc(info_player_team2);
+spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this); }
+spawnfunc(team_CTF_bluespawn) { spawnfunc_info_player_team2(this); }
+
+spawnfunc(team_CTF_neutralflag) { spawnfunc_item_flag_neutral(this); }
+spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this); }
+
+// compatibility for wop maps
+spawnfunc(team_redplayer) { spawnfunc_info_player_team1(this); }
+spawnfunc(team_blueplayer) { spawnfunc_info_player_team2(this); }
+spawnfunc(team_ctl_redlolly) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_CTL_redlolly) { spawnfunc_item_flag_team1(this); }
+spawnfunc(team_ctl_bluelolly) { spawnfunc_item_flag_team2(this); }
+spawnfunc(team_CTL_bluelolly) { spawnfunc_item_flag_team2(this); }
+
+
+// ==============
+// Initialization
+// ==============
+
+// scoreboard setup
+void ctf_ScoreRules(int teams)
+{
+ CheckAllowedTeams(NULL);
+ GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+ field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+ field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
+ field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
+ field(SP_CTF_PICKUPS, "pickups", 0);
+ field(SP_CTF_FCKILLS, "fckills", 0);
+ field(SP_CTF_RETURNS, "returns", 0);
+ field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
+ });
+}
+
+// code from here on is just to support maps that don't have flag and team entities
+void ctf_SpawnTeam (string teamname, int teamcolor)
+{
+ entity this = new_pure(ctf_team);
+ this.netname = teamname;
+ this.cnt = teamcolor - 1;
+ this.spawnfunc_checked = true;
+ this.team = teamcolor;
+}
+
+void ctf_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+ ctf_teams = 0;
+
+ entity tmp_entity;
+ for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
+ {
+ //if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
+ //if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
+
+ switch(tmp_entity.team)
+ {
+ case NUM_TEAM_1: BITSET_ASSIGN(ctf_teams, BIT(0)); break;
+ case NUM_TEAM_2: BITSET_ASSIGN(ctf_teams, BIT(1)); break;
+ case NUM_TEAM_3: BITSET_ASSIGN(ctf_teams, BIT(2)); break;
+ case NUM_TEAM_4: BITSET_ASSIGN(ctf_teams, BIT(3)); break;
+ }
+ if(tmp_entity.team == 0) { ctf_oneflag = true; }
+ }
+
+ havocbot_ctf_calculate_middlepoint();
+
+ if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
+ {
+ ctf_teams = 0; // so set the default red and blue teams
+ BITSET_ASSIGN(ctf_teams, BIT(0));
+ BITSET_ASSIGN(ctf_teams, BIT(1));
+ }
+
+ //ctf_teams = bound(2, ctf_teams, 4);
+
+ // if no teams are found, spawn defaults
+ if(find(NULL, classname, "ctf_team") == NULL)
+ {
+ LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.");
+ if(ctf_teams & BIT(0))
+ ctf_SpawnTeam("Red", NUM_TEAM_1);
+ if(ctf_teams & BIT(1))
+ ctf_SpawnTeam("Blue", NUM_TEAM_2);
+ if(ctf_teams & BIT(2))
+ ctf_SpawnTeam("Yellow", NUM_TEAM_3);
+ if(ctf_teams & BIT(3))
+ ctf_SpawnTeam("Pink", NUM_TEAM_4);
+ }
+
+ ctf_ScoreRules(ctf_teams);
+}
+
+void ctf_Initialize()
+{
+ ctf_captimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
+
+ ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
+ ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
+ ctf_captureshield_force = autocvar_g_ctf_shield_force;
+
+ InitializeEntity(NULL, ctf_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
--- /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) (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.health = 1; // this is used to indicate that it should be silent
+ e.lip = 0;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerPhysics)
+{
+ entity player = M_ARGV(0, entity);
+ float dt = M_ARGV(1, float);
+
+ player.race_movetime_frac += dt;
+ float f = floor(player.race_movetime_frac);
+ player.race_movetime_frac -= f;
+ player.race_movetime_count += f;
+ player.race_movetime = player.race_movetime_frac + player.race_movetime_count;
+
+#ifdef SVQC
+ if(IS_PLAYER(player))
+ {
+ if (player.race_penalty)
+ if (time > player.race_penalty)
+ player.race_penalty = 0;
+ if(player.race_penalty)
+ {
+ player.velocity = '0 0 0';
+ set_movetype(player, MOVETYPE_NONE);
+ player.disableclientprediction = 2;
+ }
+ }
+#endif
+
+ // force kbd movement for fairness
+ float wishspeed;
+ vector wishvel;
+
+ // if record times matter
+ // ensure nothing EVIL is being done (i.e. div0_evade)
+ // this hinders joystick users though
+ // but it still gives SOME analog control
+ wishvel.x = fabs(CS(player).movement.x);
+ wishvel.y = fabs(CS(player).movement.y);
+ if(wishvel.x != 0 && wishvel.y != 0 && wishvel.x != wishvel.y)
+ {
+ wishvel.z = 0;
+ wishspeed = vlen(wishvel);
+ if(wishvel.x >= 2 * wishvel.y)
+ {
+ // pure X motion
+ if(CS(player).movement.x > 0)
+ CS(player).movement_x = wishspeed;
+ else
+ CS(player).movement_x = -wishspeed;
+ CS(player).movement_y = 0;
+ }
+ else if(wishvel.y >= 2 * wishvel.x)
+ {
+ // pure Y motion
+ CS(player).movement_x = 0;
+ if(CS(player).movement.y > 0)
+ CS(player).movement_y = wishspeed;
+ else
+ CS(player).movement_y = -wishspeed;
+ }
+ else
+ {
+ // diagonal
+ if(CS(player).movement.x > 0)
+ CS(player).movement_x = M_SQRT1_2 * wishspeed;
+ else
+ CS(player).movement_x = -M_SQRT1_2 * wishspeed;
+ if(CS(player).movement.y > 0)
+ CS(player).movement_y = M_SQRT1_2 * wishspeed;
+ else
+ CS(player).movement_y = -M_SQRT1_2 * wishspeed;
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, reset_map_global)
+{
+ float s;
+
+ Score_NicePrint(NULL);
+
+ race_ClearRecords();
+ PlayerScore_Sort(race_place, 0, 1, 0);
+
+ FOREACH_CLIENT(true, {
+ if(it.race_place)
+ {
+ s = GameRules_scoring_add(it, RACE_FASTEST, 0);
+ if(!s)
+ it.race_place = 0;
+ }
+ cts_EventLog(ftos(it.race_place), it);
+ });
+
+ if(g_race_qualifying == 2)
+ {
+ g_race_qualifying = 0;
+ independent_players = 0;
+ cvar_set("fraglimit", ftos(race_fraglimit));
+ cvar_set("leadlimit", ftos(race_leadlimit));
+ cvar_set("timelimit", ftos(race_timelimit));
+ cts_ScoreRules();
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ClientConnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ race_PreparePlayer(player);
+ player.race_checkpoint = -1;
+
+ if(IS_REAL_CLIENT(player))
+ {
+ string rr = CTS_RECORD;
+
+ msg_entity = player;
+ race_send_recordtime(MSG_ONE);
+ race_send_speedaward(MSG_ONE);
+
+ speedaward_alltimebest = stof(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed")));
+ speedaward_alltimebest_holder = uid2name(db_get(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp")));
+ race_send_speedaward_alltimebest(MSG_ONE);
+
+ float i;
+ int m = min(RANKINGS_CNT, autocvar_g_cts_send_rankings_cnt);
+ race_send_rankings_cnt(MSG_ONE);
+ for (i = 1; i <= m; ++i)
+ {
+ race_SendRankings(i, 0, 0, MSG_ONE);
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, AbortSpeedrun)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(autocvar_g_allow_checkpoints)
+ race_PreparePlayer(player); // nice try
+}
+
+MUTATOR_HOOKFUNCTION(cts, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(GameRules_scoring_add(player, RACE_FASTEST, 0))
+ player.frags = FRAGS_LMS_LOSER;
+ else
+ player.frags = FRAGS_SPECTATOR;
+
+ race_PreparePlayer(player);
+ player.race_checkpoint = -1;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+ entity spawn_spot = M_ARGV(1, entity);
+
+ if(spawn_spot.target == "")
+ // Emergency: this wasn't a real spawnpoint. Can this ever happen?
+ race_PreparePlayer(player);
+
+ // if we need to respawn, do it right
+ player.race_respawn_checkpoint = player.race_checkpoint;
+ player.race_respawn_spotref = spawn_spot;
+
+ player.race_place = 0;
+}
+
+MUTATOR_HOOKFUNCTION(cts, PutClientInServer)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(IS_PLAYER(player))
+ if(!game_stopped)
+ {
+ if(CS(player).killcount == FRAGS_SPECTATOR /* initial spawn */ || g_race_qualifying) // spawn
+ race_PreparePlayer(player);
+ else // respawn
+ race_RetractPlayer(player);
+
+ race_AbandonRaceCheck(player);
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, PlayerDies)
+{
+ entity frag_target = M_ARGV(2, entity);
+
+ frag_target.respawn_flags |= RESPAWN_FORCE;
+ race_AbandonRaceCheck(frag_target);
+}
+
+MUTATOR_HOOKFUNCTION(cts, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ bot.havocbot_role = havocbot_role_cts;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, GetPressedKeys)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
+ {
+ if (!player.stored_netname)
+ player.stored_netname = strzone(uid2name(player.crypto_idfp));
+ if(player.stored_netname != player.netname)
+ {
+ db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
+ strcpy(player.stored_netname, player.netname);
+ }
+ }
+
+ if (!IS_OBSERVER(player))
+ {
+ if(vdist(player.velocity - player.velocity_z * '0 0 1', >, speedaward_speed))
+ {
+ speedaward_speed = vlen(player.velocity - player.velocity_z * '0 0 1');
+ speedaward_holder = player.netname;
+ speedaward_uid = player.crypto_idfp;
+ speedaward_lastupdate = time;
+ }
+ if (speedaward_speed > speedaward_lastsent && time - speedaward_lastupdate > 1)
+ {
+ string rr = CTS_RECORD;
+ race_send_speedaward(MSG_ALL);
+ speedaward_lastsent = speedaward_speed;
+ if (speedaward_speed > speedaward_alltimebest && speedaward_uid != "")
+ {
+ speedaward_alltimebest = speedaward_speed;
+ speedaward_alltimebest_holder = speedaward_holder;
+ speedaward_alltimebest_uid = speedaward_uid;
+ db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/speed"), ftos(speedaward_alltimebest));
+ db_put(ServerProgsDB, strcat(GetMapname(), rr, "speed/crypto_idfp"), speedaward_alltimebest_uid);
+ race_send_speedaward_alltimebest(MSG_ALL);
+ }
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidThrowCurrentWeapon)
+{
+ // no weapon dropping in CTS
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, FilterItem)
+{
+ entity item = M_ARGV(0, entity);
+
+ if (Item_IsLoot(item))
+ {
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, Damage_Calculate)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_deathtype = M_ARGV(3, float);
+ float frag_damage = M_ARGV(4, float);
+
+ if(frag_target == frag_attacker || frag_deathtype == DEATH_FALL.m_id)
+ if(!autocvar_g_cts_selfdamage)
+ {
+ frag_damage = 0;
+ M_ARGV(4, float) = frag_damage;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidPlayerScore_Clear)
+{
+ return true; // in CTS, you don't lose score by observing
+}
+
+MUTATOR_HOOKFUNCTION(cts, GetRecords)
+{
+ int record_page = M_ARGV(0, int);
+ string ret_string = M_ARGV(1, string);
+
+ for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
+ {
+ if(MapInfo_Get_ByID(i))
+ {
+ float r = race_readTime(MapInfo_Map_bspname, 1);
+
+ if(!r)
+ continue;
+
+ string h = race_readName(MapInfo_Map_bspname, 1);
+ ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-8, TIME_ENCODED_TOSTRING(r)), " ", h, "\n");
+ }
+ }
+
+ M_ARGV(1, string) = ret_string;
+}
+
+void ClientKill_Now(entity this);
+MUTATOR_HOOKFUNCTION(cts, ClientKill)
+{
+ entity player = M_ARGV(0, entity);
+
+ M_ARGV(1, float) = 0; // kill delay
+
+ if(player.killindicator && player.killindicator.health == 1) // player.killindicator.health == 1 means that the kill indicator was spawned by CTS_ClientKill
+ {
+ delete(player.killindicator);
+ player.killindicator = NULL;
+
+ ClientKill_Now(player); // allow instant kill in this case
+ return;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(cts, Race_FinalCheckpoint)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(autocvar_g_cts_finish_kill_delay)
+ CTS_ClientKill(player);
+}
+
+MUTATOR_HOOKFUNCTION(cts, HideTeamNagger)
+{
+ return true; // doesn't work so well (but isn't cts a teamless mode?)
+}
+
+MUTATOR_HOOKFUNCTION(cts, FixClientCvars)
+{
+ entity player = M_ARGV(0, entity);
+
+ stuffcmd(player, "cl_cmd settemp cl_movecliptokeyboard 2\n");
+}
+
+MUTATOR_HOOKFUNCTION(cts, WantWeapon)
+{
+ M_ARGV(1, float) = (M_ARGV(0, entity) == WEP_SHOTGUN); // want weapon = weapon info
+ M_ARGV(3, bool) = true; // want mutator blocked
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(cts, ForbidDropCurrentWeapon)
+{
+ return true;
+}
+
+void cts_Initialize()
+{
+ cts_ScoreRules();
+}
+#endif
--- /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 (toucher.health < 1)
+ return;
+
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted())
+ return;
+
+ if(time < this.captime + 0.3)
+ return;
+
+ // only valid teams can claim it
+ entity head = find(NULL, classname, "dom_team");
+ while (head && head.team != toucher.team)
+ head = find(head, classname, "dom_team");
+ if (!head || head.netname == "" || head == this.goalentity)
+ return;
+
+ // delay capture
+
+ this.team = this.goalentity.team; // this stores the PREVIOUS team!
+
+ this.cnt = toucher.team;
+ this.owner = head; // team to switch to after the delay
+ this.dmg_inflictor = toucher;
+
+ // this.state = 1;
+ // this.delay = time + cvar("g_domination_point_capturetime");
+ //this.nextthink = time + cvar("g_domination_point_capturetime");
+ //this.think = dompoint_captured;
+
+ // go to neutral team in the mean time
+ head = find(NULL, classname, "dom_team");
+ while (head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if(head == NULL)
+ return;
+
+ WaypointSprite_UpdateSprites(this.sprite, WP_DomNeut, WP_Null, WP_Null);
+ WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, '0 1 1');
+ WaypointSprite_Ping(this.sprite);
+
+ this.goalentity = head;
+ this.model = head.mdl;
+ this.modelindex = head.dmg;
+ this.skin = head.skin;
+
+ this.enemy = toucher; // individual player scoring
+ this.enemy_playerid = toucher.playerid;
+ dompoint_captured(this);
+}
+
+void dom_controlpoint_setup(entity this)
+{
+ entity head;
+ // find the spawnfunc_dom_team representing unclaimed points
+ head = find(NULL, classname, "dom_team");
+ while(head && head.netname != "")
+ head = find(head, classname, "dom_team");
+ if (!head)
+ objerror(this, "no spawnfunc_dom_team with netname \"\" found\n");
+
+ // copy important properties from spawnfunc_dom_team entity
+ this.goalentity = head;
+ _setmodel(this, head.mdl); // precision already set
+ this.skin = head.skin;
+
+ this.cnt = -1;
+
+ if(this.message == "")
+ this.message = " has captured a control point";
+
+ if(this.frags <= 0)
+ this.frags = 1;
+ if(this.wait <= 0)
+ this.wait = 5;
+
+ float points, waittime;
+ if (autocvar_g_domination_point_amt)
+ points = autocvar_g_domination_point_amt;
+ else
+ points = this.frags;
+ if (autocvar_g_domination_point_rate)
+ waittime = autocvar_g_domination_point_rate;
+ else
+ waittime = this.wait;
+
+ total_pps += points/waittime;
+
+ if(!this.t_width)
+ this.t_width = 0.02; // frame animation rate
+ if(!this.t_length)
+ this.t_length = 239; // maximum frame
+
+ setthink(this, dompointthink);
+ this.nextthink = time;
+ settouch(this, dompointtouch);
+ this.solid = SOLID_TRIGGER;
+ if(!this.flags & FL_ITEM)
+ IL_PUSH(g_items, this);
+ this.flags = FL_ITEM;
+ setsize(this, '-32 -32 -32', '32 32 32');
+ setorigin(this, this.origin + '0 0 20');
+ droptofloor(this);
+
+ waypoint_spawnforitem(this);
+ WaypointSprite_SpawnFixed(WP_DomNeut, this.origin + '0 0 32', this, sprite, RADARICON_DOMPOINT);
+}
+
+float total_controlpoints;
+void Domination_count_controlpoints()
+{
+ total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
+ IL_EACH(g_dompoints, true,
+ {
+ ++total_controlpoints;
+ redowned += (it.goalentity.team == NUM_TEAM_1);
+ blueowned += (it.goalentity.team == NUM_TEAM_2);
+ yellowowned += (it.goalentity.team == NUM_TEAM_3);
+ pinkowned += (it.goalentity.team == NUM_TEAM_4);
+ });
+}
+
+float Domination_GetWinnerTeam()
+{
+ float winner_team = 0;
+ if(redowned == total_controlpoints)
+ winner_team = NUM_TEAM_1;
+ if(blueowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkowned == total_controlpoints)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no control points left?
+}
+
+#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
+#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
+float Domination_CheckWinner()
+{
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+
+ game_stopped = true;
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+ return 1;
+ }
+
+ Domination_count_controlpoints();
+
+ float winner_team = Domination_GetWinnerTeam();
+
+ if(winner_team == -1)
+ return 0;
+
+ if(winner_team > 0)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+ TeamScore_AddToTeam(winner_team, ST_DOM_CAPS, +1);
+ }
+ else if(winner_team == -1)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+ }
+
+ game_stopped = true;
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+
+ return 1;
+}
+
+float Domination_CheckPlayers()
+{
+ return 1;
+}
+
+void Domination_RoundStart()
+{
+ FOREACH_CLIENT(IS_PLAYER(it), { it.player_blocked = false; });
+}
+
+//go to best items, or control points you don't own
+void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
+{
+ IL_EACH(g_dompoints, vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
+ {
+ if(it.cnt > -1) // this is just being fought
+ navigation_routerating(this, it, ratingscale, 5000);
+ else if(it.goalentity.cnt == 0) // unclaimed
+ navigation_routerating(this, it, ratingscale * 0.5, 5000);
+ else if(it.goalentity.team != this.team) // other team's point
+ navigation_routerating(this, it, ratingscale * 0.2, 5000);
+ });
+}
+
+void havocbot_role_dom(entity this)
+{
+ if(IS_DEAD(this))
+ return;
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
+ havocbot_goalrating_items(this, 8000, this.origin, 8000);
+ //havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
+ havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
+{
+ // fallback?
+ M_ARGV(0, float) = domination_teams;
+ string ret_string = "dom_team";
+
+ entity head = find(NULL, classname, ret_string);
+ while(head)
+ {
+ if(head.netname != "")
+ {
+ switch(head.team)
+ {
+ case NUM_TEAM_1: c1 = 0; break;
+ case NUM_TEAM_2: c2 = 0; break;
+ case NUM_TEAM_3: c3 = 0; break;
+ case NUM_TEAM_4: c4 = 0; break;
+ }
+ }
+
+ head = find(head, classname, ret_string);
+ }
+
+ M_ARGV(1, string) = string_null;
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(dom, reset_map_players)
+{
+ total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ PutClientInServer(it);
+ if(domination_roundbased)
+ it.player_blocked = 1;
+ if(IS_REAL_CLIENT(it))
+ set_dom_state(it);
+ });
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(dom, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(domination_roundbased)
+ if(!round_handler_IsRoundStarted())
+ player.player_blocked = 1;
+ else
+ player.player_blocked = 0;
+}
+
+MUTATOR_HOOKFUNCTION(dom, ClientConnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ set_dom_state(player);
+}
+
+MUTATOR_HOOKFUNCTION(dom, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ bot.havocbot_role = havocbot_role_dom;
+ return true;
+}
+
+/*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
+Control point for Domination gameplay.
+*/
+spawnfunc(dom_controlpoint)
+{
+ if(!g_domination)
+ {
+ delete(this);
+ return;
+ }
+ setthink(this, dom_controlpoint_setup);
+ this.nextthink = time + 0.1;
+ this.reset = dom_controlpoint_setup;
+
+ if(!this.scale)
+ this.scale = 0.6;
+
+ this.effects = this.effects | EF_LOWPRECISION;
+ if (autocvar_g_domination_point_fullbright)
+ this.effects |= EF_FULLBRIGHT;
+
+ IL_PUSH(g_dompoints, this);
+}
+
+/*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
+Team declaration for Domination gameplay, this allows you to decide what team
+names and control point models are used in your map.
+
+Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
+can have netname set! The nameless team owns all control points at start.
+
+Keys:
+"netname"
+ Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
+"cnt"
+ Scoreboard color of the team (for example 4 is red and 13 is blue)
+"model"
+ Model to use for control points owned by this team (for example
+ "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
+ keycard)
+"skin"
+ Skin of the model to use (for team skins on a single model)
+"noise"
+ Sound to play when this team captures a point.
+ (this is a localized sound, like a small alarm or other effect)
+"noise1"
+ Narrator speech to play when this team captures a point.
+ (this is a global sound, like "Red team has captured a control point")
+*/
+
+spawnfunc(dom_team)
+{
+ if(!g_domination || autocvar_g_domination_teams_override >= 2)
+ {
+ delete(this);
+ return;
+ }
+ precache_model(this.model);
+ if (this.noise != "")
+ precache_sound(this.noise);
+ if (this.noise1 != "")
+ precache_sound(this.noise1);
+ this.classname = "dom_team";
+ _setmodel(this, this.model); // precision not needed
+ this.mdl = this.model;
+ this.dmg = this.modelindex;
+ this.model = "";
+ this.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ if(this.cnt)
+ this.team = this.cnt + 1; // WHY are these different anyway?
+}
+
+// scoreboard setup
+void ScoreRules_dom(int teams)
+{
+ if(domination_roundbased)
+ {
+ GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
+ field_team(ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
+ field(SP_DOM_TAKES, "takes", 0);
+ });
+ }
+ else
+ {
+ float sp_domticks, sp_score;
+ sp_score = sp_domticks = 0;
+ if(autocvar_g_domination_disable_frags)
+ sp_domticks = SFL_SORT_PRIO_PRIMARY;
+ else
+ sp_score = SFL_SORT_PRIO_PRIMARY;
+ GameRules_scoring(teams, sp_score, sp_score, {
+ field_team(ST_DOM_TICKS, "ticks", sp_domticks);
+ field(SP_DOM_TICKS, "ticks", sp_domticks);
+ field(SP_DOM_TAKES, "takes", 0);
+ });
+ }
+}
+
+// code from here on is just to support maps that don't have control point and team entities
+void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
+{
+ TC(Sound, capsound);
+ entity e = new_pure(dom_team);
+ e.netname = strzone(teamname);
+ e.cnt = teamcolor;
+ e.model = pointmodel;
+ e.skin = pointskin;
+ e.noise = strzone(Sound_fixpath(capsound));
+ e.noise1 = strzone(capnarration);
+ e.message = strzone(capmessage);
+
+ // this code is identical to spawnfunc_dom_team
+ _setmodel(e, e.model); // precision not needed
+ e.mdl = e.model;
+ e.dmg = e.modelindex;
+ e.model = "";
+ e.modelindex = 0;
+ // this would have to be changed if used in quakeworld
+ e.team = e.cnt + 1;
+
+ //eprint(e);
+}
+
+void dom_spawnpoint(vector org)
+{
+ entity e = spawn();
+ e.classname = "dom_controlpoint";
+ setthink(e, spawnfunc_dom_controlpoint);
+ e.nextthink = time;
+ setorigin(e, org);
+ spawnfunc_dom_controlpoint(e);
+}
+
+// spawn some default teams if the map is not set up for domination
+void dom_spawnteams(int teams)
+{
+ TC(int, teams);
+ dom_spawnteam(Team_ColoredFullName(NUM_TEAM_1), NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, SND_DOM_CLAIM, "", "Red team has captured a control point");
+ dom_spawnteam(Team_ColoredFullName(NUM_TEAM_2), NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, SND_DOM_CLAIM, "", "Blue team has captured a control point");
+ if(teams >= 3)
+ dom_spawnteam(Team_ColoredFullName(NUM_TEAM_3), NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, SND_DOM_CLAIM, "", "Yellow team has captured a control point");
+ if(teams >= 4)
+ dom_spawnteam(Team_ColoredFullName(NUM_TEAM_4), NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, SND_DOM_CLAIM, "", "Pink team has captured a control point");
+ dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, SND_Null, "", "");
+}
+
+void dom_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+ // if no teams are found, spawn defaults
+ if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
+ {
+ LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
+ domination_teams = autocvar_g_domination_teams_override;
+ if (domination_teams < 2)
+ domination_teams = autocvar_g_domination_default_teams;
+ domination_teams = bound(2, domination_teams, 4);
+ dom_spawnteams(domination_teams);
+ }
+
+ CheckAllowedTeams(NULL);
+ //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
+
+ int teams = 0;
+ if(c1 >= 0) teams |= BIT(0);
+ if(c2 >= 0) teams |= BIT(1);
+ if(c3 >= 0) teams |= BIT(2);
+ if(c4 >= 0) teams |= BIT(3);
+ domination_teams = teams;
+
+ domination_roundbased = autocvar_g_domination_roundbased;
+
+ ScoreRules_dom(domination_teams);
+
+ if(domination_roundbased)
+ {
+ round_handler_Spawn(Domination_CheckPlayers, Domination_CheckWinner, Domination_RoundStart);
+ round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
+ }
+}
+
+void dom_Initialize()
+{
+ g_domination = true;
+ InitializeEntity(NULL, dom_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
--- /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
+float autocvar_g_freezetag_frozen_maxtime;
+float autocvar_g_freezetag_revive_clearspeed;
+float autocvar_g_freezetag_round_timelimit;
+//int autocvar_g_freezetag_teams;
+int autocvar_g_freezetag_teams_override;
+float autocvar_g_freezetag_warmup;
+
+void freezetag_count_alive_players()
+{
+ total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ switch(it.team)
+ {
+ case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
+ case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
+ case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
+ case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
+ }
+ });
+ FOREACH_CLIENT(IS_REAL_CLIENT(it), {
+ STAT(REDALIVE, it) = redalive;
+ STAT(BLUEALIVE, it) = bluealive;
+ STAT(YELLOWALIVE, it) = yellowalive;
+ STAT(PINKALIVE, it) = pinkalive;
+ });
+
+ eliminatedPlayers.SendFlags |= 1;
+}
+#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
+
+float freezetag_CheckTeams()
+{
+ static float prev_missing_teams_mask;
+ if(FREEZETAG_ALIVE_TEAMS_OK())
+ {
+ if(prev_missing_teams_mask > 0)
+ Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+ prev_missing_teams_mask = -1;
+ return 1;
+ }
+ if(total_players == 0)
+ {
+ if(prev_missing_teams_mask > 0)
+ Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
+ prev_missing_teams_mask = -1;
+ return 0;
+ }
+ int missing_teams_mask = 0;
+ if(freezetag_teams & BIT(0))
+ missing_teams_mask += (!redalive) * 1;
+ if(freezetag_teams & BIT(1))
+ missing_teams_mask += (!bluealive) * 2;
+ if(freezetag_teams & BIT(2))
+ missing_teams_mask += (!yellowalive) * 4;
+ if(freezetag_teams & BIT(3))
+ missing_teams_mask += (!pinkalive) * 8;
+ if(prev_missing_teams_mask != missing_teams_mask)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
+ prev_missing_teams_mask = missing_teams_mask;
+ }
+ return 0;
+}
+
+float freezetag_getWinnerTeam()
+{
+ float winner_team = 0;
+ if(redalive >= 1)
+ winner_team = NUM_TEAM_1;
+ if(bluealive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_2;
+ }
+ if(yellowalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_3;
+ }
+ if(pinkalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = NUM_TEAM_4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no player left
+}
+
+void nades_Clear(entity);
+void nades_GiveBonus(entity player, float score);
+
+float freezetag_CheckWinner()
+{
+ if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ it.freezetag_frozen_timeout = 0;
+ nades_Clear(it);
+ });
+ game_stopped = true;
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+ return 1;
+ }
+
+ if(FREEZETAG_ALIVE_TEAMS() > 1)
+ return 0;
+
+ int winner_team = freezetag_getWinnerTeam();
+ if(winner_team > 0)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+ TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
+ }
+ else if(winner_team == -1)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ it.freezetag_frozen_timeout = 0;
+ nades_Clear(it);
+ });
+
+ game_stopped = true;
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+ return 1;
+}
+
+entity freezetag_LastPlayerForTeam(entity this)
+{
+ entity last_pl = NULL;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
+ if(it.health >= 1)
+ if(!STAT(FROZEN, it))
+ if(SAME_TEAM(it, this))
+ if(!last_pl)
+ last_pl = it;
+ else
+ return NULL;
+ });
+ return last_pl;
+}
+
+void freezetag_LastPlayerForTeam_Notify(entity this)
+{
+ if(round_handler_IsActive())
+ if(round_handler_IsRoundStarted())
+ {
+ entity pl = freezetag_LastPlayerForTeam(this);
+ if(pl)
+ Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
+ }
+}
+
+void freezetag_Add_Score(entity targ, entity attacker)
+{
+ if(attacker == targ)
+ {
+ // you froze your own dumb targ
+ // counted as "suicide" already
+ GameRules_scoring_add(targ, SCORE, -1);
+ }
+ else if(IS_PLAYER(attacker))
+ {
+ // got frozen by an enemy
+ // counted as "kill" and "death" already
+ GameRules_scoring_add(targ, SCORE, -1);
+ GameRules_scoring_add(attacker, SCORE, +1);
+ }
+ // else nothing - got frozen by the game type rules themselves
+}
+
+void freezetag_Freeze(entity targ, entity attacker)
+{
+ if(STAT(FROZEN, targ))
+ return;
+
+ if(autocvar_g_freezetag_frozen_maxtime > 0)
+ targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
+
+ Freeze(targ, 0, 1, true);
+
+ freezetag_count_alive_players();
+
+ freezetag_Add_Score(targ, attacker);
+}
+
+void freezetag_Unfreeze(entity this)
+{
+ this.freezetag_frozen_time = 0;
+ this.freezetag_frozen_timeout = 0;
+
+ Unfreeze(this);
+}
+
+float freezetag_isEliminated(entity e)
+{
+ if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
+ return true;
+ return false;
+}
+
+
+// ================
+// Bot player logic
+// ================
+
+void(entity this) havocbot_role_ft_freeing;
+void(entity this) havocbot_role_ft_offense;
+
+void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
+{
+ float t;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+ if (STAT(FROZEN, it) == 1)
+ {
+ if(vdist(it.origin - org, >, sradius))
+ continue;
+ navigation_routerating(this, it, ratingscale, 2000);
+ }
+ else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
+ {
+ // If teamate is not frozen still seek them out as fight better
+ // in a group.
+ t = 0.2 * 150 / (this.health + this.armorvalue);
+ navigation_routerating(this, it, t * ratingscale, 2000);
+ }
+ });
+}
+
+void havocbot_role_ft_offense(entity this)
+{
+ if(IS_DEAD(this))
+ return;
+
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + random() * 10 + 20;
+
+ // Count how many players on team are unfrozen.
+ int unfrozen = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
+
+ // If only one left on team or if role has timed out then start trying to free players.
+ if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
+ {
+ LOG_TRACE("changing role to freeing");
+ this.havocbot_role = havocbot_role_ft_freeing;
+ this.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+ havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
+ havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+void havocbot_role_ft_freeing(entity this)
+{
+ if(IS_DEAD(this))
+ return;
+
+ if (!this.havocbot_role_timeout)
+ this.havocbot_role_timeout = time + random() * 10 + 20;
+
+ if (time > this.havocbot_role_timeout)
+ {
+ LOG_TRACE("changing role to offense");
+ this.havocbot_role = havocbot_role_ft_offense;
+ this.havocbot_role_timeout = 0;
+ return;
+ }
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_items(this, 8000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
+ havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
+ havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+void ft_RemovePlayer(entity this)
+{
+ this.health = 0; // neccessary to update correctly alive stats
+ if(!STAT(FROZEN, this))
+ freezetag_LastPlayerForTeam_Notify(this);
+ freezetag_Unfreeze(this);
+ freezetag_count_alive_players();
+}
+
+MUTATOR_HOOKFUNCTION(ft, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ ft_RemovePlayer(player);
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ ft_RemovePlayer(player);
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerDies)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_deathtype = M_ARGV(3, float);
+
+ if(round_handler_IsActive())
+ if(round_handler_CountdownRunning())
+ {
+ if(STAT(FROZEN, frag_target))
+ freezetag_Unfreeze(frag_target);
+ freezetag_count_alive_players();
+ return true; // let the player die so that he can respawn whenever he wants
+ }
+
+ // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+ // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+ if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+ || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
+ {
+ // let the player die, he will be automatically frozen when he respawns
+ if(STAT(FROZEN, frag_target) != 1)
+ {
+ freezetag_Add_Score(frag_target, frag_attacker);
+ freezetag_count_alive_players();
+ freezetag_LastPlayerForTeam_Notify(frag_target);
+ }
+ else
+ freezetag_Unfreeze(frag_target); // remove ice
+ frag_target.health = 0; // Unfreeze resets health
+ frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
+ return true;
+ }
+
+ if(STAT(FROZEN, frag_target))
+ return true;
+
+ freezetag_Freeze(frag_target, frag_attacker);
+ freezetag_LastPlayerForTeam_Notify(frag_target);
+
+ if(frag_attacker == frag_target || frag_attacker == NULL)
+ {
+ if(IS_PLAYER(frag_target))
+ Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
+ }
+ else
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+ return true; // do nothing, round is starting right now
+
+ if(player.freezetag_frozen_timeout == -2) // player was dead
+ {
+ freezetag_Freeze(player, NULL);
+ return true;
+ }
+
+ freezetag_count_alive_players();
+
+ if(round_handler_IsActive())
+ if(round_handler_IsRoundStarted())
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
+ freezetag_Freeze(player, NULL);
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, reset_map_players)
+{
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ CS(it).killcount = 0;
+ it.freezetag_frozen_timeout = -1;
+ PutClientInServer(it);
+ it.freezetag_frozen_timeout = 0;
+ });
+ freezetag_count_alive_players();
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
+{
+ M_ARGV(2, float) = 0; // no frags counted in Freeze Tag
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
+{
+ if(game_stopped)
+ return true;
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ return true;
+
+ int n;
+ entity o = NULL;
+ entity player = M_ARGV(0, entity);
+ //if(STAT(FROZEN, player))
+ //if(player.freezetag_frozen_timeout > 0 && time < player.freezetag_frozen_timeout)
+ //player.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (player.freezetag_frozen_timeout - time) / (player.freezetag_frozen_timeout - player.freezetag_frozen_time);
+
+ if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
+ n = -1;
+ else
+ {
+ vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
+ n = 0;
+ FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
+ if(STAT(FROZEN, it) == 0)
+ if(!IS_DEAD(it))
+ if(SAME_TEAM(it, player))
+ if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
+ {
+ if(!o)
+ o = it;
+ if(STAT(FROZEN, player) == 1)
+ it.reviving = true;
+ ++n;
+ }
+ });
+
+ }
+
+ if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
+ {
+ STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
+ player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+
+ if(STAT(REVIVE_PROGRESS, player) >= 1)
+ {
+ freezetag_Unfreeze(player);
+ freezetag_count_alive_players();
+
+ if(n == -1)
+ {
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
+ return true;
+ }
+
+ // EVERY team mate nearby gets a point (even if multiple!)
+ FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
+ GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
+ GameRules_scoring_add(it, SCORE, +1);
+ nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
+ });
+
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
+ Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, o.netname);
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
+ STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
+ it.reviving = false;
+ });
+ }
+ else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
+ {
+ STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
+ player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+ }
+ else if(!n && !STAT(FROZEN, player))
+ {
+ STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, SetStartItems)
+{
+ start_items &= ~IT_UNLIMITED_AMMO;
+ //start_health = warmup_start_health = cvar("g_lms_start_health");
+ //start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor");
+ start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells");
+ start_ammo_nails = warmup_start_ammo_nails = cvar("g_lms_start_ammo_nails");
+ start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
+ start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells");
+ start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma");
+ start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
+}
+
+MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ if (!IS_DEAD(bot))
+ {
+ if (random() < 0.5)
+ bot.havocbot_role = havocbot_role_ft_freeing;
+ else
+ bot.havocbot_role = havocbot_role_ft_offense;
+ }
+
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+ M_ARGV(0, float) = freezetag_teams;
+}
+
+MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
+{
+ // most weapons arena
+ if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+ M_ARGV(0, string) = "most";
+}
+
+MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
+{
+ entity frag_attacker = M_ARGV(0, entity);
+ entity frag_target = M_ARGV(1, entity);
+ //float frag_deathtype = M_ARGV(2, float);
+ int kill_count_to_attacker = M_ARGV(3, int);
+ int kill_count_to_target = M_ARGV(4, int);
+
+ if(STAT(FROZEN, frag_target))
+ return; // target was already frozen, so this is just pushing them off the cliff
+
+ Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
+ Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+
+ return true;
+}
+
+void freezetag_Initialize()
+{
+ freezetag_teams = autocvar_g_freezetag_teams_override;
+ if(freezetag_teams < 2)
+ freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
+
+ freezetag_teams = BITS(bound(2, freezetag_teams, 4));
+ GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
+ field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+ });
+
+ round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
+ round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
+
+ EliminatedPlayers_Init(freezetag_isEliminated);
+}
+#endif
--- /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, it.health > 0,
+ {
+ if((get_monsterinfo(it.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
+ ++supermonster_count;
+ ++total_alive_monsters;
+
+ if(teamplay)
+ switch(it.team)
+ {
+ case NUM_TEAM_1: ++red_alive; break;
+ case NUM_TEAM_2: ++blue_alive; break;
+ case NUM_TEAM_3: ++yellow_alive; break;
+ case NUM_TEAM_4: ++pink_alive; break;
+ }
+ });
+
+ if((total_alive_monsters + inv_numkilled) < inv_maxspawned && inv_maxcurrent < inv_maxspawned)
+ {
+ if(time >= inv_lastcheck)
+ {
+ invasion_SpawnMonsters(supermonster_count);
+ inv_lastcheck = time + autocvar_g_invasion_spawn_delay;
+ }
+
+ return 0;
+ }
+
+ if(inv_numspawned < 1)
+ return 0; // nothing has spawned yet
+
+ if(teamplay)
+ {
+ if(((red_alive > 0) + (blue_alive > 0) + (yellow_alive > 0) + (pink_alive > 0)) > 1)
+ return 0;
+ }
+ else if(inv_numkilled < inv_maxspawned)
+ return 0;
+
+ entity winner = NULL;
+ float winning_score = 0, winner_team = 0;
+
+
+ if(teamplay)
+ {
+ if(red_alive > 0) { winner_team = NUM_TEAM_1; }
+ if(blue_alive > 0)
+ if(winner_team) { winner_team = 0; }
+ else { winner_team = NUM_TEAM_2; }
+ if(yellow_alive > 0)
+ if(winner_team) { winner_team = 0; }
+ else { winner_team = NUM_TEAM_3; }
+ if(pink_alive > 0)
+ if(winner_team) { winner_team = 0; }
+ else { winner_team = NUM_TEAM_4; }
+ }
+ else
+ {
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ float cs = GameRules_scoring_add(it, KILLS, 0);
+ if(cs > winning_score)
+ {
+ winning_score = cs;
+ winner = it;
+ }
+ });
+ }
+
+ IL_EACH(g_monsters, true,
+ {
+ Monster_Remove(it);
+ });
+ IL_CLEAR(g_monsters);
+
+ if(teamplay)
+ {
+ if(winner_team)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
+ }
+ }
+ else if(winner)
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, winner.netname);
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_PLAYER_WIN, winner.netname);
+ }
+
+ round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
+
+ return 1;
+}
+
+bool Invasion_CheckPlayers()
+{
+ return true;
+}
+
+void Invasion_RoundStart()
+{
+ int numplayers = 0;
+ FOREACH_CLIENT(IS_PLAYER(it), {
+ it.player_blocked = false;
+ ++numplayers;
+ });
+
+ if(inv_roundcnt < inv_maxrounds)
+ inv_roundcnt += 1; // a limiter to stop crazy counts
+
+ inv_monsterskill = inv_roundcnt + max(1, numplayers * 0.3);
+
+ inv_maxcurrent = 0;
+ inv_numspawned = 0;
+ inv_numkilled = 0;
+
+ inv_maxspawned = rint(max(autocvar_g_invasion_monster_count, autocvar_g_invasion_monster_count * (inv_roundcnt * 0.5)));
+
+ if(teamplay)
+ {
+ DistributeEvenly_Init(inv_maxspawned, invasion_teams);
+ inv_monsters_perteam[NUM_TEAM_1] = DistributeEvenly_Get(1);
+ inv_monsters_perteam[NUM_TEAM_2] = DistributeEvenly_Get(1);
+ if(invasion_teams >= 3) inv_monsters_perteam[NUM_TEAM_3] = DistributeEvenly_Get(1);
+ if(invasion_teams >= 4) inv_monsters_perteam[NUM_TEAM_4] = DistributeEvenly_Get(1);
+ }
+}
+
+MUTATOR_HOOKFUNCTION(inv, MonsterDies)
+{
+ entity frag_target = M_ARGV(0, entity);
+ entity frag_attacker = M_ARGV(1, entity);
+
+ if(!(frag_target.spawnflags & MONSTERFLAG_RESPAWNED))
+ {
+ if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+ {
+ inv_numkilled += 1;
+ inv_maxcurrent -= 1;
+ }
+ if(teamplay) { inv_monsters_perteam[frag_target.team] -= 1; }
+
+ if(IS_PLAYER(frag_attacker))
+ if(SAME_TEAM(frag_attacker, frag_target)) // in non-teamplay modes, same team = same player, so this works
+ GameRules_scoring_add(frag_attacker, KILLS, -1);
+ else
+ {
+ GameRules_scoring_add(frag_attacker, KILLS, +1);
+ if(teamplay)
+ TeamScore_AddToTeam(frag_attacker.team, ST_INV_KILLS, +1);
+ }
+ }
+}
+
+MUTATOR_HOOKFUNCTION(inv, MonsterSpawn)
+{
+ entity mon = M_ARGV(0, entity);
+ mon.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_BOTCLIP | DPCONTENTS_MONSTERCLIP;
+
+ if(autocvar_g_invasion_type == INV_TYPE_HUNT)
+ return false; // allowed
+
+ if(!(mon.spawnflags & MONSTERFLAG_SPAWNED))
+ return true;
+
+ if(!(mon.spawnflags & MONSTERFLAG_RESPAWNED))
+ {
+ inv_numspawned += 1;
+ inv_maxcurrent += 1;
+ }
+
+ mon.monster_skill = inv_monsterskill;
+
+ if((get_monsterinfo(mon.monsterid)).spawnflags & MON_FLAG_SUPERMONSTER)
+ Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_INVASION_SUPERMONSTER, mon.monster_name);
+}
+
+MUTATOR_HOOKFUNCTION(inv, SV_StartFrame)
+{
+ if(autocvar_g_invasion_type != INV_TYPE_ROUND)
+ return; // uses map spawned monsters
+
+ monsters_total = inv_maxspawned; // TODO: make sure numspawned never exceeds maxspawned
+ monsters_killed = inv_numkilled;
+}
+
+MUTATOR_HOOKFUNCTION(inv, PlayerRegen)
+{
+ // no regeneration in invasion, regardless of the game type
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.bot_attack)
+ IL_REMOVE(g_bot_targets, player);
+ player.bot_attack = false;
+}
+
+MUTATOR_HOOKFUNCTION(inv, Damage_Calculate)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_damage = M_ARGV(4, float);
+ vector frag_force = M_ARGV(6, vector);
+
+ if(IS_PLAYER(frag_attacker) && IS_PLAYER(frag_target) && frag_attacker != frag_target)
+ {
+ frag_damage = 0;
+ frag_force = '0 0 0';
+
+ M_ARGV(4, float) = frag_damage;
+ M_ARGV(6, vector) = frag_force;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(inv, BotShouldAttack)
+{
+ entity targ = M_ARGV(1, entity);
+
+ if(!IS_MONSTER(targ))
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, SetStartItems)
+{
+ if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+ {
+ start_health = 200;
+ start_armorvalue = 200;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(inv, AccuracyTargetValid)
+{
+ entity frag_target = M_ARGV(1, entity);
+
+ if(IS_MONSTER(frag_target))
+ return MUT_ACCADD_INVALID;
+ return MUT_ACCADD_INDIFFERENT;
+}
+
+MUTATOR_HOOKFUNCTION(inv, AllowMobSpawning)
+{
+ // monster spawning disabled during an invasion
+ M_ARGV(1, string) = "You cannot spawn monsters during an invasion!";
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, CheckRules_World)
+{
+ if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+ return false;
+
+ M_ARGV(0, float) = WinningCondition_Invasion();
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(inv, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+{
+ M_ARGV(0, float) = invasion_teams;
+}
+
+MUTATOR_HOOKFUNCTION(inv, AllowMobButcher)
+{
+ M_ARGV(0, string) = "This command does not work during an invasion!";
+ return true;
+}
+
+void invasion_ScoreRules(int inv_teams)
+{
+ if(inv_teams) { CheckAllowedTeams(NULL); }
+ GameRules_score_enabled(false);
+ GameRules_scoring(inv_teams, 0, 0, {
+ if (inv_teams) {
+ field_team(ST_INV_KILLS, "frags", SFL_SORT_PRIO_PRIMARY);
+ }
+ field(SP_KILLS, "frags", ((inv_teams) ? SFL_SORT_PRIO_SECONDARY : SFL_SORT_PRIO_PRIMARY));
+ });
+}
+
+void invasion_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
+{
+ if(autocvar_g_invasion_type == INV_TYPE_HUNT || autocvar_g_invasion_type == INV_TYPE_STAGE)
+ cvar_set("fraglimit", "0");
+
+ if(autocvar_g_invasion_teams)
+ {
+ invasion_teams = BITS(bound(2, autocvar_g_invasion_teams, 4));
+ }
+ else
+ invasion_teams = 0;
+
+ independent_players = 1; // to disable extra useless scores
+
+ invasion_ScoreRules(invasion_teams);
+
+ independent_players = 0;
+
+ if(autocvar_g_invasion_type == INV_TYPE_ROUND)
+ {
+ round_handler_Spawn(Invasion_CheckPlayers, Invasion_CheckWinner, Invasion_RoundStart);
+ round_handler_Init(5, autocvar_g_invasion_warmup, autocvar_g_invasion_round_timelimit);
+
+ inv_roundcnt = 0;
+ inv_maxrounds = 15; // 15?
+ }
+}
+
+void invasion_Initialize()
+{
+ InitializeEntity(NULL, invasion_DelayedInit, INITPRIO_GAMETYPE);
+}
+#endif
--- /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 = (this.health + this.armorvalue) / (ball_owner.health + ball_owner.armorvalue);
+ navigation_routerating(this, ball_owner, t * ratingscale, 2000);
+ }
+ else // Ball has been dropped so collect.
+ navigation_routerating(this, ka_ball, ratingscale, 2000);
+}
+
+void havocbot_role_ka_carrier(entity this)
+{
+ if (IS_DEAD(this))
+ return;
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
+ havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+
+ if (!this.ballcarried)
+ {
+ this.havocbot_role = havocbot_role_ka_collector;
+ navigation_goalrating_timeout_expire(this, 2);
+ }
+}
+
+void havocbot_role_ka_collector(entity this)
+{
+ if (IS_DEAD(this))
+ return;
+
+ if (navigation_goalrating_timeout(this))
+ {
+ navigation_goalrating_start(this);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 1000, this.origin, 10000);
+ havocbot_goalrating_ball(this, 20000, this.origin);
+ navigation_goalrating_end(this);
+
+ navigation_goalrating_timeout_set(this);
+ }
+
+ if (this.ballcarried)
+ {
+ this.havocbot_role = havocbot_role_ka_carrier;
+ navigation_goalrating_timeout_expire(this, 2);
+ }
+}
+
+
+// ==============
+// Hook Functions
+// ==============
+
+MUTATOR_HOOKFUNCTION(ka, PlayerDies)
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+
+ if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)))
+ {
+ if(frag_target.ballcarried) { // add to amount of times killing carrier
+ GameRules_scoring_add(frag_attacker, KEEPAWAY_CARRIERKILLS, 1);
+ if(autocvar_g_keepaway_score_bckill) // add bckills to the score
+ GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_bckill);
+ }
+ else if(!frag_attacker.ballcarried)
+ if(autocvar_g_keepaway_noncarrier_warn)
+ Send_Notification(NOTIF_ONE_ONLY, frag_attacker, MSG_CENTER, CENTER_KEEPAWAY_WARN);
+
+ if(frag_attacker.ballcarried) // add to amount of kills while ballcarrier
+ GameRules_scoring_add(frag_attacker, SCORE, autocvar_g_keepaway_score_killac);
+ }
+
+ if(frag_target.ballcarried) { ka_DropEvent(frag_target); } // a player with the ball has died, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, GiveFragsForKill)
+{
+ M_ARGV(2, float) = 0; // no frags counted in keepaway
+ return true; // you deceptive little bugger ;3 This needs to be true in order for this function to even count.
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPreThink)
+{
+ entity player = M_ARGV(0, entity);
+
+ // clear the item used for the ball in keepaway
+ player.items &= ~IT_KEY1;
+
+ // if the player has the ball, make sure they have the item for it (Used for HUD primarily)
+ if(player.ballcarried)
+ player.items |= IT_KEY1;
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerUseKey)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(MUTATOR_RETURNVALUE == 0)
+ if(player.ballcarried)
+ {
+ ka_DropEvent(player);
+ return true;
+ }
+}
+
+MUTATOR_HOOKFUNCTION(ka, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
+{
+ entity frag_attacker = M_ARGV(1, entity);
+ entity frag_target = M_ARGV(2, entity);
+ float frag_damage = M_ARGV(4, float);
+ vector frag_force = M_ARGV(6, vector);
+
+ if(frag_attacker.ballcarried) // if the attacker is a ballcarrier
+ {
+ if(frag_target == frag_attacker) // damage done to yourself
+ {
+ frag_damage *= autocvar_g_keepaway_ballcarrier_selfdamage;
+ frag_force *= autocvar_g_keepaway_ballcarrier_selfforce;
+ }
+ else // damage done to noncarriers
+ {
+ frag_damage *= autocvar_g_keepaway_ballcarrier_damage;
+ frag_force *= autocvar_g_keepaway_ballcarrier_force;
+ }
+ }
+ else if (!frag_target.ballcarried) // if the target is a noncarrier
+ {
+ if(frag_target == frag_attacker) // damage done to yourself
+ {
+ frag_damage *= autocvar_g_keepaway_noncarrier_selfdamage;
+ frag_force *= autocvar_g_keepaway_noncarrier_selfforce;
+ }
+ else // damage done to other noncarriers
+ {
+ frag_damage *= autocvar_g_keepaway_noncarrier_damage;
+ frag_force *= autocvar_g_keepaway_noncarrier_force;
+ }
+ }
+
+ M_ARGV(4, float) = frag_damage;
+ M_ARGV(6, vector) = frag_force;
+}
+
+MUTATOR_HOOKFUNCTION(ka, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ if(player.ballcarried) { ka_DropEvent(player); } // a player with the ball has left the match, drop it
+}
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPowerups)
+{
+ entity player = M_ARGV(0, entity);
+
+ // In the future this hook is supposed to allow me to do some extra stuff with waypointsprites and invisibility powerup
+ // So bare with me until I can fix a certain bug with ka_ballcarrier_waypointsprite_visible_for_player()
+
+ player.effects &= ~autocvar_g_keepaway_ballcarrier_effects;
+
+ if(player.ballcarried)
+ player.effects |= autocvar_g_keepaway_ballcarrier_effects;
+}
+
+
+MUTATOR_HOOKFUNCTION(ka, PlayerPhysics_UpdateStats)
+{
+ entity player = M_ARGV(0, entity);
+ // these automatically reset, no need to worry
+
+ if(player.ballcarried)
+ STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_keepaway_ballcarrier_highspeed;
+}
+
+MUTATOR_HOOKFUNCTION(ka, BotShouldAttack)
+{
+ entity bot = M_ARGV(0, entity);
+ entity targ = M_ARGV(1, entity);
+
+ // if neither player has ball then don't attack unless the ball is on the ground
+ if(!targ.ballcarried && !bot.ballcarried && ka_ball.owner)
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ka, HavocBot_ChooseRole)
+{
+ entity bot = M_ARGV(0, entity);
+
+ if (bot.ballcarried)
+ bot.havocbot_role = havocbot_role_ka_carrier;
+ else
+ bot.havocbot_role = havocbot_role_ka_collector;
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(ka, DropSpecialItems)
+{
+ entity frag_target = M_ARGV(0, entity);
+
+ if(frag_target.ballcarried)
+ ka_DropEvent(frag_target);
+}
+
+.bool pushable;
+
+// ==============
+// Initialization
+// ==============
+
+MODEL(KA_BALL, "models/orbs/orbblue.md3");
+
+void ka_SpawnBall() // loads various values for the ball, runs only once at start of match
+{
+ entity e = new(keepawayball);
+ setmodel(e, MDL_KA_BALL);
+ setsize(e, '-16 -16 -20', '16 16 20'); // 20 20 20 was too big, player is only 16 16 24... gotta cheat with the Z (20) axis so that the particle isn't cut off
+ e.damageforcescale = autocvar_g_keepawayball_damageforcescale;
+ e.takedamage = DAMAGE_YES;
+ e.solid = SOLID_TRIGGER;
+ set_movetype(e, MOVETYPE_BOUNCE);
+ e.glow_color = autocvar_g_keepawayball_trail_color;
+ e.glow_trail = true;
+ e.flags = FL_ITEM;
+ IL_PUSH(g_items, e);
+ e.pushable = true;
+ e.reset = ka_Reset;
+ settouch(e, ka_TouchEvent);
+ e.owner = NULL;
+ ka_ball = e;
+ navigation_dynamicgoal_init(ka_ball, false);
+
+ InitializeEntity(e, ka_RespawnBall, INITPRIO_SETLOCATION); // is this the right priority? Neh, I have no idea.. Well-- it works! So.
+}
+
+void ka_Initialize() // run at the start of a match, initiates game mode
+{
+ ka_SpawnBall();
+}
+#endif
--- /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
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;
{
.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';
}
}
}
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;
}
// 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 ( ((it.health || it.armorvalue) && needarmor) || (STAT(WEAPONS, it) && needweapons ) )
if (vdist(it.origin - org, <, sradius))
{
int t = it.bot_pickupevalfunc(this, it);
--- /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)
};
#define ITEM_HANDLE(signal, ...) __Item_Send_##signal(__VA_ARGS__)
#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;
#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;
#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;
#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;
#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;
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;
REGISTER_ITEM(ArmorSmall, Armor) {
this.m_canonical_spawnfunc = "item_armor_small";
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_ArmorSmall_ITEM;
this.m_sound = SND_ArmorSmall;
#endif
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;
REGISTER_ITEM(ArmorMedium, Armor) {
this.m_canonical_spawnfunc = "item_armor_medium";
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_ArmorMedium_ITEM;
this.m_sound = SND_ArmorMedium;
#endif
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;
REGISTER_ITEM(ArmorBig, Armor) {
this.m_canonical_spawnfunc = "item_armor_big";
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_ArmorBig_ITEM;
this.m_sound = SND_ArmorBig;
#endif
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;
REGISTER_ITEM(ArmorMega, Armor) {
this.m_canonical_spawnfunc = "item_armor_mega";
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_ArmorMega_ITEM;
this.m_sound = SND_ArmorMega;
#endif
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;
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;
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;
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;
REGISTER_ITEM(HealthMega, Health) {
this.m_canonical_spawnfunc = "item_health_mega";
#ifdef GAMEQC
- this.spawnflags = ITEM_FLAG_NORMAL | ITEM_FLAG_OVERKILL;
+ this.spawnflags = ITEM_FLAG_NORMAL;
this.m_model = MDL_HealthMega_ITEM;
this.m_sound = SND_HealthMega;
#endif
#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;
#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;
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;
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 = this.health / this.max_health;
+ if(h < 0.25)
+ this.colormod = '1 0 0';
+ else if(h <= 0.75)
+ this.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
+ else
+ this.colormod = '1 1 1';
+}
+
+void func_breakable_look_destroyed(entity this)
+{
+ float floorZ;
+
+ if(this.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
+ this.dropped_origin = this.origin;
+
+ if(this.mdl_dead == "")
+ this.effects |= EF_NODRAW;
+ else {
+ if (this.origin == '0 0 0') { // probably no origin brush, so don't spawn in the middle of the map..
+ floorZ = this.absmin.z;
+ setorigin(this, ((this.absmax + this.absmin) * 0.5));
+ this.origin_z = floorZ;
+ }
+ _setmodel(this, this.mdl_dead);
+ ApplyMinMaxScaleAngles(this);
+ this.effects &= ~EF_NODRAW;
+ }
+
+ this.solid = SOLID_NOT;
+}
+
+void func_breakable_look_restore(entity this)
+{
+ _setmodel(this, this.mdl);
+ ApplyMinMaxScaleAngles(this);
+ this.effects &= ~EF_NODRAW;
+
+ if(this.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
+ setorigin(this, this.dropped_origin);
+
+ this.solid = SOLID_BSP;
+}
+
+void func_breakable_behave_destroyed(entity this)
+{
+ this.health = this.max_health;
+ this.takedamage = DAMAGE_NO;
+ if(this.bot_attack)
+ IL_REMOVE(g_bot_targets, this);
+ this.bot_attack = false;
+ this.event_damage = func_null;
+ this.state = STATE_BROKEN;
+ if(this.spawnflags & BREAKABLE_NODAMAGE)
+ this.use = func_null;
+ func_breakable_colormod(this);
+ if (this.noise1)
+ stopsound (this, CH_TRIGGER_SINGLE);
+}
+
+void func_breakable_think(entity this)
+{
+ this.nextthink = time;
+ CSQCMODEL_AUTOUPDATE(this);
+}
+
+void func_breakable_destroy(entity this, entity actor, entity trigger);
+void func_breakable_behave_restore(entity this)
+{
+ this.health = this.max_health;
+ if(this.sprite)
+ {
+ WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
+ WaypointSprite_UpdateHealth(this.sprite, this.health);
+ }
+ if(!(this.spawnflags & BREAKABLE_NODAMAGE))
+ {
+ this.takedamage = DAMAGE_AIM;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
+ this.bot_attack = true;
+ this.event_damage = func_breakable_damage;
+ }
+ if(this.spawnflags & BREAKABLE_NODAMAGE)
+ this.use = func_breakable_destroy; // don't need to set it usually, as .use isn't reset
+ this.state = STATE_ALIVE;
+ //this.nextthink = 0; // cancel auto respawn
+ setthink(this, func_breakable_think);
+ this.nextthink = time + 0.1;
+ func_breakable_colormod(this);
+ if (this.noise1)
+ _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+}
+
+void func_breakable_init_for_player(entity this, entity player)
+{
+ if (this.noise1 && this.state == STATE_ALIVE && IS_REAL_CLIENT(player))
+ {
+ msg_entity = player;
+ soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+ }
+}
+
+void func_breakable_destroyed(entity this)
+{
+ func_breakable_look_destroyed(this);
+ func_breakable_behave_destroyed(this);
+}
+
+void func_breakable_restore(entity this, entity actor, entity trigger)
+{
+ func_breakable_look_restore(this);
+ func_breakable_behave_restore(this);
+}
+
+void func_breakable_restore_self(entity this)
+{
+ func_breakable_restore(this, NULL, NULL);
+}
+
+vector debrisforce; // global, set before calling this
+void func_breakable_destroy(entity this, entity actor, entity trigger)
+{
+ float n, i;
+ string oldmsg;
+
+ entity act = this.owner;
+ this.owner = NULL; // set by W_PrepareExplosionByDamage
+
+ // now throw around the debris
+ n = tokenize_console(this.debris);
+ for(i = 0; i < n; ++i)
+ LaunchDebris(this, argv(i), debrisforce);
+
+ func_breakable_destroyed(this);
+
+ if(this.noise)
+ _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+
+ if(this.dmg)
+ RadiusDamage(this, act, this.dmg, this.dmg_edge, this.dmg_radius, this, NULL, this.dmg_force, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, NULL);
+
+ if(this.cnt) // TODO
+ __pointparticles(this.cnt, this.absmin * 0.5 + this.absmax * 0.5, '0 0 0', this.count);
+
+ if(this.respawntime)
+ {
+ CSQCMODEL_AUTOUPDATE(this);
+ setthink(this, func_breakable_restore_self);
+ this.nextthink = time + this.respawntime + crandom() * this.respawntimejitter;
+ }
+
+ oldmsg = this.message;
+ this.message = "";
+ SUB_UseTargets(this, act, trigger);
+ this.message = oldmsg;
+}
+
+void func_breakable_destroy_self(entity this)
+{
+ func_breakable_destroy(this, NULL, NULL);
+}
+
+void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if(this.state == STATE_BROKEN)
+ return;
+ if(this.spawnflags & NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ if(this.team)
+ if(attacker.team == this.team)
+ return;
+ this.pain_finished = time;
+ this.health = this.health - damage;
+ if(this.sprite)
+ {
+ WaypointSprite_Ping(this.sprite);
+ WaypointSprite_UpdateHealth(this.sprite, this.health);
+ }
+ func_breakable_colormod(this);
+
+ if(this.health <= 0)
+ {
+ debrisforce = force;
+
+ this.takedamage = DAMAGE_NO;
+ this.event_damage = func_null;
+
+ if(IS_CLIENT(attacker)) //&& this.classname == "func_assault_destructible")
+ {
+ this.owner = attacker;
+ this.realowner = attacker;
+ }
+
+ // do not explode NOW but in the NEXT FRAME!
+ // because recursive calls to RadiusDamage are not allowed
+ this.nextthink = time;
+ CSQCMODEL_AUTOUPDATE(this);
+ setthink(this, func_breakable_destroy_self);
+ }
+}
+
+void func_breakable_reset(entity this)
+{
+ this.team = this.team_saved;
+ func_breakable_look_restore(this);
+ if(this.spawnflags & START_DISABLED)
+ func_breakable_behave_destroyed(this);
+ else
+ func_breakable_behave_restore(this);
+}
+
+// destructible walls that can be used to trigger target_objective_decrease
+spawnfunc(func_breakable)
+{
+ float n, i;
+ if(!this.health)
+ this.health = 100;
+ this.max_health = this.health;
+
+ // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
+ if(!this.debrismovetype) this.debrismovetype = MOVETYPE_BOUNCE;
+ if(!this.debrissolid) this.debrissolid = SOLID_NOT;
+ if(this.debrisvelocity == '0 0 0') this.debrisvelocity = '0 0 140';
+ if(this.debrisvelocityjitter == '0 0 0') this.debrisvelocityjitter = '70 70 70';
+ if(this.debrisavelocityjitter == '0 0 0') this.debrisavelocityjitter = '600 600 600';
+ if(!this.debristime) this.debristime = 3.5;
+ if(!this.debristimejitter) this.debristime = 2.5;
+
+ if(this.mdl != "")
+ this.cnt = _particleeffectnum(this.mdl);
+ if(this.count == 0)
+ this.count = 1;
+
+ if(this.message == "")
+ this.message = "got too close to an explosion";
+ if(this.message2 == "")
+ this.message2 = "was pushed into an explosion by";
+ if(!this.dmg_radius)
+ this.dmg_radius = 150;
+ if(!this.dmg_force)
+ this.dmg_force = 200;
+
+ this.mdl = this.model;
+ SetBrushEntityModel(this);
+
+ if(this.spawnflags & BREAKABLE_NODAMAGE)
+ this.use = func_breakable_destroy;
+ else
+ this.use = func_breakable_restore;
+
+ if(this.spawnflags & BREAKABLE_NODAMAGE)
+ {
+ this.takedamage = DAMAGE_NO;
+ this.event_damage = func_null;
+ this.bot_attack = false;
+ }
+
+ // precache all the models
+ if (this.mdl_dead)
+ precache_model(this.mdl_dead);
+ n = tokenize_console(this.debris);
+ for(i = 0; i < n; ++i)
+ precache_model(argv(i));
+ if(this.noise)
+ precache_sound(this.noise);
+ if(this.noise1)
+ precache_sound(this.noise1);
+
+ this.team_saved = this.team;
+ IL_PUSH(g_saved_team, this);
+ this.dropped_origin = this.origin;
+
+ this.reset = func_breakable_reset;
+ this.reset(this);
+
+ IL_PUSH(g_initforplayer, this);
+ this.init_for_player = func_breakable_init_for_player;
+
+ CSQCMODEL_AUTOINIT(this);
+}
+
+// for use in maps with a "model" key set
+spawnfunc(misc_breakablemodel) {
+ spawnfunc_func_breakable(this);
+}
+#endif
--- /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 (this.health)
+ this.takedamage = DAMAGE_YES; // can be shot again
+}
+
+
+void button_blocked(entity this, entity blocker)
+{
+ // do nothing, just don't come all the way back out
+}
+
+
+void button_fire(entity this)
+{
+ this.health = this.max_health;
+ this.takedamage = DAMAGE_NO; // will be reset upon return
+
+ if (this.state == STATE_UP || this.state == STATE_TOP)
+ return;
+
+ if (this.noise != "")
+ _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+
+ this.state = STATE_UP;
+ SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, button_wait);
+}
+
+void button_reset(entity this)
+{
+ this.health = this.max_health;
+ setorigin(this, this.pos1);
+ this.frame = 0; // use normal textures
+ this.state = STATE_BOTTOM;
+ this.velocity = '0 0 0';
+ setthink(this, func_null);
+ this.nextthink = 0;
+ if (this.health)
+ this.takedamage = DAMAGE_YES; // can be shot again
+}
+
+void button_use(entity this, entity actor, entity trigger)
+{
+ if(this.active != ACTIVE_ACTIVE)
+ return;
+
+ this.enemy = actor;
+ button_fire(this);
+}
+
+void button_touch(entity this, entity toucher)
+{
+ if (!toucher)
+ return;
+ if (!toucher.iscreature)
+ return;
+ if(toucher.velocity * this.movedir < 0)
+ return;
+ this.enemy = toucher;
+ if (toucher.owner)
+ this.enemy = toucher.owner;
+ button_fire (this);
+}
+
+void button_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if(this.spawnflags & NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
+ {
+ if (this.health <= damage)
+ {
+ this.enemy = attacker;
+ button_fire(this);
+ }
+ }
+ else
+ {
+ this.health = this.health - damage;
+ if (this.health <= 0)
+ {
+ this.enemy = attacker;
+ button_fire(this);
+ }
+ }
+}
+
+
+/*QUAKED spawnfunc_func_button (0 .5 .8) ?
+When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
+
+"angle" determines the opening direction
+"target" all entities with a matching targetname will be used
+"speed" override the default 40 speed
+"wait" override the default 1 second wait (-1 = never return)
+"lip" override the default 4 pixel lip remaining at end of move
+"health" if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
+"noise" sound that is played when the button is activated
+*/
+spawnfunc(func_button)
+{
+ SetMovedir(this);
+
+ if (!InitMovingBrushTrigger(this))
+ return;
+ this.effects |= EF_LOWPRECISION;
+
+ setblocked(this, button_blocked);
+ this.use = button_use;
+
+// if (this.health == 0) // all buttons are now shootable
+// this.health = 10;
+ if (this.health)
+ {
+ this.max_health = this.health;
+ this.event_damage = button_damage;
+ this.takedamage = DAMAGE_YES;
+ }
+ else
+ settouch(this, button_touch);
+
+ if (!this.speed)
+ this.speed = 40;
+ if (!this.wait)
+ this.wait = 1;
+ if (!this.lip)
+ this.lip = 4;
+
+ if(this.noise != "")
+ precache_sound(this.noise);
+
+ this.active = ACTIVE_ACTIVE;
+
+ this.pos1 = this.origin;
+ this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
+ this.flags |= FL_NOTARGET;
+
+ this.reset = button_reset;
+
+ button_reset(this);
+}
+#endif
--- /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;
+ this.health = this.max_health;
+ }
+
+ this.state = STATE_DOWN;
+ SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_hit_bottom);
+}
+
+void door_go_up(entity this, entity actor, entity trigger)
+{
+ if (this.state == STATE_UP)
+ return; // already going up
+
+ if (this.state == STATE_TOP)
+ { // reset top wait time
+ this.nextthink = this.ltime + this.wait;
+ return;
+ }
+
+ if (this.noise2 != "")
+ _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+ this.state = STATE_UP;
+ SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_hit_top);
+
+ string oldmessage;
+ oldmessage = this.message;
+ this.message = "";
+ SUB_UseTargets(this, actor, trigger);
+ this.message = oldmessage;
+}
+
+
+/*
+=============================================================================
+
+ACTIVATION FUNCTIONS
+
+=============================================================================
+*/
+
+bool door_check_keys(entity door, entity player)
+{
+ if(door.owner)
+ door = door.owner;
+
+ // no key needed
+ if(!door.itemkeys)
+ return true;
+
+ // this door require a key
+ // only a player can have a key
+ if(!IS_PLAYER(player))
+ return false;
+
+ entity store = player;
+#ifdef SVQC
+ store = PS(player);
+#endif
+ int valid = (door.itemkeys & store.itemkeys);
+ door.itemkeys &= ~valid; // only some of the needed keys were given
+
+ if(!door.itemkeys)
+ {
+#ifdef SVQC
+ play2(player, door.noise);
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_UNLOCKED);
+#endif
+ return true;
+ }
+
+ if(!valid)
+ {
+#ifdef SVQC
+ if(player.key_door_messagetime <= time)
+ {
+ play2(player, door.noise3);
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
+ player.key_door_messagetime = time + 2;
+ }
+#endif
+ return false;
+ }
+
+ // door needs keys the player doesn't have
+#ifdef SVQC
+ if(player.key_door_messagetime <= time)
+ {
+ play2(player, door.noise3);
+ Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
+ player.key_door_messagetime = time + 2;
+ }
+#endif
+
+ return false;
+}
+
+void door_fire(entity this, entity actor, entity trigger)
+{
+ if (this.owner != this)
+ objerror (this, "door_fire: this.owner != this");
+
+ if (this.spawnflags & DOOR_TOGGLE)
+ {
+ if (this.state == STATE_UP || this.state == STATE_TOP)
+ {
+ entity e = this;
+ do {
+ if (e.classname == "door") {
+ door_go_down(e);
+ } else {
+ door_rotating_go_down(e);
+ }
+ e = e.enemy;
+ } while ((e != this) && (e != NULL));
+ return;
+ }
+ }
+
+// trigger all paired doors
+ entity e = this;
+ do {
+ if (e.classname == "door") {
+ door_go_up(e, actor, trigger);
+ } else {
+ // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
+ if ((e.spawnflags & DOOR_ROTATING_BIDIR) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
+ e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
+ e.pos2 = '0 0 0' - e.pos2;
+ }
+ // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
+ if (!((e.spawnflags & DOOR_ROTATING_BIDIR) && (e.spawnflags & DOOR_ROTATING_BIDIR_IN_DOWN) && e.state == STATE_DOWN
+ && (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
+ {
+ door_rotating_go_up(e, trigger);
+ }
+ }
+ e = e.enemy;
+ } while ((e != this) && (e != NULL));
+}
+
+void door_use(entity this, entity actor, entity trigger)
+{
+ //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
+
+ if (this.owner)
+ door_fire(this.owner, actor, trigger);
+}
+
+void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if(this.spawnflags & NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ this.health = this.health - damage;
+
+ if (this.itemkeys)
+ {
+ // don't allow opening doors through damage if keys are required
+ return;
+ }
+
+ if (this.health <= 0)
+ {
+ this.owner.health = this.owner.max_health;
+ this.owner.takedamage = DAMAGE_NO; // wil be reset upon return
+ door_use(this.owner, NULL, NULL);
+ }
+}
+
+.float door_finished;
+
+/*
+================
+door_touch
+
+Prints messages
+================
+*/
+
+void door_touch(entity this, entity toucher)
+{
+ if (!IS_PLAYER(toucher))
+ return;
+ if (this.owner.door_finished > time)
+ return;
+
+ this.owner.door_finished = time + 2;
+
+#ifdef SVQC
+ if (!(this.owner.dmg) && (this.owner.message != ""))
+ {
+ if (IS_CLIENT(toucher))
+ centerprint(toucher, this.owner.message);
+ play2(toucher, this.owner.noise);
+ }
+#endif
+}
+
+void door_generic_plat_blocked(entity this, entity blocker)
+{
+ if((this.spawnflags & DOOR_CRUSH) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
+#ifdef SVQC
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+ }
+ else
+ {
+
+#ifdef SVQC
+ if((this.dmg) && (blocker.takedamage == DAMAGE_YES)) // Shall we bite?
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+
+ //Dont chamge direction for dead or dying stuff
+ if(IS_DEAD(blocker) && (blocker.takedamage == DAMAGE_NO))
+ {
+ if (this.wait >= 0)
+ {
+ if (this.state == STATE_DOWN)
+ door_rotating_go_up (this, blocker);
+ else
+ door_rotating_go_down (this);
+ }
+ }
+#ifdef SVQC
+ else
+ {
+ //gib dying stuff just to make sure
+ if((this.dmg) && (blocker.takedamage != DAMAGE_NO)) // Shall we bite?
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+ }
+#endif
+ }
+}
+
+/*
+=========================================
+door trigger
+
+Spawned if a door lacks a real activator
+=========================================
+*/
+
+void door_trigger_touch(entity this, entity toucher)
+{
+ if (toucher.health < 1)
+#ifdef SVQC
+ if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
+#elif defined(CSQC)
+ if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
+#endif
+ return;
+
+ if (time < this.door_finished)
+ return;
+
+ // check if door is locked
+ if (!door_check_keys(this, toucher))
+ return;
+
+ this.door_finished = time + 1;
+
+ door_use(this.owner, toucher, NULL);
+}
+
+void door_spawnfield(entity this, vector fmins, vector fmaxs)
+{
+ entity trigger;
+ vector t1 = fmins, t2 = fmaxs;
+
+ trigger = new(doortriggerfield);
+ set_movetype(trigger, MOVETYPE_NONE);
+ trigger.solid = SOLID_TRIGGER;
+ trigger.owner = this;
+#ifdef SVQC
+ settouch(trigger, door_trigger_touch);
+#endif
+
+ setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
+}
+
+
+/*
+=============
+LinkDoors
+
+
+=============
+*/
+
+entity LinkDoors_nextent(entity cur, entity near, entity pass)
+{
+ while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & DOOR_DONT_LINK) || cur.enemy))
+ {
+ }
+ return cur;
+}
+
+bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
+{
+ float DELTA = 4;
+ if((e1.absmin_x > e2.absmax_x + DELTA)
+ || (e1.absmin_y > e2.absmax_y + DELTA)
+ || (e1.absmin_z > e2.absmax_z + DELTA)
+ || (e2.absmin_x > e1.absmax_x + DELTA)
+ || (e2.absmin_y > e1.absmax_y + DELTA)
+ || (e2.absmin_z > e1.absmax_z + DELTA)
+ ) { return false; }
+ return true;
+}
+
+#ifdef SVQC
+void door_link();
+#endif
+void LinkDoors(entity this)
+{
+ entity t;
+ vector cmins, cmaxs;
+
+#ifdef SVQC
+ door_link();
+#endif
+
+ if (this.enemy)
+ return; // already linked by another door
+ if (this.spawnflags & DOOR_DONT_LINK)
+ {
+ this.owner = this.enemy = this;
+
+ if (this.health)
+ return;
+ IFTARGETED
+ return;
+ if (this.items)
+ return;
+
+ door_spawnfield(this, this.absmin, this.absmax);
+
+ return; // don't want to link this door
+ }
+
+ FindConnectedComponent(this, enemy, LinkDoors_nextent, LinkDoors_isconnected, this);
+
+ // set owner, and make a loop of the chain
+ LOG_TRACE("LinkDoors: linking doors:");
+ for(t = this; ; t = t.enemy)
+ {
+ LOG_TRACE(" ", etos(t));
+ t.owner = this;
+ if(t.enemy == NULL)
+ {
+ t.enemy = this;
+ break;
+ }
+ }
+ LOG_TRACE("");
+
+ // collect health, targetname, message, size
+ cmins = this.absmin;
+ cmaxs = this.absmax;
+ for(t = this; ; t = t.enemy)
+ {
+ if(t.health && !this.health)
+ this.health = t.health;
+ if((t.targetname != "") && (this.targetname == ""))
+ this.targetname = t.targetname;
+ if((t.message != "") && (this.message == ""))
+ this.message = t.message;
+ if (t.absmin_x < cmins_x)
+ cmins_x = t.absmin_x;
+ if (t.absmin_y < cmins_y)
+ cmins_y = t.absmin_y;
+ if (t.absmin_z < cmins_z)
+ cmins_z = t.absmin_z;
+ if (t.absmax_x > cmaxs_x)
+ cmaxs_x = t.absmax_x;
+ if (t.absmax_y > cmaxs_y)
+ cmaxs_y = t.absmax_y;
+ if (t.absmax_z > cmaxs_z)
+ cmaxs_z = t.absmax_z;
+ if(t.enemy == this)
+ break;
+ }
+
+ // distribute health, targetname, message
+ for(t = this; t; t = t.enemy)
+ {
+ t.health = this.health;
+ t.targetname = this.targetname;
+ t.message = this.message;
+ if(t.enemy == this)
+ break;
+ }
+
+ // shootable, or triggered doors just needed the owner/enemy links,
+ // they don't spawn a field
+
+ if (this.health)
+ return;
+ IFTARGETED
+ return;
+ if (this.items)
+ return;
+
+ door_spawnfield(this, cmins, cmaxs);
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
+
+#ifdef SVQC
+/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
+if two doors touch, they are assumed to be connected and operate as a unit.
+
+TOGGLE causes the door to wait in both the start and end states for a trigger event.
+
+START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
+
+GOLD_KEY causes the door to open only if the activator holds a gold key.
+
+SILVER_KEY causes the door to open only if the activator holds a silver key.
+
+"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
+"angle" determines the opening direction
+"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
+"health" if set, door must be shot open
+"speed" movement speed (100 default)
+"wait" wait before returning (3 default, -1 = never return)
+"lip" lip remaining at end of move (8 default)
+"dmg" damage to inflict when blocked (2 default)
+"sounds"
+0) no sound
+1) stone
+2) base
+3) stone chain
+4) screechy metal
+FIXME: only one sound set available at the time being
+
+*/
+
+float door_send(entity this, entity to, float sf)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
+ WriteByte(MSG_ENTITY, sf);
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ WriteString(MSG_ENTITY, this.classname);
+ WriteByte(MSG_ENTITY, this.spawnflags);
+
+ WriteString(MSG_ENTITY, this.model);
+
+ trigger_common_write(this, true);
+
+ WriteVector(MSG_ENTITY, this.pos1);
+ WriteVector(MSG_ENTITY, this.pos2);
+
+ WriteVector(MSG_ENTITY, this.size);
+
+ WriteShort(MSG_ENTITY, this.wait);
+ WriteShort(MSG_ENTITY, this.speed);
+ WriteByte(MSG_ENTITY, this.lip);
+ WriteByte(MSG_ENTITY, this.state);
+ WriteCoord(MSG_ENTITY, this.ltime);
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ // client makes use of this, we do not
+ }
+
+ if(sf & SF_TRIGGER_UPDATE)
+ {
+ WriteVector(MSG_ENTITY, this.origin);
+
+ WriteVector(MSG_ENTITY, this.pos1);
+ WriteVector(MSG_ENTITY, this.pos2);
+ }
+
+ return true;
+}
+
+void door_link()
+{
+ // set size now, as everything is loaded
+ //FixSize(this);
+ //Net_LinkEntity(this, false, 0, door_send);
+}
+#endif
+
+void door_init_startopen(entity this)
+{
+ setorigin(this, this.pos2);
+ this.pos2 = this.pos1;
+ this.pos1 = this.origin;
+
+#ifdef SVQC
+ this.SendFlags |= SF_TRIGGER_UPDATE;
+#endif
+}
+
+void door_reset(entity this)
+{
+ setorigin(this, this.pos1);
+ this.velocity = '0 0 0';
+ this.state = STATE_BOTTOM;
+ setthink(this, func_null);
+ this.nextthink = 0;
+
+#ifdef SVQC
+ this.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+#ifdef SVQC
+
+// common code for func_door and func_door_rotating spawnfuncs
+void door_init_shared(entity this)
+{
+ this.max_health = this.health;
+
+ // unlock sound
+ if(this.noise == "")
+ {
+ this.noise = "misc/talk.wav";
+ }
+ // door still locked sound
+ if(this.noise3 == "")
+ {
+ this.noise3 = "misc/talk.wav";
+ }
+ precache_sound(this.noise);
+ precache_sound(this.noise3);
+
+ if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message == ""))
+ {
+ this.message = "was squished";
+ }
+ if((this.dmg || (this.spawnflags & DOOR_CRUSH)) && (this.message2 == ""))
+ {
+ this.message2 = "was squished by";
+ }
+
+ // TODO: other soundpacks
+ if (this.sounds > 0)
+ {
+ this.noise2 = "plats/medplat1.wav";
+ this.noise1 = "plats/medplat2.wav";
+ }
+
+ // sound when door stops moving
+ if(this.noise1 && this.noise1 != "")
+ {
+ precache_sound(this.noise1);
+ }
+ // sound when door is moving
+ if(this.noise2 && this.noise2 != "")
+ {
+ precache_sound(this.noise2);
+ }
+
+ if (!this.wait)
+ {
+ this.wait = 3;
+ }
+ if (!this.lip)
+ {
+ this.lip = 8;
+ }
+
+ this.state = STATE_BOTTOM;
+
+ if (this.health)
+ {
+ //this.canteamdamage = true; // TODO
+ this.takedamage = DAMAGE_YES;
+ this.event_damage = door_damage;
+ }
+
+ if (this.items)
+ {
+ this.wait = -1;
+ }
+}
+
+// spawnflags require key (for now only func_door)
+spawnfunc(func_door)
+{
+ // Quake 1 keys compatibility
+ if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
+ this.itemkeys |= ITEM_KEY_BIT(0);
+ if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
+ this.itemkeys |= ITEM_KEY_BIT(1);
+
+ SetMovedir(this);
+
+ if (!InitMovingBrushTrigger(this))
+ return;
+ this.effects |= EF_LOWPRECISION;
+ this.classname = "door";
+
+ setblocked(this, door_blocked);
+ this.use = door_use;
+
+ this.pos1 = this.origin;
+ this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
+
+ if(this.spawnflags & DOOR_NONSOLID)
+ this.solid = SOLID_NOT;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+ if (this.spawnflags & DOOR_START_OPEN)
+ InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
+
+ door_init_shared(this);
+
+ if (!this.speed)
+ {
+ this.speed = 100;
+ }
+
+ settouch(this, door_touch);
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+ InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
+
+ this.reset = door_reset;
+}
+
+#elif defined(CSQC)
+
+NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
+{
+ int sf = ReadByte();
+
+ if(sf & SF_TRIGGER_INIT)
+ {
+ this.classname = strzone(ReadString());
+ this.spawnflags = ReadByte();
+
+ this.mdl = strzone(ReadString());
+ _setmodel(this, this.mdl);
+
+ trigger_common_read(this, true);
+
+ this.pos1 = ReadVector();
+ this.pos2 = ReadVector();
+
+ this.size = ReadVector();
+
+ this.wait = ReadShort();
+ this.speed = ReadShort();
+ this.lip = ReadByte();
+ this.state = ReadByte();
+ this.ltime = ReadCoord();
+
+ this.solid = SOLID_BSP;
+ set_movetype(this, MOVETYPE_PUSH);
+ this.use = door_use;
+
+ LinkDoors(this);
+
+ if(this.spawnflags & DOOR_START_OPEN)
+ door_init_startopen(this);
+
+ this.move_time = time;
+ set_movetype(this, MOVETYPE_PUSH);
+ }
+
+ if(sf & SF_TRIGGER_RESET)
+ {
+ door_reset(this);
+ }
+
+ if(sf & SF_TRIGGER_UPDATE)
+ {
+ this.origin = ReadVector();
+ setorigin(this, this.origin);
+
+ this.pos1 = ReadVector();
+ this.pos2 = ReadVector();
+ }
+ return true;
+}
+
+#endif
--- /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;
+ this.health = this.max_health;
+ }
+
+ this.state = STATE_DOWN;
+ SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
+}
+
+void door_rotating_go_up(entity this, entity oth)
+{
+ if (this.state == STATE_UP)
+ return; // already going up
+
+ if (this.state == STATE_TOP)
+ { // reset top wait time
+ this.nextthink = this.ltime + this.wait;
+ return;
+ }
+ if (this.noise2 != "")
+ _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+ this.state = STATE_UP;
+ SUB_CalcAngleMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_rotating_hit_top);
+
+ string oldmessage;
+ oldmessage = this.message;
+ this.message = "";
+ SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
+ this.message = oldmessage;
+}
+#endif
+
+#ifdef SVQC
+void door_rotating_reset(entity this)
+{
+ this.angles = this.pos1;
+ this.avelocity = '0 0 0';
+ this.state = STATE_BOTTOM;
+ setthink(this, func_null);
+ this.nextthink = 0;
+}
+
+void door_rotating_init_startopen(entity this)
+{
+ this.angles = this.movedir;
+ this.pos2 = '0 0 0';
+ this.pos1 = this.movedir;
+}
+
+spawnfunc(func_door_rotating)
+{
+ //if (!this.deathtype) // map makers can override this
+ // this.deathtype = " got in the way";
+
+ // I abuse "movedir" for denoting the axis for now
+ if (this.spawnflags & DOOR_ROTATING_XAXIS)
+ this.movedir = '0 0 1';
+ else if (this.spawnflags & DOOR_ROTATING_YAXIS)
+ this.movedir = '1 0 0';
+ else // Z
+ this.movedir = '0 1 0';
+
+ if (this.angles_y==0) this.angles_y = 90;
+
+ this.movedir = this.movedir * this.angles_y;
+ this.angles = '0 0 0';
+
+ this.avelocity = this.movedir;
+ if (!InitMovingBrushTrigger(this))
+ return;
+ this.velocity = '0 0 0';
+ //this.effects |= EF_LOWPRECISION;
+ this.classname = "door_rotating";
+
+ setblocked(this, door_blocked);
+ this.use = door_use;
+
+ this.pos1 = '0 0 0';
+ this.pos2 = this.movedir;
+
+// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
+// but spawn in the open position
+ if (this.spawnflags & DOOR_START_OPEN)
+ InitializeEntity(this, door_rotating_init_startopen, INITPRIO_SETLOCATION);
+
+ door_init_shared(this);
+ if (!this.speed)
+ {
+ this.speed = 50;
+ }
+ this.lip = 0; // this.lip is used to remember reverse opening direction for door_rotating
+
+ settouch(this, door_touch);
+
+// LinkDoors can't be done until all of the doors have been spawned, so
+// the sizes can be detected properly.
+ InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
+
+ this.reset = door_rotating_reset;
+}
+#endif
--- /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;
+
+ this.health = 10000;
+ if(!this.bot_attack)
+ IL_PUSH(g_bot_targets, this);
+ this.bot_attack = true;
+
+ // exit if still moving around...
+ if (this.origin != this.oldorigin)
+ return;
+
+ message_save = this.message;
+ this.message = ""; // no more message
+ SUB_UseTargets(this, actor, trigger); // fire all targets / killtargets
+ this.message = message_save;
+
+ this.velocity = '0 0 0';
+
+ // Make a sound, wait a little...
+
+ if (this.noise1 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
+ this.nextthink = this.ltime + 0.1;
+
+ temp = 1 - (this.spawnflags & DOOR_SECRET_1ST_LEFT); // 1 or -1
+ makevectors(this.mangle);
+
+ if (!this.t_width)
+ {
+ if (this.spawnflags & DOOR_SECRET_1ST_DOWN)
+ this.t_width = fabs(v_up * this.size);
+ else
+ this.t_width = fabs(v_right * this.size);
+ }
+
+ if (!this.t_length)
+ this.t_length = fabs(v_forward * this.size);
+
+ if (this.spawnflags & DOOR_SECRET_1ST_DOWN)
+ this.dest1 = this.origin - v_up * this.t_width;
+ else
+ this.dest1 = this.origin + v_right * (this.t_width * temp);
+
+ this.dest2 = this.dest1 + v_forward * this.t_length;
+ SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move1);
+ if (this.noise2 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ fd_secret_use(this, NULL, NULL);
+}
+
+// Wait after first movement...
+void fd_secret_move1(entity this)
+{
+ this.nextthink = this.ltime + 1.0;
+ setthink(this, fd_secret_move2);
+ if (this.noise3 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+// Start moving sideways w/sound...
+void fd_secret_move2(entity this)
+{
+ if (this.noise2 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(this, this.dest2, TSPEED_LINEAR, this.speed, fd_secret_move3);
+}
+
+// Wait here until time to go back...
+void fd_secret_move3(entity this)
+{
+ if (this.noise3 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+ if (!(this.spawnflags & DOOR_SECRET_OPEN_ONCE) && this.wait >= 0)
+ {
+ this.nextthink = this.ltime + this.wait;
+ setthink(this, fd_secret_move4);
+ }
+}
+
+// Move backward...
+void fd_secret_move4(entity this)
+{
+ if (this.noise2 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move5);
+}
+
+// Wait 1 second...
+void fd_secret_move5(entity this)
+{
+ this.nextthink = this.ltime + 1.0;
+ setthink(this, fd_secret_move6);
+ if (this.noise3 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+void fd_secret_move6(entity this)
+{
+ if (this.noise2 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
+ SUB_CalcMove(this, this.oldorigin, TSPEED_LINEAR, this.speed, fd_secret_done);
+}
+
+void fd_secret_done(entity this)
+{
+ if (this.spawnflags&DOOR_SECRET_YES_SHOOT)
+ {
+ this.health = 10000;
+ this.takedamage = DAMAGE_YES;
+ //this.th_pain = fd_secret_use;
+ }
+ if (this.noise3 != "")
+ _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
+}
+
+.float door_finished;
+
+void secret_blocked(entity this, entity blocker)
+{
+ if (time < this.door_finished)
+ return;
+ this.door_finished = time + 0.5;
+ //T_Damage (other, this, this, this.dmg, this.dmg, this.deathtype, DT_IMPACT, (this.absmin + this.absmax) * 0.5, '0 0 0', Obituary_Generic);
+}
+
+/*
+==============
+secret_touch
+
+Prints messages
+================
+*/
+void secret_touch(entity this, entity toucher)
+{
+ if (!toucher.iscreature)
+ return;
+ if (this.door_finished > time)
+ return;
+
+ this.door_finished = time + 2;
+
+ if (this.message)
+ {
+ if (IS_CLIENT(toucher))
+ centerprint(toucher, this.message);
+ play2(toucher, this.noise);
+ }
+}
+
+void secret_reset(entity this)
+{
+ if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
+ {
+ this.health = 10000;
+ this.takedamage = DAMAGE_YES;
+ }
+ setorigin(this, this.oldorigin);
+ setthink(this, func_null);
+ this.nextthink = 0;
+}
+
+/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
+Basic secret door. Slides back, then to the side. Angle determines direction.
+wait = # of seconds before coming back
+1st_left = 1st move is left of arrow
+1st_down = 1st move is down from arrow
+always_shoot = even if targeted, keep shootable
+t_width = override WIDTH to move back (or height if going down)
+t_length = override LENGTH to move sideways
+"dmg" damage to inflict when blocked (2 default)
+
+If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
+"sounds"
+1) medieval
+2) metal
+3) base
+*/
+
+spawnfunc(func_door_secret)
+{
+ /*if (!this.deathtype) // map makers can override this
+ this.deathtype = " got in the way";*/
+
+ if (!this.dmg)
+ {
+ this.dmg = 2;
+ }
+
+ // Magic formula...
+ this.mangle = this.angles;
+ this.angles = '0 0 0';
+ this.classname = "door";
+ if (!InitMovingBrushTrigger(this)) return;
+ this.effects |= EF_LOWPRECISION;
+
+ // TODO: other soundpacks
+ if (this.sounds > 0)
+ {
+ this.noise1 = "plats/medplat1.wav";
+ this.noise2 = "plats/medplat1.wav";
+ this.noise3 = "plats/medplat2.wav";
+ }
+
+ // sound on touch
+ if (this.noise == "")
+ {
+ this.noise = "misc/talk.wav";
+ }
+ precache_sound(this.noise);
+ // sound while moving backwards
+ if (this.noise1 && this.noise1 != "")
+ {
+ precache_sound(this.noise1);
+ }
+ // sound while moving sideways
+ if (this.noise2 && this.noise2 != "")
+ {
+ precache_sound(this.noise2);
+ }
+ // sound when door stops moving
+ if (this.noise3 && this.noise3 != "")
+ {
+ precache_sound(this.noise3);
+ }
+
+ settouch(this, secret_touch);
+ setblocked(this, secret_blocked);
+ this.speed = 50;
+ this.use = fd_secret_use;
+ IFTARGETED
+ {
+ }
+ else
+ this.spawnflags |= DOOR_SECRET_YES_SHOOT;
+
+ if (this.spawnflags & DOOR_SECRET_YES_SHOOT)
+ {
+ //this.canteamdamage = true; // TODO
+ this.health = 10000;
+ this.takedamage = DAMAGE_YES;
+ this.event_damage = fd_secret_damage;
+ }
+ this.oldorigin = this.origin;
+ if (!this.wait) this.wait = 5; // seconds before closing
+
+ this.reset = secret_reset;
+ this.reset(this);
+}
+#endif
--- /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 (toucher.health <= 0)
+ return;
+#elif defined(CSQC)
+ if (!IS_PLAYER(toucher))
+ return;
+ if(IS_DEAD(toucher))
+ return;
+#endif
+
+ if (this.enemy.state == STATE_BOTTOM) {
+ plat_go_up(this.enemy);
+ } else if (this.enemy.state == STATE_TOP)
+ this.enemy.nextthink = this.enemy.ltime + 1;
+}
+
+void plat_outside_touch(entity this, entity toucher)
+{
+#ifdef SVQC
+ if (!toucher.iscreature)
+ return;
+
+ if (toucher.health <= 0)
+ return;
+#elif defined(CSQC)
+ if (!IS_PLAYER(toucher))
+ return;
+#endif
+
+ if (this.enemy.state == STATE_TOP) {
+ entity e = this.enemy;
+ plat_go_down(e);
+ }
+}
+
+void plat_trigger_use(entity this, entity actor, entity trigger)
+{
+ if (getthink(this))
+ return; // already activated
+ plat_go_down(this);
+}
+
+
+void plat_crush(entity this, entity blocker)
+{
+ if((this.spawnflags & CRUSH) && (blocker.takedamage != DAMAGE_NO))
+ { // KIll Kill Kill!!
+#ifdef SVQC
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+#endif
+ }
+ else
+ {
+#ifdef SVQC
+ if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
+ { // Shall we bite?
+ Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+ // Gib dead/dying stuff
+ if(IS_DEAD(blocker))
+ Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
+ }
+#endif
+
+ if (this.state == STATE_UP)
+ plat_go_down (this);
+ else if (this.state == STATE_DOWN)
+ plat_go_up (this);
+ // when in other states, then the plat_crush event came delayed after
+ // plat state already had changed
+ // this isn't a bug per se!
+ }
+}
+
+void plat_use(entity this, entity actor, entity trigger)
+{
+ this.use = func_null;
+ if (this.state != STATE_UP)
+ objerror (this, "plat_use: not in up state");
+ plat_go_down(this);
+}
+
+// WARNING: backwards compatibility because people don't use already existing fields :(
+// TODO: Check if any maps use these fields and remove these fields if it doesn't break maps
+.string sound1, sound2;
+
+void plat_reset(entity this)
+{
+ IFTARGETED
+ {
+ setorigin(this, this.pos1);
+ this.state = STATE_UP;
+ this.use = plat_use;
+ }
+ else
+ {
+ setorigin(this, this.pos2);
+ this.state = STATE_BOTTOM;
+ this.use = plat_trigger_use;
+ }
+
+#ifdef SVQC
+ this.SendFlags |= SF_TRIGGER_RESET;
+#endif
+}
+
+.float platmovetype_start_default, platmovetype_end_default;
+bool set_platmovetype(entity e, string s)
+{
+ // sets platmovetype_start and platmovetype_end based on a string consisting of two values
+
+ int n = tokenize_console(s);
+ if(n > 0)
+ e.platmovetype_start = stof(argv(0));
+ else
+ e.platmovetype_start = 0;
+
+ if(n > 1)
+ e.platmovetype_end = stof(argv(1));
+ else
+ e.platmovetype_end = e.platmovetype_start;
+
+ if(n > 2)
+ if(argv(2) == "force")
+ return true; // no checking, return immediately
+
+ if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
+ {
+ objerror(e, "Invalid platform move type; platform would go in reverse, which is not allowed.");
+ return false;
+ }
+
+ return true;
+}
--- /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;
+ SetBrushEntityModel(this);
+ set_movetype(this, MOVETYPE_NONE);
+ this.modelindex = 0;
+ this.model = "";
+}
+
+void InitSolidBSPTrigger(entity this)
+{
+// trigger angles are used for one-way touches. An angle of 0 is assumed
+// to mean no restrictions, so use a yaw of 360 instead.
+ SetMovedir(this);
+ this.solid = SOLID_BSP;
+ SetBrushEntityModel(this);
+ set_movetype(this, MOVETYPE_NONE); // why was this PUSH? -div0
+// this.modelindex = 0;
+ this.model = "";
+}
+
+bool InitMovingBrushTrigger(entity this)
+{
+// trigger angles are used for one-way touches. An angle of 0 is assumed
+// to mean no restrictions, so use a yaw of 360 instead.
+ this.solid = SOLID_BSP;
+ SetBrushEntityModel(this);
+ set_movetype(this, MOVETYPE_PUSH);
+ if(this.modelindex == 0)
+ {
+ objerror(this, "InitMovingBrushTrigger: no brushes found!");
+ return false;
+ }
+ return true;
+}
+#endif
--- /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) && player.health >= 1)
+ {
+ if (!(teamplay && autocvar_g_telefrags_teamplay && head.team == player.team))
+ {
+ if(IS_PLAYER(head))
+ if(head.health >= 1)
+ ++tdeath_hit;
+ Damage (head, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, head.origin, '0 0 0');
+ }
+ }
+ else // dead bodies and monsters gib themselves instead of telefragging
+ Damage (telefragger, teleporter, telefragger, 10000, DEATH_TELEFRAG.m_id, DMG_NOWEP, telefragger.origin, '0 0 0');
+ }
+}
+
+void spawn_tdeath(vector v0, entity e, vector v)
+{
+ tdeath(e, e, e, '0 0 0', '0 0 0');
+}
+#endif
+
+void TeleportPlayer(entity teleporter, entity player, vector to, vector to_angles, vector to_velocity, vector telefragmin, vector telefragmax, float tflags)
+{
+ entity telefragger;
+ vector from;
+
+ if(teleporter.owner)
+ telefragger = teleporter.owner;
+ else
+ telefragger = player;
+
+ makevectors (to_angles);
+
+#ifdef SVQC
+ if(player.teleportable == TELEPORT_NORMAL) // don't play sounds or show particles for anything that isn't a player, maybe change later to block only observers
+ {
+ if(teleporter.pushltime < time) // only show one teleport effect per teleporter per 0.2 seconds, for better fps
+ {
+ if(tflags & TELEPORT_FLAG_SOUND)
+ {
+ string thesound = SND(TELEPORT);
+ if(teleporter.noise != "")
+ {
+ RandomSelection_Init();
+ FOREACH_WORD(teleporter.noise, true,
+ {
+ RandomSelection_AddString(it, 1, 1);
+ });
+ thesound = RandomSelection_chosen_string;
+ }
+ _sound (player, CH_TRIGGER, thesound, VOL_BASE, ATTEN_NORM);
+ }
+ if(tflags & TELEPORT_FLAG_PARTICLES)
+ {
+ Send_Effect(EFFECT_TELEPORT, player.origin, '0 0 0', 1);
+ Send_Effect(EFFECT_TELEPORT, to + v_forward * 32, '0 0 0', 1);
+ }
+ teleporter.pushltime = time + 0.2;
+ }
+ }
+#endif
+
+ // Relocate the player
+ // assuming to allows PL_MIN to PL_MAX box and some more
+#ifdef SVQC
+ from = player.origin;
+ setorigin(player, to);
+ player.oldorigin = to; // don't undo the teleport by unsticking
+ player.angles = to_angles;
+ player.fixangle = true;
+ player.velocity = to_velocity;
+ BITXOR_ASSIGN(player.effects, EF_TELEPORT_BIT);
+
+ makevectors(player.angles);
+ Reset_ArcBeam(player, v_forward);
+ UpdateCSQCProjectileAfterTeleport(player);
+ UpdateItemAfterTeleport(player);
+#elif defined(CSQC)
+ from = player.origin;
+ setorigin(player, to);
+ player.angles = to_angles;
+ player.velocity = to_velocity;
+ UNSET_ONGROUND(player);
+ player.iflags |= IFLAG_TELEPORTED | IFLAG_V_ANGLE | IFLAG_ANGLES;
+ player.csqcmodel_teleported = 1;
+ player.v_angle = to_angles;
+
+ if(player == csqcplayer) // not for anything but the main player
+ {
+ setproperty(VF_ANGLES, player.angles);
+ setproperty(VF_CL_VIEWANGLES, player.angles);
+ }
+#endif
+
+#ifdef SVQC
+ if(IS_PLAYER(player))
+ {
+ if(tflags & TELEPORT_FLAG_TDEATH)
+ if(player.takedamage && !IS_DEAD(player) && !g_race && !g_cts && (autocvar_g_telefrags || (tflags & TELEPORT_FLAG_FORCE_TDEATH)))
+ tdeath(player, teleporter, telefragger, telefragmin, telefragmax);
+
+ // player no longer is on ground
+ UNSET_ONGROUND(player);
+
+ // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+ player.oldvelocity = player.velocity;
+
+ // reset tracking of who pushed you into a hazard (for kill credit)
+ if(teleporter.owner)
+ {
+ player.pusher = teleporter.owner;
+ player.pushltime = time + autocvar_g_maxpushtime;
+ player.istypefrag = PHYS_INPUT_BUTTON_CHAT(player);
+ }
+ else
+ {
+ player.pushltime = 0;
+ player.istypefrag = 0;
+ }
+
+ player.lastteleporttime = time;
+ player.lastteleport_origin = from;
+ }
+#endif
+}
+
+entity Simple_TeleportPlayer(entity teleporter, entity player)
+{
+ vector locout;
+ entity e = NULL;
+
+ // Find the output teleporter
+ if(teleporter.enemy)
+ {
+ e = teleporter.enemy;
+ }
+ else
+ {
+ // sorry CSQC, random stuff ain't gonna happen
+#ifdef SVQC
+ RandomSelection_Init();
+ FOREACH_ENTITY_STRING(targetname, teleporter.target,
+ {
+ bool p = true;
+ if(STAT(TELEPORT_TELEFRAG_AVOID, player))
+ {
+ #ifdef SVQC
+ locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
+ #elif defined(CSQC)
+ locout = it.origin + '0 0 1' * (1 - player.mins.z - 24);
+ #endif
+ if(check_tdeath(player, locout, '0 0 0', '0 0 0'))
+ p = false;
+ }
+ RandomSelection_AddEnt(it, (it.cnt ? it.cnt : 1), p);
+ });
+ e = RandomSelection_chosen_ent;
+#endif
+ }
+
+#ifdef SVQC
+ if(!e) { sprint(player, "Teleport destination vanished. Sorry... please complain to the mapper.\n"); }
+#elif defined(CSQC)
+ if(!e) { LOG_INFO("Teleport destination could not be found from CSQC."); }
+#endif
+
+ makevectors(e.mangle);
+
+ if(e.speed)
+ if(vdist(player.velocity, >, e.speed))
+ player.velocity = normalize(player.velocity) * max(0, e.speed);
+
+ if(STAT(TELEPORT_MAXSPEED, player))
+ if(vdist(player.velocity, >, STAT(TELEPORT_MAXSPEED, player)))
+ player.velocity = normalize(player.velocity) * max(0, STAT(TELEPORT_MAXSPEED, player));
+
+ locout = e.origin + '0 0 1' * (1 - player.mins.z - 24);
+
+ TeleportPlayer(teleporter, player, locout, e.mangle, v_forward * vlen(player.velocity), '0 0 0', '0 0 0', TELEPORT_FLAGS_TELEPORTER);
+
+ return e;
+}
+
+void teleport_findtarget(entity this)
+{
+ bool istrigger = (this.solid == SOLID_TRIGGER);
+
+ int n = 0;
+ for(entity e = NULL; (e = find(e, targetname, this.target)); )
+ {
+ ++n;
+#ifdef SVQC
+ if(e.move_movetype == MOVETYPE_NONE)
+ {
+ entity tracetest_ent = spawn();
+ setsize(tracetest_ent, PL_MIN_CONST, PL_MAX_CONST);
+ tracetest_ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ waypoint_spawnforteleporter(this, e.origin, 0, tracetest_ent);
+ delete(tracetest_ent);
+ }
+ if(e.classname != "info_teleport_destination")
+ LOG_INFO("^3MAPPER ERROR: teleporter does target an invalid teleport destination entity. Angles will not work.");
+#endif
+ }
+
+ if(n == 0)
+ {
+ // no dest!
+ objerror (this, "Teleporter with nonexistant target");
+ return;
+ }
+ else if(n == 1)
+ {
+ // exactly one dest - bots love that
+ this.enemy = find(NULL, targetname, this.target);
+ }
+ else
+ {
+ // have to use random selection every single time
+ this.enemy = NULL;
+ }
+
+ // now enable touch
+ if(istrigger)
+ settouch(this, Teleport_Touch);
+#ifdef SVQC
+ if(istrigger)
+ trigger_teleport_link(this);
+#endif
+}
+
+entity Teleport_Find(vector mi, vector ma)
+{
+ IL_EACH(g_teleporters, WarpZoneLib_BoxTouchesBrush(mi, ma, it, NULL),
+ {
+ return it;
+ });
+ return NULL;
+}
+
+void WarpZone_PostTeleportPlayer_Callback(entity pl)
+{
+#ifdef SVQC
+ makevectors(pl.angles);
+ Reset_ArcBeam(pl, v_forward);
+ UpdateCSQCProjectileAfterTeleport(pl);
+ UpdateItemAfterTeleport(pl);
+ if (IS_PLAYER(pl)) anticheat_fixangle(pl);
+#endif
+ // "disown" projectiles after teleport
+ if(pl.owner)
+ if(pl.owner == pl.realowner)
+ {
+ #ifdef SVQC
+ if(!(pl.flags & FL_PROJECTILE))
+ #elif defined(CSQC)
+ if(!(pl.flags & BIT(15))) // FL_PROJECTILE
+ #endif
+ LOG_INFO("A non-projectile got through a warpzone and its owner cleared. It's a ", pl.classname, ".");
+ pl.owner = NULL;
+ }
+ if(IS_PLAYER(pl))
+ {
+ // reset tracking of oldvelocity for impact damage (sudden velocity changes)
+ #ifdef SVQC
+ pl.oldvelocity = pl.velocity;
+ #endif
+ }
+}
--- /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);
+ 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
+
+
+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)
+ {
+ this.health = this.max_health;
+ this.takedamage = DAMAGE_YES;
+ this.solid = SOLID_BBOX;
+ }
+}
+
+
+// the trigger was just touched/killed/used
+// this.enemy should be set to the activator so it can be held through a delay
+// so wait for the delay time before firing
+void multi_trigger(entity this)
+{
+ if (this.nextthink > time)
+ {
+ return; // allready been triggered
+ }
+
+ if(this.spawnflags & ONLY_PLAYERS && !IS_PLAYER(this.enemy))
+ {
+ return; // only players
+ }
+
+ // TODO: restructure this so that trigger_secret is more independent
+ if (this.classname == "trigger_secret")
+ {
+ if (!IS_PLAYER(this.enemy))
+ return;
+ found_secrets = found_secrets + 1;
+ WriteByte (MSG_ALL, SVC_FOUNDSECRET);
+ }
+
+ if (this.noise)
+ {
+ _sound (this.enemy, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ }
+
+ // don't trigger again until reset
+ this.takedamage = DAMAGE_NO;
+
+ SUB_UseTargets(this, this.enemy, this.goalentity);
+
+ if (this.wait > 0)
+ {
+ setthink(this, multi_wait);
+ this.nextthink = time + this.wait;
+ }
+ else if (this.wait == 0)
+ {
+ multi_wait(this); // waiting finished
+ }
+ else
+ { // we can't just delete(this) here, because this is a touch function
+ // called while C code is looping through area links...
+ settouch(this, func_null);
+ }
+}
+
+void multi_use(entity this, entity actor, entity trigger)
+{
+ this.goalentity = trigger;
+ this.enemy = actor;
+ multi_trigger(this);
+}
+
+void multi_touch(entity this, entity toucher)
+{
+ if(!(this.spawnflags & ALL_ENTITIES) && !toucher.iscreature)
+ {
+ return;
+ }
+
+ if(this.team)
+ {
+ if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != toucher.team))
+ {
+ return;
+ }
+ }
+
+ // if the trigger has an angles field, check player's facing direction
+ if (this.movedir != '0 0 0')
+ {
+ makevectors (toucher.angles);
+ if (v_forward * this.movedir < 0)
+ return; // not facing the right way
+ }
+
+ // if the trigger has pressed keys, check that the player is pressing those keys
+ if(this.pressedkeys && IS_PLAYER(toucher)) // only for players
+ {
+ if(!(CS(toucher).pressedkeys & this.pressedkeys))
+ {
+ return;
+ }
+ }
+
+ EXACTTRIGGER_TOUCH(this, toucher);
+
+ this.enemy = toucher;
+ this.goalentity = toucher;
+ multi_trigger(this);
+}
+
+void multi_eventdamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if(!this.takedamage)
+ return;
+ if(this.spawnflags & NOSPLASH)
+ if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
+ return;
+ if(this.team)
+ if(((this.spawnflags & INVERT_TEAMS) == 0) == (this.team != attacker.team))
+ return;
+ this.health = this.health - damage;
+ if (this.health <= 0)
+ {
+ this.enemy = attacker;
+ this.goalentity = inflictor;
+ multi_trigger(this);
+ }
+}
+
+void multi_reset(entity this)
+{
+ if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
+ settouch(this, multi_touch);
+ if (this.max_health)
+ {
+ this.health = this.max_health;
+ this.takedamage = DAMAGE_YES;
+ this.solid = SOLID_BBOX;
+ }
+ setthink(this, func_null);
+ this.nextthink = 0;
+ this.team = this.team_saved;
+}
+
+/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
+Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
+If "delay" is set, the trigger waits some time after activating before firing.
+"wait" : Seconds between triggerings. (.2 default)
+If notouch is set, the trigger is only fired by other entities, not by touching.
+NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
+sounds
+1) secret
+2) beep beep
+3) large switch
+4)
+set "message" to text string
+*/
+spawnfunc(trigger_multiple)
+{
+ this.reset = multi_reset;
+ if (this.sounds == 1)
+ this.noise = "misc/secret.wav";
+ else if (this.sounds == 2)
+ this.noise = strzone(SND(TALK));
+ else if (this.sounds == 3)
+ this.noise = "misc/trigger1.wav";
+
+ if(this.noise)
+ precache_sound(this.noise);
+
+ if (!this.wait)
+ this.wait = 0.2;
+ else if(this.wait < -1)
+ this.wait = 0;
+ this.use = multi_use;
+
+ EXACTTRIGGER_INIT;
+
+ this.team_saved = this.team;
+ IL_PUSH(g_saved_team, this);
+
+ if (this.health)
+ {
+ if (this.spawnflags & SPAWNFLAG_NOTOUCH)
+ objerror (this, "health and notouch don't make sense\n");
+ this.canteamdamage = true;
+ this.max_health = this.health;
+ this.event_damage = multi_eventdamage;
+ this.takedamage = DAMAGE_YES;
+ this.solid = SOLID_BBOX;
+ setorigin(this, this.origin); // make sure it links into the world
+ }
+ else
+ {
+ if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
+ {
+ settouch(this, multi_touch);
+ setorigin(this, this.origin); // make sure it links into the world
+ }
+ }
+}
+
+
+/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
+Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
+"targetname". If "health" is set, the trigger must be killed to activate.
+If notouch is set, the trigger is only fired by other entities, not by touching.
+if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
+if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
+sounds
+1) secret
+2) beep beep
+3) large switch
+4)
+set "message" to text string
+*/
+spawnfunc(trigger_once)
+{
+ this.wait = -1;
+ spawnfunc_trigger_multiple(this);
+}
+#endif
--- /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?
+ 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;
+
+
+/**
+ * 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, DMG_NOWEP, this.owner.origin, '0 0 0');
+#endif
+
+ this.nextthink = time + this.swamp_interval;
+}
+
+void swamp_touch(entity this, entity toucher)
+{
+ // If whatever thats touching the swamp is not a player
+ // or if its a dead player, just dont care abt it.
+ if(!IS_PLAYER(toucher) || IS_DEAD(toucher))
+ return;
+
+ EXACTTRIGGER_TOUCH(this, toucher);
+
+ // Chech if player alredy got a swampslug.
+ if(toucher.in_swamp != 1)
+ {
+ // If not attach one.
+ //centerprint(toucher,"Entering swamp!\n");
+ toucher.swampslug = spawn();
+ toucher.swampslug.health = 2;
+ setthink(toucher.swampslug, swampslug_think);
+ toucher.swampslug.nextthink = time;
+ toucher.swampslug.owner = toucher;
+ toucher.swampslug.dmg = this.dmg;
+ toucher.swampslug.swamp_interval = this.swamp_interval;
+ toucher.swamp_slowdown = this.swamp_slowdown;
+ toucher.in_swamp = 1;
+ return;
+ }
+
+ //toucher.in_swamp = 1;
+
+ //Revitalize players swampslug
+ toucher.swampslug.health = 2;
+}
+
+REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
+
+#ifdef SVQC
+float swamp_send(entity this, entity to, float sf)
+{
+ WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
+
+ WriteByte(MSG_ENTITY, this.dmg); // can probably get away with using a single byte here
+ WriteByte(MSG_ENTITY, this.swamp_slowdown);
+ WriteByte(MSG_ENTITY, this.swamp_interval);
+
+ trigger_common_write(this, false);
+
+ return true;
+}
+
+void swamp_link(entity this)
+{
+ trigger_link(this, swamp_send);
+}
+
+/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
+Players gettin into the swamp will
+get slowd down and damaged
+*/
+spawnfunc(trigger_swamp)
+{
+ // Init stuff
+ trigger_init(this);
+ settouch(this, swamp_touch);
+
+ // Setup default keys, if missing
+ if(this.dmg <= 0)
+ this.dmg = 5;
+ if(this.swamp_interval <= 0)
+ this.swamp_interval = 1;
+ if(this.swamp_slowdown <= 0)
+ this.swamp_slowdown = 0.5;
+
+ swamp_link(this);
+}
+
+#elif defined(CSQC)
+
+NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
+{
+ this.dmg = ReadByte();
+ this.swamp_slowdown = ReadByte();
+ this.swamp_interval = ReadByte();
+
+ trigger_common_read(this, false);
+
+ return = true;
+
+ this.classname = "trigger_swamp";
+ this.solid = SOLID_TRIGGER;
+ settouch(this, swamp_touch);
+ this.drawmask = MASK_NORMAL;
+ this.move_time = time;
+ this.entremove = trigger_remove_generic;
+}
+#endif
--- /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
switch(this.skin)
{
case 0: return (targ.health < autocvar_g_balance_health_regenstable);
- case 1: return ((targ.ammo_cells && targ.ammo_cells < g_pickup_cells_max) || (targ.ammo_plasma && targ.ammo_plasma < g_pickup_plasma_max) || (targ.ammo_rockets && targ.ammo_rockets < g_pickup_rockets_max) || (targ.ammo_nails && targ.ammo_nails < g_pickup_nails_max) || (targ.ammo_shells && targ.ammo_shells < g_pickup_shells_max));
+ case 1:
+ {
+ return ((GetResourceAmount(targ, RESOURCE_CELLS) && GetResourceAmount(targ, RESOURCE_CELLS) < g_pickup_cells_max)
+ || (GetResourceAmount(targ, RESOURCE_PLASMA) && GetResourceAmount(targ, RESOURCE_PLASMA) < g_pickup_plasma_max)
+ || (GetResourceAmount(targ, RESOURCE_ROCKETS) && GetResourceAmount(targ, RESOURCE_ROCKETS) < g_pickup_rockets_max)
+ || (GetResourceAmount(targ, RESOURCE_BULLETS) && GetResourceAmount(targ, RESOURCE_BULLETS) < g_pickup_nails_max)
+ || (GetResourceAmount(targ, RESOURCE_SHELLS) && GetResourceAmount(targ, RESOURCE_SHELLS) < g_pickup_shells_max)
+ );
+ }
case 2: return (targ.armorvalue < autocvar_g_balance_armor_regenstable);
case 3: return (targ.health > 0);
}
this.realowner.mage_spike = NULL;
Send_Effect(EFFECT_EXPLOSION_SMALL, this.origin, '0 0 0', 1);
- RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
+ RadiusDamage (this, this.realowner, (autocvar_g_monster_mage_attack_spike_damage), (autocvar_g_monster_mage_attack_spike_damage) * 0.5, (autocvar_g_monster_mage_attack_spike_radius),
NULL, NULL, 0, DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, directhitentity);
delete(this);
fx = EFFECT_HEALING;
break;
case 1:
- if(it.ammo_cells) it.ammo_cells = bound(it.ammo_cells, it.ammo_cells + 1, g_pickup_cells_max);
- if(it.ammo_plasma) it.ammo_plasma = bound(it.ammo_plasma, it.ammo_plasma + 1, g_pickup_plasma_max);
- if(it.ammo_rockets) it.ammo_rockets = bound(it.ammo_rockets, it.ammo_rockets + 1, g_pickup_rockets_max);
- if(it.ammo_shells) it.ammo_shells = bound(it.ammo_shells, it.ammo_shells + 2, g_pickup_shells_max);
- if(it.ammo_nails) it.ammo_nails = bound(it.ammo_nails, it.ammo_nails + 5, g_pickup_nails_max);
+ {
+ float tmpfld;
+ tmpfld = GetResourceAmount(it, RESOURCE_CELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_CELLS, bound(tmpfld, tmpfld + 1, g_pickup_cells_max));
+ tmpfld = GetResourceAmount(it, RESOURCE_PLASMA); if(tmpfld) SetResourceAmount(it, RESOURCE_PLASMA, bound(tmpfld, tmpfld + 1, g_pickup_plasma_max));
+ tmpfld = GetResourceAmount(it, RESOURCE_ROCKETS); if(tmpfld) SetResourceAmount(it, RESOURCE_ROCKETS, bound(tmpfld, tmpfld + 1, g_pickup_rockets_max));
+ tmpfld = GetResourceAmount(it, RESOURCE_SHELLS); if(tmpfld) SetResourceAmount(it, RESOURCE_SHELLS, bound(tmpfld, tmpfld + 2, g_pickup_shells_max));
+ tmpfld = GetResourceAmount(it, RESOURCE_BULLETS); if(tmpfld) SetResourceAmount(it, RESOURCE_BULLETS, bound(tmpfld, tmpfld + 5, g_pickup_nails_max));
fx = EFFECT_AMMO_REGEN;
break;
+ }
case 2:
if(it.armorvalue < autocvar_g_balance_armor_regenstable)
{
void M_Mage_Attack_Push(entity this)
{
sound(this, CH_SHOTS, SND_TAGEXP1, 1, ATTEN_NORM);
- RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
+ RadiusDamage (this, this, (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_damage), (autocvar_g_monster_mage_attack_push_radius),
NULL, NULL, (autocvar_g_monster_mage_attack_push_force), DEATH_MONSTER_MAGE.m_id, DMG_NOWEP, this.enemy);
Send_Effect(EFFECT_TE_EXPLOSION, this.origin, '0 0 0', 1);
entity own = this.realowner;
- RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force,
+ RadiusDamage(this, own, autocvar_g_monster_wyvern_attack_fireball_damage, autocvar_g_monster_wyvern_attack_fireball_edgedamage, autocvar_g_monster_wyvern_attack_fireball_force,
NULL, NULL, autocvar_g_monster_wyvern_attack_fireball_radius, this.projectiledeathtype, DMG_NOWEP, NULL);
FOREACH_ENTITY_RADIUS(this.origin, autocvar_g_monster_wyvern_attack_fireball_radius, it.takedamage == DAMAGE_AIM,
#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))
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;
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 { \
#endif
string Buff_UndeprecateName(string buffname);
+entity buff_FirstFromFlags(int _buffs);
REGISTER_BUFF(Null);
BUFF_SPAWNFUNCS(random, BUFF_Null)
#include "sv_buffs.qh"
-#include <common/triggers/target/music.qh>
+#include <common/mapobjects/target/music.qh>
#include <common/gamemodes/_mod.qh>
void buffs_DelayedInit(entity this);
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;
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;
#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 || MUTATOR_IS_ENABLED(mutator_instagib))
#define SV_DAMAGETEXT_SPECTATORS_ONLY() (autocvar_sv_damagetext >= 1)
#define SV_DAMAGETEXT_PLAYERS() (autocvar_sv_damagetext >= 2)
#define SV_DAMAGETEXT_ALL() (autocvar_sv_damagetext >= 3)
// 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;
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)
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);
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
{
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);
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;
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);
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,
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
{
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), "");
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;
{
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)
{
STAT(NADE_BONUS, player) = STAT(NADE_BONUS_SCORE, player) = 0;
}
+
+ if(STAT(VEIL_ORB, player) && STAT(VEIL_ORB, player) <= time)
+ {
+ STAT(VEIL_ORB, player) = 0;
+ if(player.vehicle)
+ player.vehicle.alpha = player.vehicle.nade_veil_prevalpha;
+ else
+ player.alpha = player.nade_veil_prevalpha;
+ }
}
int n = 0;
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)
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);
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)) {
.string cvar_cl_pokenade_type;
.float toss_time;
.float nade_show_particles;
+.float nade_veil_prevalpha;
bool orb_send(entity this, entity to, int sf);
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
*/
-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
{
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];
this.nix_nextincr = time + autocvar_g_balance_nix_incrtime;
}
- this.weapons = '0 0 0';
+ STAT(WEAPONS, this) = '0 0 0';
if(g_nix_with_blaster)
- this.weapons |= WEPSET(BLASTER);
- this.weapons |= e.m_wepset;
+ STAT(WEAPONS, this) |= WEPSET(BLASTER);
+ STAT(WEAPONS, this) |= e.m_wepset;
Weapon w = Weapons_from(nix_weapon);
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
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;
}
// generated file; do not modify
+#ifdef SVQC
+ #include <common/mutators/mutator/offhand_blaster/sv_offhand_blaster.qh>
+#endif
+#include "sv_offhand_blaster.qh"
+
string autocvar_g_offhand_blaster = "0";
REGISTER_MUTATOR(offhand_blaster, expr_evaluate(autocvar_g_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
-#include "hmg.qh"
-
-#ifdef SVQC
-
-REGISTER_MUTATOR(hmg_nadesupport, true);
-MUTATOR_HOOKFUNCTION(hmg_nadesupport, Nade_Damage)
-{
- if (M_ARGV(1, entity) != WEP_HMG) return;
- return = true;
- M_ARGV(3, float) /* damage */ = (M_ARGV(0, entity)).max_health * 0.1;
-}
-
-void W_HeavyMachineGun_Attack_Auto(Weapon thiswep, entity actor, .entity weaponentity, int fire)
-{
- if (!PHYS_INPUT_BUTTON_ATCK(actor))
- {
- w_ready(thiswep, actor, weaponentity, fire);
- return;
- }
-
- if((!thiswep.wr_checkammo1(thiswep, actor, weaponentity) && !(actor.items & IT_UNLIMITED_WEAPON_AMMO)) || (!(actor.items & IT_SUPERWEAPON) && !(actor.items & IT_UNLIMITED_SUPERWEAPONS)))
- {
- W_SwitchWeapon_Force(actor, w_getbestweapon(actor, weaponentity), weaponentity);
- w_ready(thiswep, actor, weaponentity, fire);
- return;
- }
-
- W_DecreaseAmmo(WEP_HMG, actor, WEP_CVAR(hmg, ammo), weaponentity);
-
- W_SetupShot (actor, weaponentity, true, 0, SND_UZI_FIRE, CH_WEAPON_A, WEP_CVAR(hmg, damage), WEP_HMG.m_id);
-
- if(!autocvar_g_norecoil)
- {
- actor.punchangle_x = random () - 0.5;
- actor.punchangle_y = random () - 0.5;
- }
-
- float hmg_spread = bound(WEP_CVAR(hmg, spread_min), WEP_CVAR(hmg, spread_min) + (WEP_CVAR(hmg, spread_add) * actor.(weaponentity).misc_bulletcounter), WEP_CVAR(hmg, spread_max));
- fireBullet(actor, weaponentity, w_shotorg, w_shotdir, hmg_spread, WEP_CVAR(hmg, solidpenetration), WEP_CVAR(hmg, damage), WEP_CVAR(hmg, force), WEP_HMG.m_id, 0);
-
- actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
-
- Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
-
- W_MachineGun_MuzzleFlash(actor, weaponentity);
- W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
-
- if (autocvar_g_casings >= 2) // casing code
- {
- makevectors(actor.v_angle); // for some reason, this is lost
- SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
- }
-
- int slot = weaponslot(weaponentity);
- ATTACK_FINISHED(actor, slot) = time + WEP_CVAR(hmg, refire) * W_WeaponRateFactor(actor);
- weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR(hmg, refire), W_HeavyMachineGun_Attack_Auto);
-}
-
-METHOD(HeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
-{
- if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
- PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
- else
- PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
-}
-
-METHOD(HeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
-{
- if(WEP_CVAR(hmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR(hmg, ammo)) { // forced reload
- thiswep.wr_reload(thiswep, actor, weaponentity);
- } else
- {
- if (fire & 1)
- if (weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
- {
- actor.(weaponentity).misc_bulletcounter = 0;
- W_HeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
- }
- }
-}
-
-METHOD(HeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
-{
- float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
-
- if(autocvar_g_balance_hmg_reload_ammo)
- ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
- return ammo_amount;
-}
-
-METHOD(HeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
-{
- float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR(hmg, ammo);
-
- if(autocvar_g_balance_hmg_reload_ammo)
- ammo_amount += actor.(weaponentity).(weapon_load[WEP_HMG.m_id]) >= WEP_CVAR(hmg, ammo);
-
- return ammo_amount;
-}
-
-METHOD(HeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
-{
- W_Reload(actor, weaponentity, WEP_CVAR(hmg, ammo), SND_RELOAD);
-}
-
-METHOD(HeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
-{
- return WEAPON_THINKING_WITH_PORTALS;
-}
-
-METHOD(HeavyMachineGun, wr_killmessage, Notification(entity thiswep))
-{
- if(w_deathtype & HITTYPE_SECONDARY)
- return WEAPON_HMG_MURDER_SNIPE;
- else
- return WEAPON_HMG_MURDER_SPRAY;
-}
-
-#endif
-#ifdef CSQC
-
-METHOD(HeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
-{
- vector org2;
- org2 = w_org + w_backoff * 2;
- pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
- if(!w_issilent)
- sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
-}
-
-#endif
+++ /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, 0);
+
+ actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+
+ Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+
+ if (autocvar_g_casings >= 2) // casing code
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
+ SpawnCasing (((random () * 50 + 50) * v_right) - (v_forward * (random () * 25 + 25)) - ((random () * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
+ }
+
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okhmg, refire) * W_WeaponRateFactor(actor);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okhmg, refire), W_OverkillHeavyMachineGun_Attack_Auto);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ else
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+ if ((WEP_CVAR_SEC(okhmg, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+ {
+ // Secondary uses it's own refire timer if refire_type is 1.
+ actor.jump_interval = time + WEP_CVAR_SEC(okhmg, refire) * W_WeaponRateFactor(actor);
+ BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+ if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+ (actor.(weaponentity).wframe == WFRAME_FIRE2))
+ {
+ // Set secondary fire animation.
+ vector a = '0 0 0';
+ actor.(weaponentity).wframe = WFRAME_FIRE2;
+ a = actor.(weaponentity).anim_fire2;
+ a.z *= g_weaponratefactor;
+ FOREACH_CLIENT(true, LAMBDA(
+ if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+ {
+ wframe_send(it, actor.(weaponentity), a, true);
+ }
+ ));
+ animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+ }
+ }
+ if (WEP_CVAR(okhmg, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okhmg, ammo))
+ {
+ // Forced reload.
+ thiswep.wr_reload(thiswep, actor, weaponentity);
+ return;
+ }
+ if (fire & 1) // Primary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+ {
+ return;
+ }
+ actor.(weaponentity).misc_bulletcounter = 0;
+ W_OverkillHeavyMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+ return;
+ }
+ if ((fire & 2) && (WEP_CVAR_SEC(okhmg, refire_type) == 0)) // Secondary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okhmg, refire)))
+ {
+ return;
+ }
+ BLASTER_SECONDARY_ATTACK(okhmg, actor, weaponentity);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okhmg, animtime), w_ready);
+ }
+}
+
+METHOD(OverkillHeavyMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okhmg, ammo);
+ if (autocvar_g_balance_okhmg_reload_ammo)
+ {
+ ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_PRI(okhmg, ammo);
+ }
+ return ammo_amount;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(okhmg, ammo);
+ if (autocvar_g_balance_okhmg_reload_ammo)
+ {
+ ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_HMG.m_id]) >= WEP_CVAR_SEC(okhmg, ammo);
+ }
+ return ammo_amount;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ W_Reload(actor, weaponentity, WEP_CVAR_PRI(okhmg, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillHeavyMachineGun, wr_suicidemessage, Notification(entity thiswep))
+{
+ return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillHeavyMachineGun, wr_killmessage, Notification(entity thiswep))
+{
+ if(w_deathtype & HITTYPE_SECONDARY)
+ return WEAPON_OVERKILL_HMG_MURDER_SNIPE;
+ else
+ return WEAPON_OVERKILL_HMG_MURDER_SPRAY;
+}
+
+#endif
+#ifdef CSQC
+
+METHOD(OverkillHeavyMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+{
+ vector org2;
+ org2 = w_org + w_backoff * 2;
+ pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+ if(!w_issilent)
+ sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTEN_NORM);
+}
+
+#endif
--- /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, 0);
+
+ actor.(weaponentity).misc_bulletcounter = actor.(weaponentity).misc_bulletcounter + 1;
+
+ Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+
+ W_MachineGun_MuzzleFlash(actor, weaponentity);
+ W_AttachToShotorg(actor, weaponentity, actor.(weaponentity).muzzle_flash, '5 0 0');
+
+ if(autocvar_g_casings >= 2) // casing code
+ {
+ makevectors(actor.v_angle); // for some reason, this is lost
+ SpawnCasing(((random() * 50 + 50) * v_right) - (v_forward * (random() * 25 + 25)) - ((random() * 5 - 70) * v_up), 2, vectoangles(v_forward),'0 250 0', 100, 3, actor, weaponentity);
+ }
+
+ int slot = weaponslot(weaponentity);
+ ATTACK_FINISHED(actor, slot) = time + WEP_CVAR_PRI(okmachinegun, refire) * W_WeaponRateFactor(actor);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okmachinegun, refire), W_OverkillMachineGun_Attack_Auto);
+}
+
+METHOD(OverkillMachineGun, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ if(vdist(actor.origin - actor.enemy.origin, <, 3000 - bound(0, skill, 10) * 200))
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+ else
+ PHYS_INPUT_BUTTON_ATCK2(actor) = bot_aim(actor, weaponentity, 1000000, 0, 0.001, false);
+}
+
+METHOD(OverkillMachineGun, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+ if ((WEP_CVAR_SEC(okmachinegun, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+ {
+ // Secondary uses it's own refire timer if refire_type is 1.
+ actor.jump_interval = time + WEP_CVAR_SEC(okmachinegun, refire) * W_WeaponRateFactor(actor);
+ BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+ if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+ (actor.(weaponentity).wframe == WFRAME_FIRE2))
+ {
+ // Set secondary fire animation.
+ vector a = '0 0 0';
+ actor.(weaponentity).wframe = WFRAME_FIRE2;
+ a = actor.(weaponentity).anim_fire2;
+ a.z *= g_weaponratefactor;
+ FOREACH_CLIENT(true, LAMBDA(
+ if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+ {
+ wframe_send(it, actor.(weaponentity), a, true);
+ }
+ ));
+ animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+ }
+ }
+ if (WEP_CVAR(okmachinegun, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okmachinegun, ammo))
+ {
+ // Forced reload
+ thiswep.wr_reload(thiswep, actor, weaponentity);
+ return;
+ }
+ if (fire & 1) // Primary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, false, 0))
+ {
+ return;
+ }
+ actor.(weaponentity).misc_bulletcounter = 0;
+ W_OverkillMachineGun_Attack_Auto(thiswep, actor, weaponentity, fire);
+ return;
+ }
+ if ((fire & 2) && (WEP_CVAR_SEC(okmachinegun, refire_type) == 0)) // Secondary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, true, WEP_CVAR_SEC(okmachinegun, refire)))
+ {
+ return;
+ }
+ BLASTER_SECONDARY_ATTACK(okmachinegun, actor, weaponentity);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okmachinegun, animtime), w_ready);
+ }
+}
+
+METHOD(OverkillMachineGun, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ float ammo_amount;
+ ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okmachinegun, ammo);
+ if (WEP_CVAR(okmachinegun, reload_ammo))
+ {
+ ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_MACHINEGUN.m_id]) >= WEP_CVAR_PRI(okmachinegun, ammo);
+ }
+ return ammo_amount;
+}
+
+METHOD(OverkillMachineGun, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ return true; // Blaster secondary is unlimited.
+}
+
+METHOD(OverkillMachineGun, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ W_Reload(actor, weaponentity, WEP_CVAR_PRI(okmachinegun, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillMachineGun, wr_suicidemessage, Notification(entity thiswep))
+{
+ return WEAPON_THINKING_WITH_PORTALS;
+}
+
+METHOD(OverkillMachineGun, wr_killmessage, Notification(entity thiswep))
+{
+ return WEAPON_OVERKILL_MACHINEGUN_MURDER;
+}
+
+#endif
+#ifdef CSQC
+
+METHOD(OverkillMachineGun, wr_impacteffect, void(entity thiswep, entity actor))
+{
+ vector org2;
+ org2 = w_org + w_backoff * 2;
+ pointparticles(EFFECT_MACHINEGUN_IMPACT, org2, w_backoff * 1000, 1);
+ if(!w_issilent)
+ sound(actor, CH_SHOTS, SND_RIC_RANDOM(), VOL_BASE, ATTN_NORM);
+}
+
+#endif
+
--- /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
+
+.float m_chainsaw_damage; // accumulated damage of the missile as it passes trough enemies
+
+void W_OverkillRocketPropelledChainsaw_Explode(entity this, entity directhitentity)
+{
+ this.event_damage = func_null;
+ this.takedamage = DAMAGE_NO;
+
+ float explosion_damage = RadiusDamage(this, this.realowner, WEP_CVAR_PRI(okrpc, damage), WEP_CVAR_PRI(okrpc, edgedamage), WEP_CVAR_PRI(okrpc, radius), NULL, NULL, WEP_CVAR_PRI(okrpc, force), this.projectiledeathtype, this.weaponentity_fld, directhitentity);
+ if (explosion_damage > 0 && this.m_chainsaw_damage > 0)
+ {
+ // if chainsaw hit something, it removed fired damage (so that direct hit is 100%)
+ // now that we also damaged something by explosion we'd go over 100% so let's add the fired damage back
+ accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, WEP_CVAR(okrpc, damage), 0);
+ }
+
+ delete(this);
+}
+
+void W_OverkillRocketPropelledChainsaw_Explode_think(entity this)
+{
+ W_OverkillRocketPropelledChainsaw_Explode(this, NULL);
+}
+
+void W_OverkillRocketPropelledChainsaw_Touch (entity this, entity toucher)
+{
+ if(WarpZone_Projectile_Touch(this, toucher))
+ if(wasfreed(this))
+ return;
+
+ W_OverkillRocketPropelledChainsaw_Explode(this, toucher);
+}
+
+void W_OverkillRocketPropelledChainsaw_Damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
+{
+ if (this.health <= 0)
+ return;
+
+ if (!W_CheckProjectileDamage(inflictor.realowner, this.realowner, deathtype, -1)) // no exceptions
+ return; // g_projectiles_damage says to halt
+
+ this.health = this.health - damage;
+
+ if (this.health <= 0)
+ W_PrepareExplosionByDamage(this, attacker, W_OverkillRocketPropelledChainsaw_Explode_think);
+}
+
+void W_OverkillRocketPropelledChainsaw_Think(entity this)
+{
+ if(this.cnt <= time)
+ {
+ delete(this);
+ return;
+ }
+
+ float myspeed = vlen(this.velocity);
+ float myspeed_accel = myspeed * sys_frametime;
+ vector mydir = normalize(this.velocity);
+
+ tracebox(this.origin, this.mins, this.maxs, this.origin + mydir * (2 * myspeed_accel), MOVE_NORMAL, this);
+ if (IS_PLAYER(trace_ent))
+ {
+ if (accuracy_isgooddamage(this.realowner, trace_ent))
+ {
+ if (this.m_chainsaw_damage == 0) // first hit
+ {
+ // The fired damage of the explosion is already counted in the statistics (when launching the chainsaw).
+ // We remove it here so that a direct hit that passes through and doesn't damage anything by the explosion later is still 100%.
+ float fired_damage = WEP_CVAR_PRI(okrpc, damage2) - WEP_CVAR_PRI(okrpc, damage);
+ float hit_damage = WEP_CVAR_PRI(okrpc, damage2);
+ accuracy_add(this.realowner, DEATH_WEAPONOF(this.projectiledeathtype).m_id, fired_damage, hit_damage);
+ }
+ this.m_chainsaw_damage += WEP_CVAR_PRI(okrpc, damage2);
+ }
+ Damage(trace_ent, this, this.realowner, WEP_CVAR_PRI(okrpc, damage2), this.projectiledeathtype, this.weaponentity_fld, this.origin, normalize(this.origin - trace_ent.origin) * WEP_CVAR_PRI(okrpc, force));
+ }
+
+ this.velocity = mydir * (myspeed + (WEP_CVAR_PRI(okrpc, speedaccel) * sys_frametime));
+
+ UpdateCSQCProjectile(this);
+ this.nextthink = time;
+}
+
+void W_OverkillRocketPropelledChainsaw_Attack (Weapon thiswep, entity actor, .entity weaponentity)
+{
+ entity missile = spawn(); //WarpZone_RefSys_SpawnSameRefSys(actor);
+ entity flash = spawn ();
+
+ W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(okrpc, ammo), weaponentity);
+ W_SetupShot_ProjectileSize(actor, weaponentity, '-3 -3 -3', '3 3 3', false, 5, SND_ROCKET_FIRE, CH_WEAPON_A, WEP_CVAR_PRI(okrpc, damage), WEP_OVERKILL_RPC.m_id);
+ Send_Effect(EFFECT_ROCKET_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
+ PROJECTILE_MAKETRIGGER(missile);
+
+ missile.owner = missile.realowner = actor;
+ missile.bot_dodge = true;
+ missile.bot_dodgerating = WEP_CVAR_PRI(okrpc, damage) * 2;
+
+ missile.takedamage = DAMAGE_YES;
+ missile.damageforcescale = WEP_CVAR_PRI(okrpc, damageforcescale);
+ missile.health = WEP_CVAR_PRI(okrpc, health);
+ missile.event_damage = W_OverkillRocketPropelledChainsaw_Damage;
+ missile.damagedbycontents = true;
+ IL_PUSH(g_damagedbycontents, missile);
+ set_movetype(missile, MOVETYPE_FLY);
+
+ missile.projectiledeathtype = WEP_OVERKILL_RPC.m_id;
+ missile.weaponentity_fld = weaponentity;
+ setsize (missile, '-3 -3 -3', '3 3 3'); // give it some size so it can be shot
+
+ setorigin(missile, w_shotorg - v_forward * 3); // move it back so it hits the wall at the right point
+ W_SetupProjVelocity_Basic(missile, WEP_CVAR_PRI(okrpc, speed), 0);
+
+ settouch(missile, W_OverkillRocketPropelledChainsaw_Touch);
+
+ setthink(missile, W_OverkillRocketPropelledChainsaw_Think);
+ missile.cnt = time + WEP_CVAR_PRI(okrpc, lifetime);
+ missile.nextthink = time;
+ missile.flags = FL_PROJECTILE;
+ IL_PUSH(g_projectiles, missile);
+ IL_PUSH(g_bot_dodge, missile);
+
+ CSQCProjectile(missile, true, PROJECTILE_RPC, false);
+
+ setmodel(flash, MDL_RPC_MUZZLEFLASH); // precision set below
+ SUB_SetFade (flash, time, 0.1);
+ flash.effects = EF_ADDITIVE | EF_FULLBRIGHT | EF_LOWPRECISION;
+ W_AttachToShotorg(actor, weaponentity, flash, '5 0 0');
+ missile.m_chainsaw_damage = 0;
+
+ MUTATOR_CALLHOOK(EditProjectile, actor, missile);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ PHYS_INPUT_BUTTON_ATCK(actor) = bot_aim(actor, weaponentity, WEP_CVAR_PRI(okrpc, speed), 0, WEP_CVAR_PRI(okrpc, lifetime), false);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
+{
+ if ((WEP_CVAR_SEC(okrpc, refire_type) == 1) && (fire & 2) && (time >= actor.jump_interval))
+ {
+ // Secondary uses it's own refire timer if refire_type is 1.
+ actor.jump_interval = time + WEP_CVAR_SEC(okrpc, refire) * W_WeaponRateFactor(actor);
+ BLASTER_SECONDARY_ATTACK(okrpc, actor, weaponentity);
+ if ((actor.(weaponentity).wframe == WFRAME_IDLE) ||
+ (actor.(weaponentity).wframe == WFRAME_FIRE2))
+ {
+ // Set secondary fire animation.
+ vector a = '0 0 0';
+ actor.(weaponentity).wframe = WFRAME_FIRE2;
+ a = actor.(weaponentity).anim_fire2;
+ a.z *= g_weaponratefactor;
+ FOREACH_CLIENT(true, LAMBDA(
+ if (it == actor || (IS_SPEC(it) && it.enemy == actor))
+ {
+ wframe_send(it, actor.(weaponentity), a, true);
+ }
+ ));
+ animdecide_setaction(actor, ANIMACTION_SHOOT, true);
+ }
+ }
+ if (WEP_CVAR(okrpc, reload_ammo) && actor.(weaponentity).clip_load < WEP_CVAR_PRI(okrpc, ammo))
+ {
+ // Forced reload
+ thiswep.wr_reload(thiswep, actor, weaponentity);
+ return;
+ }
+ if (fire & 1) // Primary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_PRI(okrpc, refire)))
+ {
+ return;
+ }
+ W_OverkillRocketPropelledChainsaw_Attack(thiswep, actor, weaponentity);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE1, WEP_CVAR_PRI(okrpc, animtime), w_ready);
+ return;
+ }
+ if ((fire & 2) && (WEP_CVAR_SEC(okrpc, refire_type) == 0)) // Secondary attack
+ {
+ if (!weapon_prepareattack(thiswep, actor, weaponentity, false, WEP_CVAR_SEC(okrpc, refire)))
+ {
+ return;
+ }
+ BLASTER_SECONDARY_ATTACK(okrpc, actor, weaponentity);
+ weapon_thinkf(actor, weaponentity, WFRAME_FIRE2, WEP_CVAR_SEC(okrpc, animtime), w_ready);
+ }
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_checkammo1, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_PRI(okrpc, ammo);
+ ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_RPC.m_id]) >= WEP_CVAR_PRI(okrpc, ammo);
+ return ammo_amount;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_checkammo2, bool(entity thiswep, entity actor, .entity weaponentity))
+{
+ float ammo_amount = GetResourceAmount(actor, thiswep.ammo_type) >= WEP_CVAR_SEC(okrpc, ammo);
+ ammo_amount += actor.(weaponentity).(weapon_load[WEP_OVERKILL_RPC.m_id]) >= WEP_CVAR_SEC(okrpc, ammo);
+ return ammo_amount;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_reload, void(entity thiswep, entity actor, .entity weaponentity))
+{
+ W_Reload(actor, weaponentity, WEP_CVAR_PRI(okrpc, ammo), SND_RELOAD);
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_suicidemessage, Notification(entity thiswep))
+{
+ if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+ return WEAPON_OVERKILL_RPC_SUICIDE_SPLASH;
+ else
+ return WEAPON_OVERKILL_RPC_SUICIDE_DIRECT;
+}
+
+METHOD(OverkillRocketPropelledChainsaw, wr_killmessage, Notification(entity thiswep))
+{
+ if(w_deathtype & HITTYPE_SECONDARY)
+ return WEAPON_BLASTER_MURDER;
+ else if((w_deathtype & HITTYPE_BOUNCE) || (w_deathtype & HITTYPE_SPLASH))
+ return WEAPON_OVERKILL_RPC_MURDER_SPLASH;
+ else
+ return WEAPON_OVERKILL_RPC_MURDER_DIRECT;
+}
+
+#endif
+
+#ifdef CSQC
+
+METHOD(OverkillRocketPropelledChainsaw, wr_impacteffect, void(entity thiswep, entity actor))
+{
+ vector org2;
+ org2 = w_org + w_backoff * 12;
+ pointparticles(EFFECT_ROCKET_EXPLODE, org2, '0 0 0', 1);
+ if(!w_issilent)
+ sound(actor, CH_SHOTS, SND_ROCKET_IMPACT, VOL_BASE, ATTEN_NORM);
+}
+
+#endif
--- /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
-#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;
-
- BLASTER_SECONDARY_ATTACK(vaporizer, player, weaponentity);
+ 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;
}
}
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;
+ }
+}
#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");
}
#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)
{
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] */
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)
{
// 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) {
#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;
// 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_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;
#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;
#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
#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)
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()) \
+)
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;
#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(!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);
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_initial_random, int, 1,
"For items that don't start spawned: 0: spawn after their normal respawntime; 1: spawn after `random * respawntime` with the *same* random; 2: same as 1 but each item has separate random");
-float shared_random;
-STATIC_INIT(shared_random) { shared_random = random(); }
void Item_ScheduleInitialRespawn(entity e)
{
Item_Show(e, 0);
// range: respawntime .. respawntime + respawntimejitter
spawn_in = e.respawntime + random() * e.respawntimejitter;
}
- else if (autocvar_g_pickup_respawntime_initial_random == 1)
+ else
{
+ float rnd;
+ if (autocvar_g_pickup_respawntime_initial_random == 1)
+ {
+ static float shared_random = 0;
+ // NOTE this code works only if items are scheduled at the same time (normal case)
+ // NOTE2 random() can't return exactly 1 so this check always work as intended
+ if (!shared_random || floor(time) > shared_random)
+ shared_random = floor(time) + random();
+ rnd = shared_random - floor(time);
+ }
+ else
+ rnd = random();
+
// range:
// if respawntime >= ITEM_RESPAWN_TICKS: ITEM_RESPAWN_TICKS .. respawntime + respawntimejitter
// else: 0 .. ITEM_RESPAWN_TICKS
// this is to prevent powerups spawning unexpectedly without waypoints
- spawn_in = ITEM_RESPAWN_TICKS + shared_random * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
- }
- else
- {
- // range: same as 1
- spawn_in = ITEM_RESPAWN_TICKS + random() * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
+ spawn_in = ITEM_RESPAWN_TICKS + rnd * (e.respawntime + e.respawntimejitter - ITEM_RESPAWN_TICKS);
}
Item_ScheduleRespawnIn(e, max(0, game_starttime - time) + ((e.respawntimestart) ? e.respawntimestart : spawn_in));
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;
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))
{
{
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;
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) && (item.ammo_shells) && (GetResourceAmount(player, RESOURCE_SHELLS) < g_pickup_shells_max))
+ c = item.ammo_shells / max(noammorating, GetResourceAmount(player, RESOURCE_SHELLS));
- if ((need_nails) && (item.ammo_nails) && (player.ammo_nails < g_pickup_nails_max))
- c = item.ammo_nails / max(noammorating, player.ammo_nails);
+ if ((need_nails) && (item.ammo_nails) && (GetResourceAmount(player, RESOURCE_BULLETS) < g_pickup_nails_max))
+ c = item.ammo_nails / max(noammorating, GetResourceAmount(player, RESOURCE_BULLETS));
- if ((need_rockets) && (item.ammo_rockets) && (player.ammo_rockets < g_pickup_rockets_max))
- c = item.ammo_rockets / max(noammorating, player.ammo_rockets);
+ if ((need_rockets) && (item.ammo_rockets) && (GetResourceAmount(player, RESOURCE_ROCKETS) < g_pickup_rockets_max))
+ c = item.ammo_rockets / max(noammorating, GetResourceAmount(player, RESOURCE_ROCKETS));
- if ((need_cells) && (item.ammo_cells) && (player.ammo_cells < g_pickup_cells_max))
- c = item.ammo_cells / max(noammorating, player.ammo_cells);
+ if ((need_cells) && (item.ammo_cells) && (GetResourceAmount(player, RESOURCE_CELLS) < g_pickup_cells_max))
+ c = item.ammo_cells / max(noammorating, GetResourceAmount(player, RESOURCE_CELLS));
- if ((need_plasma) && (item.ammo_plasma) && (player.ammo_plasma < g_pickup_plasma_max))
- c = item.ammo_plasma / max(noammorating, player.ammo_plasma);
+ if ((need_plasma) && (item.ammo_plasma) && (GetResourceAmount(player, RESOURCE_PLASMA) < g_pickup_plasma_max))
+ c = item.ammo_plasma / max(noammorating, GetResourceAmount(player, RESOURCE_PLASMA));
- if ((need_fuel) && (item.ammo_fuel) && (player.ammo_fuel < g_pickup_fuel_max))
- c = item.ammo_fuel / max(noammorating, player.ammo_fuel);
+ if ((need_fuel) && (item.ammo_fuel) && (GetResourceAmount(player, RESOURCE_FUEL) < g_pickup_fuel_max))
+ c = item.ammo_fuel / max(noammorating, GetResourceAmount(player, RESOURCE_FUEL));
rating *= min(c, 2);
if(wpn)
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);
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;
if(this.health != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.health), "health");
if(this.armorvalue != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, this.armorvalue), "armor");
FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
- FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(this.weapons & (it.m_wepset)), it.netname));
+ FOREACH(Weapons, it != WEP_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(WEAPONS, this) & (it.m_wepset)), it.netname));
}
this.netname = strzone(this.netname);
//print(this.netname, "\n");
{
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);
}
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_ROT(e, health, 1, pauserothealth_finished, autocvar_g_balance_pause_health_rot, pauseregen_finished, autocvar_g_balance_pause_health_regen, SND_MEGAHEALTH, SND_Null);
if(e.superweapons_finished <= 0)
- if(e.weapons & WEPSET_SUPERWEAPONS)
+ if(STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
e.superweapons_finished = autocvar_g_balance_superweapons_time;
if(e.strength_finished <= 0)
{
.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);
}
void GiveRot(entity e, float v0, float v1, .float rotfield, float rottime, .float regenfield, float regentime);
-#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = e.weapons
+spawnfunc(target_items);
+
+#define PREGIVE_WEAPONS(e) WepSet save_weapons; save_weapons = STAT(WEAPONS, e)
#define PREGIVE(e,f) float save_##f; save_##f = (e).f
-#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(e.weapons & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
+#define POSTGIVE_WEAPON(e,b,snd_incr,snd_decr) GiveSound((e), !!(save_weapons & WepSet_FromWeapon(b)), !!(STAT(WEAPONS, e) & WepSet_FromWeapon(b)), 0, snd_incr, snd_decr)
#define POSTGIVE_BIT(e,f,b,snd_incr,snd_decr) GiveSound((e), save_##f & (b), (e).f & (b), 0, snd_incr, snd_decr)
#define POSTGIVE_VALUE(e,f,t,snd_incr,snd_decr) GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
#define POSTGIVE_VALUE_ROT(e,f,t,rotfield,rottime,regenfield,regentime,snd_incr,snd_decr) GiveRot((e), save_##f, (e).f, rotfield, rottime, regenfield, regentime); GiveSound((e), save_##f, (e).f, t, snd_incr, snd_decr)
+++ /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, .entity weaponentity, vector hitloc, vector force);
-
-//
-// func_breakable
-// - basically func_assault_destructible for general gameplay use
-//
-void LaunchDebris (entity this, string debrisname, vector force)
-{
- entity dbr = spawn();
- vector org = this.absmin
- + '1 0 0' * random() * (this.absmax.x - this.absmin.x)
- + '0 1 0' * random() * (this.absmax.y - this.absmin.y)
- + '0 0 1' * random() * (this.absmax.z - this.absmin.z);
- setorigin(dbr, org);
- _setmodel (dbr, debrisname );
- dbr.skin = this.debrisskin;
- dbr.colormap = this.colormap; // inherit team colors
- dbr.owner = this; // do not be affected by our own explosion
- set_movetype(dbr, this.debrismovetype);
- dbr.solid = this.debrissolid;
- if(dbr.solid != SOLID_BSP) // SOLID_BSP has exact collision, MAYBE this works? TODO check this out
- setsize(dbr, '0 0 0', '0 0 0'); // needed for performance, until engine can deal better with it
- dbr.velocity_x = this.debrisvelocity.x + this.debrisvelocityjitter.x * crandom();
- dbr.velocity_y = this.debrisvelocity.y + this.debrisvelocityjitter.y * crandom();
- dbr.velocity_z = this.debrisvelocity.z + this.debrisvelocityjitter.z * crandom();
- dbr.velocity = dbr.velocity + force * this.debrisdamageforcescale;
- dbr.angles = this.angles;
- dbr.avelocity_x = random()*this.debrisavelocityjitter.x;
- dbr.avelocity_y = random()*this.debrisavelocityjitter.y;
- dbr.avelocity_z = random()*this.debrisavelocityjitter.z;
- dbr.damageforcescale = this.debrisdamageforcescale;
- if(dbr.damageforcescale)
- dbr.takedamage = DAMAGE_YES;
- SUB_SetFade(dbr, time + this.debristime + crandom() * this.debristimejitter, this.debrisfadetime);
-}
-
-void func_breakable_colormod(entity this)
-{
- float h;
- if (!(this.spawnflags & 2))
- return;
- h = this.health / this.max_health;
- if(h < 0.25)
- this.colormod = '1 0 0';
- else if(h <= 0.75)
- this.colormod = '1 0 0' + '0 1 0' * (2 * h - 0.5);
- else
- this.colormod = '1 1 1';
-}
-
-void func_breakable_look_destroyed(entity this)
-{
- float floorZ;
-
- if(this.solid == SOLID_BSP) // in case a misc_follow moved me, save the current origin first
- this.dropped_origin = this.origin;
-
- if(this.mdl_dead == "")
- this.effects |= EF_NODRAW;
- else {
- if (this.origin == '0 0 0') { // probably no origin brush, so don't spawn in the middle of the map..
- floorZ = this.absmin.z;
- setorigin(this, ((this.absmax + this.absmin) * 0.5));
- this.origin_z = floorZ;
- }
- _setmodel(this, this.mdl_dead);
- ApplyMinMaxScaleAngles(this);
- this.effects &= ~EF_NODRAW;
- }
-
- this.solid = SOLID_NOT;
-}
-
-void func_breakable_look_restore(entity this)
-{
- _setmodel(this, this.mdl);
- ApplyMinMaxScaleAngles(this);
- this.effects &= ~EF_NODRAW;
-
- if(this.mdl_dead != "") // only do this if we use mdl_dead, to behave better with misc_follow
- setorigin(this, this.dropped_origin);
-
- this.solid = SOLID_BSP;
-}
-
-void func_breakable_behave_destroyed(entity this)
-{
- this.health = this.max_health;
- this.takedamage = DAMAGE_NO;
- if(this.bot_attack)
- IL_REMOVE(g_bot_targets, this);
- this.bot_attack = false;
- this.event_damage = func_null;
- this.state = 1;
- if(this.spawnflags & 4)
- this.use = func_null;
- func_breakable_colormod(this);
- if (this.noise1)
- stopsound (this, CH_TRIGGER_SINGLE);
-}
-
-void func_breakable_think(entity this)
-{
- this.nextthink = time;
- CSQCMODEL_AUTOUPDATE(this);
-}
-
-void func_breakable_destroy(entity this, entity actor, entity trigger);
-void func_breakable_behave_restore(entity this)
-{
- this.health = this.max_health;
- if(this.sprite)
- {
- WaypointSprite_UpdateMaxHealth(this.sprite, this.max_health);
- WaypointSprite_UpdateHealth(this.sprite, this.health);
- }
- if(!(this.spawnflags & 4))
- {
- this.takedamage = DAMAGE_AIM;
- if(!this.bot_attack)
- IL_PUSH(g_bot_targets, this);
- this.bot_attack = true;
- this.event_damage = func_breakable_damage;
- }
- if(this.spawnflags & 4)
- this.use = func_breakable_destroy; // don't need to set it usually, as .use isn't reset
- this.state = 0;
- //this.nextthink = 0; // cancel auto respawn
- setthink(this, func_breakable_think);
- this.nextthink = time + 0.1;
- func_breakable_colormod(this);
- if (this.noise1)
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
-}
-
-void func_breakable_init_for_player(entity this, entity player)
-{
- if (this.noise1 && this.state == 0 && IS_REAL_CLIENT(player))
- {
- msg_entity = player;
- soundto (MSG_ONE, this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- }
-}
-
-void func_breakable_destroyed(entity this)
-{
- func_breakable_look_destroyed(this);
- func_breakable_behave_destroyed(this);
-}
-
-void func_breakable_restore(entity this, entity actor, entity trigger)
-{
- func_breakable_look_restore(this);
- func_breakable_behave_restore(this);
-}
-
-void func_breakable_restore_self(entity this)
-{
- func_breakable_restore(this, NULL, NULL);
-}
-
-vector debrisforce; // global, set before calling this
-void func_breakable_destroy(entity this, entity actor, entity trigger)
-{
- float n, i;
- string oldmsg;
-
- entity act = this.owner;
- this.owner = NULL; // set by W_PrepareExplosionByDamage
-
- // now throw around the debris
- n = tokenize_console(this.debris);
- for(i = 0; i < n; ++i)
- LaunchDebris(this, argv(i), debrisforce);
-
- func_breakable_destroyed(this);
-
- if(this.noise)
- _sound (this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
-
- if(this.dmg)
- RadiusDamage(this, act, this.dmg, this.dmg_edge, this.dmg_radius, this, NULL, this.dmg_force, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, NULL);
-
- if(this.cnt) // TODO
- __pointparticles(this.cnt, this.absmin * 0.5 + this.absmax * 0.5, '0 0 0', this.count);
-
- if(this.respawntime)
- {
- CSQCMODEL_AUTOUPDATE(this);
- setthink(this, func_breakable_restore_self);
- this.nextthink = time + this.respawntime + crandom() * this.respawntimejitter;
- }
-
- oldmsg = this.message;
- this.message = "";
- SUB_UseTargets(this, act, trigger);
- this.message = oldmsg;
-}
-
-void func_breakable_destroy_self(entity this)
-{
- func_breakable_destroy(this, NULL, NULL);
-}
-
-void func_breakable_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
- if(this.state == 1)
- return;
- if(this.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- if(this.team)
- if(attacker.team == this.team)
- return;
- this.pain_finished = time;
- this.health = this.health - damage;
- if(this.sprite)
- {
- WaypointSprite_Ping(this.sprite);
- WaypointSprite_UpdateHealth(this.sprite, this.health);
- }
- func_breakable_colormod(this);
-
- if(this.health <= 0)
- {
- debrisforce = force;
-
- this.takedamage = DAMAGE_NO;
- this.event_damage = func_null;
-
- if(IS_CLIENT(attacker)) //&& this.classname == "func_assault_destructible")
- {
- this.owner = attacker;
- this.realowner = attacker;
- }
-
- // do not explode NOW but in the NEXT FRAME!
- // because recursive calls to RadiusDamage are not allowed
- this.nextthink = time;
- CSQCMODEL_AUTOUPDATE(this);
- setthink(this, func_breakable_destroy_self);
- }
-}
-
-void func_breakable_reset(entity this)
-{
- this.team = this.team_saved;
- func_breakable_look_restore(this);
- if(this.spawnflags & 1)
- func_breakable_behave_destroyed(this);
- else
- func_breakable_behave_restore(this);
-}
-
-// destructible walls that can be used to trigger target_objective_decrease
-spawnfunc(func_breakable)
-{
- float n, i;
- if(!this.health)
- this.health = 100;
- this.max_health = this.health;
-
- // yes, I know, MOVETYPE_NONE is not available here, not that one would want it here anyway
- if(!this.debrismovetype) this.debrismovetype = MOVETYPE_BOUNCE;
- if(!this.debrissolid) this.debrissolid = SOLID_NOT;
- if(this.debrisvelocity == '0 0 0') this.debrisvelocity = '0 0 140';
- if(this.debrisvelocityjitter == '0 0 0') this.debrisvelocityjitter = '70 70 70';
- if(this.debrisavelocityjitter == '0 0 0') this.debrisavelocityjitter = '600 600 600';
- if(!this.debristime) this.debristime = 3.5;
- if(!this.debristimejitter) this.debristime = 2.5;
-
- if(this.mdl != "")
- this.cnt = _particleeffectnum(this.mdl);
- if(this.count == 0)
- this.count = 1;
-
- if(this.message == "")
- this.message = "got too close to an explosion";
- if(this.message2 == "")
- this.message2 = "was pushed into an explosion by";
- if(!this.dmg_radius)
- this.dmg_radius = 150;
- if(!this.dmg_force)
- this.dmg_force = 200;
-
- this.mdl = this.model;
- SetBrushEntityModel(this);
-
- if(this.spawnflags & 4)
- this.use = func_breakable_destroy;
- else
- this.use = func_breakable_restore;
-
- if(this.spawnflags & 4)
- {
- this.takedamage = DAMAGE_NO;
- this.event_damage = func_null;
- this.bot_attack = false;
- }
-
- // precache all the models
- if (this.mdl_dead)
- precache_model(this.mdl_dead);
- n = tokenize_console(this.debris);
- for(i = 0; i < n; ++i)
- precache_model(argv(i));
- if(this.noise)
- precache_sound(this.noise);
- if(this.noise1)
- precache_sound(this.noise1);
-
- this.team_saved = this.team;
- IL_PUSH(g_saved_team, this);
- this.dropped_origin = this.origin;
-
- this.reset = func_breakable_reset;
- this.reset(this);
-
- IL_PUSH(g_initforplayer, this);
- this.init_for_player = func_breakable_init_for_player;
-
- CSQCMODEL_AUTOINIT(this);
-}
-
-// for use in maps with a "model" key set
-spawnfunc(misc_breakablemodel) {
- spawnfunc_func_breakable(this);
-}
-#endif
+++ /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, .entity weaponentity, vector hitloc, vector force)
-{
- if(this.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- if (this.spawnflags & BUTTON_DONTACCUMULATEDMG)
- {
- if (this.health <= damage)
- {
- this.enemy = attacker;
- button_fire(this);
- }
- }
- else
- {
- this.health = this.health - damage;
- if (this.health <= 0)
- {
- this.enemy = attacker;
- button_fire(this);
- }
- }
-}
-
-
-/*QUAKED spawnfunc_func_button (0 .5 .8) ?
-When a button is touched, it moves some distance in the direction of it's angle, triggers all of it's targets, waits some time, then returns to it's original position where it can be triggered again.
-
-"angle" determines the opening direction
-"target" all entities with a matching targetname will be used
-"speed" override the default 40 speed
-"wait" override the default 1 second wait (-1 = never return)
-"lip" override the default 4 pixel lip remaining at end of move
-"health" if set, the button must be killed instead of touched. If set to -1, the button will fire on ANY attack, even damageless ones like the InstaGib laser
-"sounds"
-0) steam metal
-1) wooden clunk
-2) metallic click
-3) in-out
-*/
-spawnfunc(func_button)
-{
- SetMovedir(this);
-
- if (!InitMovingBrushTrigger(this))
- return;
- this.effects |= EF_LOWPRECISION;
-
- setblocked(this, button_blocked);
- this.use = button_use;
-
-// if (this.health == 0) // all buttons are now shootable
-// this.health = 10;
- if (this.health)
- {
- this.max_health = this.health;
- this.event_damage = button_damage;
- this.takedamage = DAMAGE_YES;
- }
- else
- settouch(this, button_touch);
-
- if (!this.speed)
- this.speed = 40;
- if (!this.wait)
- this.wait = 1;
- if (!this.lip)
- this.lip = 4;
-
- if(this.noise != "")
- precache_sound(this.noise);
-
- this.active = ACTIVE_ACTIVE;
-
- this.pos1 = this.origin;
- this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
- this.flags |= FL_NOTARGET;
-
- this.reset = button_reset;
-
- button_reset(this);
-}
-#endif
+++ /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);
- WriteVector(MSG_ENTITY, this.origin);
-
- WriteVector(MSG_ENTITY, this.mins);
- WriteVector(MSG_ENTITY, this.maxs);
-
- WriteVector(MSG_ENTITY, this.movedir);
-
- WriteByte(MSG_ENTITY, this.speed);
- WriteByte(MSG_ENTITY, this.state);
-
- WriteString(MSG_ENTITY, this.targetname);
- WriteString(MSG_ENTITY, this.target);
- }
-
- if(sf & 2)
- WriteByte(MSG_ENTITY, this.state);
-
- return true;
-}
-
-void conveyor_init(entity this)
-{
- if (!this.speed) this.speed = 200;
- this.movedir *= this.speed;
- setthink(this, conveyor_think);
- this.nextthink = time;
- IFTARGETED
- {
- this.use = conveyor_use;
- this.reset = conveyor_reset;
- this.reset(this);
- }
- else
- this.state = 1;
-
- FixSize(this);
-
- Net_LinkEntity(this, 0, false, conveyor_send);
-
- this.SendFlags |= 1;
-}
-
-spawnfunc(trigger_conveyor)
-{
- SetMovedir(this);
- EXACTTRIGGER_INIT;
- conveyor_init(this);
-}
-
-spawnfunc(func_conveyor)
-{
- SetMovedir(this);
- InitMovingBrushTrigger(this);
- set_movetype(this, MOVETYPE_NONE);
- conveyor_init(this);
-}
-
-#elif defined(CSQC)
-
-void conveyor_draw(entity this) { conveyor_think(this); }
-
-void conveyor_init(entity this, bool isnew)
-{
- if(isnew)
- IL_PUSH(g_drawables, this);
- this.draw = conveyor_draw;
- this.drawmask = MASK_NORMAL;
-
- set_movetype(this, MOVETYPE_NONE);
- this.model = "";
- this.solid = SOLID_TRIGGER;
- this.move_time = time;
-}
-
-NET_HANDLE(ENT_CLIENT_CONVEYOR, bool isnew)
-{
- int sf = ReadByte();
-
- if(sf & 1)
- {
- this.warpzone_isboxy = ReadByte();
- this.origin = ReadVector();
- setorigin(this, this.origin);
-
- this.mins = ReadVector();
- this.maxs = ReadVector();
- setsize(this, this.mins, this.maxs);
-
- this.movedir = ReadVector();
-
- this.speed = ReadByte();
- this.state = ReadByte();
-
- this.targetname = strzone(ReadString());
- this.target = strzone(ReadString());
-
- conveyor_init(this, isnew);
- }
-
- if(sf & 2)
- this.state = ReadByte();
-
- return true;
-}
-#endif
+++ /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, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
- }
- else
- {
-#ifdef SVQC
- if((this.dmg) && (blocker.takedamage == DAMAGE_YES)) // Shall we bite?
- Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-
- // don't change direction for dead or dying stuff
- if(IS_DEAD(blocker)
-#ifdef SVQC
- && (blocker.takedamage == DAMAGE_NO)
-#endif
- )
- {
- if (this.wait >= 0)
- {
- if (this.state == STATE_DOWN)
- if (this.classname == "door")
- {
- door_go_up (this, NULL, NULL);
- } else
- {
- door_rotating_go_up(this, blocker);
- }
- else
- if (this.classname == "door")
- {
- door_go_down (this);
- } else
- {
- door_rotating_go_down (this);
- }
- }
- }
-#ifdef SVQC
- else
- {
- //gib dying stuff just to make sure
- if((this.dmg) && (blocker.takedamage != DAMAGE_NO)) // Shall we bite?
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
- }
-#endif
- }
-}
-
-void door_hit_top(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = STATE_TOP;
- if (this.spawnflags & DOOR_TOGGLE)
- return; // don't come down automatically
- if (this.classname == "door")
- {
- setthink(this, door_go_down);
- } else
- {
- setthink(this, door_rotating_go_down);
- }
- this.nextthink = this.ltime + this.wait;
-}
-
-void door_hit_bottom(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = STATE_BOTTOM;
-}
-
-void door_go_down(entity this)
-{
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- if (this.max_health)
- {
- this.takedamage = DAMAGE_YES;
- this.health = this.max_health;
- }
-
- this.state = STATE_DOWN;
- SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_hit_bottom);
-}
-
-void door_go_up(entity this, entity actor, entity trigger)
-{
- if (this.state == STATE_UP)
- return; // already going up
-
- if (this.state == STATE_TOP)
- { // reset top wait time
- this.nextthink = this.ltime + this.wait;
- return;
- }
-
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- this.state = STATE_UP;
- SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_hit_top);
-
- string oldmessage;
- oldmessage = this.message;
- this.message = "";
- SUB_UseTargets(this, actor, trigger);
- this.message = oldmessage;
-}
-
-
-/*
-=============================================================================
-
-ACTIVATION FUNCTIONS
-
-=============================================================================
-*/
-
-bool door_check_keys(entity door, entity player)
-{
- if(door.owner)
- door = door.owner;
-
- // no key needed
- if(!door.itemkeys)
- return true;
-
- // this door require a key
- // only a player can have a key
- if(!IS_PLAYER(player))
- return false;
-
- entity store = player;
-#ifdef SVQC
- store = PS(player);
-#endif
- int valid = (door.itemkeys & store.itemkeys);
- door.itemkeys &= ~valid; // only some of the needed keys were given
-
- if(!door.itemkeys)
- {
-#ifdef SVQC
- play2(player, SND(TALK));
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_UNLOCKED);
-#endif
- return true;
- }
-
- if(!valid)
- {
-#ifdef SVQC
- if(player.key_door_messagetime <= time)
- {
- play2(player, door.noise3);
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_NEED, item_keys_keylist(door.itemkeys));
- player.key_door_messagetime = time + 2;
- }
-#endif
- return false;
- }
-
- // door needs keys the player doesn't have
-#ifdef SVQC
- if(player.key_door_messagetime <= time)
- {
- play2(player, door.noise3);
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_DOOR_LOCKED_ALSONEED, item_keys_keylist(door.itemkeys));
- player.key_door_messagetime = time + 2;
- }
-#endif
-
- return false;
-}
-
-void door_fire(entity this, entity actor, entity trigger)
-{
- if (this.owner != this)
- objerror (this, "door_fire: this.owner != this");
-
- if (this.spawnflags & DOOR_TOGGLE)
- {
- if (this.state == STATE_UP || this.state == STATE_TOP)
- {
- entity e = this;
- do {
- if (e.classname == "door") {
- door_go_down(e);
- } else {
- door_rotating_go_down(e);
- }
- e = e.enemy;
- } while ((e != this) && (e != NULL));
- return;
- }
- }
-
-// trigger all paired doors
- entity e = this;
- do {
- if (e.classname == "door") {
- door_go_up(e, actor, trigger);
- } else {
- // if the BIDIR spawnflag (==2) is set and the trigger has set trigger_reverse, reverse the opening direction
- if ((e.spawnflags & 2) && trigger.trigger_reverse!=0 && e.lip != 666 && e.state == STATE_BOTTOM) {
- e.lip = 666; // e.lip is used to remember reverse opening direction for door_rotating
- e.pos2 = '0 0 0' - e.pos2;
- }
- // if BIDIR_IN_DOWN (==8) is set, prevent the door from reoping during closing if it is triggered from the wrong side
- if (!((e.spawnflags & 2) && (e.spawnflags & 8) && e.state == STATE_DOWN
- && (((e.lip == 666) && (trigger.trigger_reverse == 0)) || ((e.lip != 666) && (trigger.trigger_reverse != 0)))))
- {
- door_rotating_go_up(e, trigger);
- }
- }
- e = e.enemy;
- } while ((e != this) && (e != NULL));
-}
-
-void door_use(entity this, entity actor, entity trigger)
-{
- //dprint("door_use (model: ");dprint(this.model);dprint(")\n");
-
- if (this.owner)
- door_fire(this.owner, actor, trigger);
-}
-
-void door_damage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
- if(this.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- this.health = this.health - damage;
-
- if (this.itemkeys)
- {
- // don't allow opening doors through damage if keys are required
- return;
- }
-
- if (this.health <= 0)
- {
- this.owner.health = this.owner.max_health;
- this.owner.takedamage = DAMAGE_NO; // wil be reset upon return
- door_use(this.owner, NULL, NULL);
- }
-}
-
-.float door_finished;
-
-/*
-================
-door_touch
-
-Prints messages
-================
-*/
-
-void door_touch(entity this, entity toucher)
-{
- if (!IS_PLAYER(toucher))
- return;
- if (this.owner.door_finished > time)
- return;
-
- this.owner.door_finished = time + 2;
-
-#ifdef SVQC
- if (!(this.owner.dmg) && (this.owner.message != ""))
- {
- if (IS_CLIENT(toucher))
- centerprint(toucher, this.owner.message);
- play2(toucher, this.owner.noise);
- }
-#endif
-}
-
-void door_generic_plat_blocked(entity this, entity blocker)
-{
- if((this.spawnflags & 8) && (blocker.takedamage != DAMAGE_NO)) { // Kill Kill Kill!!
-#ifdef SVQC
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
- }
- else
- {
-
-#ifdef SVQC
- if((this.dmg) && (blocker.takedamage == DAMAGE_YES)) // Shall we bite?
- Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
-
- //Dont chamge direction for dead or dying stuff
- if(IS_DEAD(blocker) && (blocker.takedamage == DAMAGE_NO))
- {
- if (this.wait >= 0)
- {
- if (this.state == STATE_DOWN)
- door_rotating_go_up (this, blocker);
- else
- door_rotating_go_down (this);
- }
- }
-#ifdef SVQC
- else
- {
- //gib dying stuff just to make sure
- if((this.dmg) && (blocker.takedamage != DAMAGE_NO)) // Shall we bite?
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
- }
-#endif
- }
-}
-
-void door_rotating_hit_top(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = STATE_TOP;
- if (this.spawnflags & DOOR_TOGGLE)
- return; // don't come down automatically
- setthink(this, door_rotating_go_down);
- this.nextthink = this.ltime + this.wait;
-}
-
-void door_rotating_hit_bottom(entity this)
-{
- if (this.noise1 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- if (this.lip==666) // this.lip is used to remember reverse opening direction for door_rotating
- {
- this.pos2 = '0 0 0' - this.pos2;
- this.lip = 0;
- }
- this.state = STATE_BOTTOM;
-}
-
-void door_rotating_go_down(entity this)
-{
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- if (this.max_health)
- {
- this.takedamage = DAMAGE_YES;
- this.health = this.max_health;
- }
-
- this.state = STATE_DOWN;
- SUB_CalcAngleMove (this, this.pos1, TSPEED_LINEAR, this.speed, door_rotating_hit_bottom);
-}
-
-void door_rotating_go_up(entity this, entity oth)
-{
- if (this.state == STATE_UP)
- return; // already going up
-
- if (this.state == STATE_TOP)
- { // reset top wait time
- this.nextthink = this.ltime + this.wait;
- return;
- }
- if (this.noise2 != "")
- _sound (this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- this.state = STATE_UP;
- SUB_CalcAngleMove (this, this.pos2, TSPEED_LINEAR, this.speed, door_rotating_hit_top);
-
- string oldmessage;
- oldmessage = this.message;
- this.message = "";
- SUB_UseTargets(this, NULL, oth); // TODO: is oth needed here?
- this.message = oldmessage;
-}
-
-
-/*
-=========================================
-door trigger
-
-Spawned if a door lacks a real activator
-=========================================
-*/
-
-void door_trigger_touch(entity this, entity toucher)
-{
- if (toucher.health < 1)
-#ifdef SVQC
- if (!((toucher.iscreature || (toucher.flags & FL_PROJECTILE)) && !IS_DEAD(toucher)))
-#elif defined(CSQC)
- if(!((IS_CLIENT(toucher) || toucher.classname == "csqcprojectile") && !IS_DEAD(toucher)))
-#endif
- return;
-
- if (time < this.door_finished)
- return;
-
- // check if door is locked
- if (!door_check_keys(this, toucher))
- return;
-
- this.door_finished = time + 1;
-
- door_use(this.owner, toucher, NULL);
-}
-
-void door_spawnfield(entity this, vector fmins, vector fmaxs)
-{
- entity trigger;
- vector t1 = fmins, t2 = fmaxs;
-
- trigger = new(doortriggerfield);
- set_movetype(trigger, MOVETYPE_NONE);
- trigger.solid = SOLID_TRIGGER;
- trigger.owner = this;
-#ifdef SVQC
- settouch(trigger, door_trigger_touch);
-#endif
-
- setsize (trigger, t1 - '60 60 8', t2 + '60 60 8');
-}
-
-
-/*
-=============
-LinkDoors
-
-
-=============
-*/
-
-entity LinkDoors_nextent(entity cur, entity near, entity pass)
-{
- while((cur = find(cur, classname, pass.classname)) && ((cur.spawnflags & 4) || cur.enemy))
- {
- }
- return cur;
-}
-
-bool LinkDoors_isconnected(entity e1, entity e2, entity pass)
-{
- float DELTA = 4;
- if((e1.absmin_x > e2.absmax_x + DELTA)
- || (e1.absmin_y > e2.absmax_y + DELTA)
- || (e1.absmin_z > e2.absmax_z + DELTA)
- || (e2.absmin_x > e1.absmax_x + DELTA)
- || (e2.absmin_y > e1.absmax_y + DELTA)
- || (e2.absmin_z > e1.absmax_z + DELTA)
- ) { return false; }
- return true;
-}
-
-#ifdef SVQC
-void door_link();
-#endif
-void LinkDoors(entity this)
-{
- entity t;
- vector cmins, cmaxs;
-
-#ifdef SVQC
- door_link();
-#endif
-
- if (this.enemy)
- return; // already linked by another door
- if (this.spawnflags & 4)
- {
- this.owner = this.enemy = this;
-
- if (this.health)
- return;
- IFTARGETED
- return;
- if (this.items)
- return;
-
- door_spawnfield(this, this.absmin, this.absmax);
-
- return; // don't want to link this door
- }
-
- FindConnectedComponent(this, enemy, LinkDoors_nextent, LinkDoors_isconnected, this);
-
- // set owner, and make a loop of the chain
- LOG_TRACE("LinkDoors: linking doors:");
- for(t = this; ; t = t.enemy)
- {
- LOG_TRACE(" ", etos(t));
- t.owner = this;
- if(t.enemy == NULL)
- {
- t.enemy = this;
- break;
- }
- }
- LOG_TRACE("");
-
- // collect health, targetname, message, size
- cmins = this.absmin;
- cmaxs = this.absmax;
- for(t = this; ; t = t.enemy)
- {
- if(t.health && !this.health)
- this.health = t.health;
- if((t.targetname != "") && (this.targetname == ""))
- this.targetname = t.targetname;
- if((t.message != "") && (this.message == ""))
- this.message = t.message;
- if (t.absmin_x < cmins_x)
- cmins_x = t.absmin_x;
- if (t.absmin_y < cmins_y)
- cmins_y = t.absmin_y;
- if (t.absmin_z < cmins_z)
- cmins_z = t.absmin_z;
- if (t.absmax_x > cmaxs_x)
- cmaxs_x = t.absmax_x;
- if (t.absmax_y > cmaxs_y)
- cmaxs_y = t.absmax_y;
- if (t.absmax_z > cmaxs_z)
- cmaxs_z = t.absmax_z;
- if(t.enemy == this)
- break;
- }
-
- // distribute health, targetname, message
- for(t = this; t; t = t.enemy)
- {
- t.health = this.health;
- t.targetname = this.targetname;
- t.message = this.message;
- if(t.enemy == this)
- break;
- }
-
- // shootable, or triggered doors just needed the owner/enemy links,
- // they don't spawn a field
-
- if (this.health)
- return;
- IFTARGETED
- return;
- if (this.items)
- return;
-
- door_spawnfield(this, cmins, cmaxs);
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_DOOR)
-
-#ifdef SVQC
-/*QUAKED spawnfunc_func_door (0 .5 .8) ? START_OPEN x DOOR_DONT_LINK GOLD_KEY SILVER_KEY TOGGLE
-if two doors touch, they are assumed to be connected and operate as a unit.
-
-TOGGLE causes the door to wait in both the start and end states for a trigger event.
-
-START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not useful for touch or takedamage doors).
-
-GOLD_KEY causes the door to open only if the activator holds a gold key.
-
-SILVER_KEY causes the door to open only if the activator holds a silver key.
-
-"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet
-"angle" determines the opening direction
-"targetname" if set, no touch field will be spawned and a remote button or trigger field activates the door.
-"health" if set, door must be shot open
-"speed" movement speed (100 default)
-"wait" wait before returning (3 default, -1 = never return)
-"lip" lip remaining at end of move (8 default)
-"dmg" damage to inflict when blocked (2 default)
-"sounds"
-0) no sound
-1) stone
-2) base
-3) stone chain
-4) screechy metal
-FIXME: only one sound set available at the time being
-
-*/
-
-float door_send(entity this, entity to, float sf)
-{
- WriteHeader(MSG_ENTITY, ENT_CLIENT_DOOR);
- WriteByte(MSG_ENTITY, sf);
-
- if(sf & SF_TRIGGER_INIT)
- {
- WriteString(MSG_ENTITY, this.classname);
- WriteByte(MSG_ENTITY, this.spawnflags);
-
- WriteString(MSG_ENTITY, this.model);
-
- trigger_common_write(this, true);
-
- WriteVector(MSG_ENTITY, this.pos1);
- WriteVector(MSG_ENTITY, this.pos2);
-
- WriteVector(MSG_ENTITY, this.size);
-
- WriteShort(MSG_ENTITY, this.wait);
- WriteShort(MSG_ENTITY, this.speed);
- WriteByte(MSG_ENTITY, this.lip);
- WriteByte(MSG_ENTITY, this.state);
- WriteCoord(MSG_ENTITY, this.ltime);
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- // client makes use of this, we do not
- }
-
- if(sf & SF_TRIGGER_UPDATE)
- {
- WriteVector(MSG_ENTITY, this.origin);
-
- WriteVector(MSG_ENTITY, this.pos1);
- WriteVector(MSG_ENTITY, this.pos2);
- }
-
- return true;
-}
-
-void door_link()
-{
- // set size now, as everything is loaded
- //FixSize(this);
- //Net_LinkEntity(this, false, 0, door_send);
-}
-#endif
-
-void door_init_startopen(entity this)
-{
- setorigin(this, this.pos2);
- this.pos2 = this.pos1;
- this.pos1 = this.origin;
-
-#ifdef SVQC
- this.SendFlags |= SF_TRIGGER_UPDATE;
-#endif
-}
-
-void door_reset(entity this)
-{
- setorigin(this, this.pos1);
- this.velocity = '0 0 0';
- this.state = STATE_BOTTOM;
- setthink(this, func_null);
- this.nextthink = 0;
-
-#ifdef SVQC
- this.SendFlags |= SF_TRIGGER_RESET;
-#endif
-}
-
-#ifdef SVQC
-
-// spawnflags require key (for now only func_door)
-spawnfunc(func_door)
-{
- // Quake 1 keys compatibility
- if (this.spawnflags & SPAWNFLAGS_GOLD_KEY)
- this.itemkeys |= ITEM_KEY_BIT(0);
- if (this.spawnflags & SPAWNFLAGS_SILVER_KEY)
- this.itemkeys |= ITEM_KEY_BIT(1);
-
- SetMovedir(this);
-
- this.max_health = this.health;
- if (!InitMovingBrushTrigger(this))
- return;
- this.effects |= EF_LOWPRECISION;
- this.classname = "door";
-
- if(this.noise == "")
- this.noise = "misc/talk.wav";
- if(this.noise3 == "")
- this.noise3 = "misc/talk.wav";
- precache_sound(this.noise);
- precache_sound(this.noise3);
-
- setblocked(this, door_blocked);
- this.use = door_use;
-
- if(this.dmg && (this.message == ""))
- this.message = "was squished";
- if(this.dmg && (this.message2 == ""))
- this.message2 = "was squished by";
-
- if (this.sounds > 0)
- {
- this.noise2 = "plats/medplat1.wav";
- this.noise1 = "plats/medplat2.wav";
- }
-
- if(this.noise1 && this.noise1 != "") { precache_sound(this.noise1); }
- if(this.noise2 && this.noise2 != "") { precache_sound(this.noise2); }
-
- if (!this.speed)
- this.speed = 100;
- if (!this.wait)
- this.wait = 3;
- if (!this.lip)
- this.lip = 8;
-
- this.pos1 = this.origin;
- this.pos2 = this.pos1 + this.movedir*(fabs(this.movedir*this.size) - this.lip);
-
- if(this.spawnflags & DOOR_NONSOLID)
- this.solid = SOLID_NOT;
-
-// DOOR_START_OPEN is to allow an entity to be lighted in the closed position
-// but spawn in the open position
- if (this.spawnflags & DOOR_START_OPEN)
- InitializeEntity(this, door_init_startopen, INITPRIO_SETLOCATION);
-
- this.state = STATE_BOTTOM;
-
- if (this.health)
- {
- //this.canteamdamage = true; // TODO
- this.takedamage = DAMAGE_YES;
- this.event_damage = door_damage;
- }
-
- if (this.items)
- this.wait = -1;
-
- settouch(this, door_touch);
-
-// LinkDoors can't be done until all of the doors have been spawned, so
-// the sizes can be detected properly.
- InitializeEntity(this, LinkDoors, INITPRIO_LINKDOORS);
-
- this.reset = door_reset;
-}
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_DOOR, bool isnew)
-{
- int sf = ReadByte();
-
- if(sf & SF_TRIGGER_INIT)
- {
- this.classname = strzone(ReadString());
- this.spawnflags = ReadByte();
-
- this.mdl = strzone(ReadString());
- _setmodel(this, this.mdl);
-
- trigger_common_read(this, true);
-
- this.pos1 = ReadVector();
- this.pos2 = ReadVector();
-
- this.size = ReadVector();
-
- this.wait = ReadShort();
- this.speed = ReadShort();
- this.lip = ReadByte();
- this.state = ReadByte();
- this.ltime = ReadCoord();
-
- this.solid = SOLID_BSP;
- set_movetype(this, MOVETYPE_PUSH);
- this.use = door_use;
-
- LinkDoors(this);
-
- if(this.spawnflags & DOOR_START_OPEN)
- door_init_startopen(this);
-
- this.move_time = time;
- set_movetype(this, MOVETYPE_PUSH);
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- door_reset(this);
- }
-
- if(sf & SF_TRIGGER_UPDATE)
- {
- this.origin = ReadVector();
- setorigin(this, this.origin);
-
- this.pos1 = ReadVector();
- this.pos2 = ReadVector();
- }
- return true;
-}
-
-#endif
+++ /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, .entity weaponentity, vector hitloc, vector force)
-{
- fd_secret_use(this, NULL, NULL);
-}
-
-// Wait after first movement...
-void fd_secret_move1(entity this)
-{
- this.nextthink = this.ltime + 1.0;
- setthink(this, fd_secret_move2);
- if (this.noise3 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-// Start moving sideways w/sound...
-void fd_secret_move2(entity this)
-{
- if (this.noise2 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- SUB_CalcMove(this, this.dest2, TSPEED_LINEAR, this.speed, fd_secret_move3);
-}
-
-// Wait here until time to go back...
-void fd_secret_move3(entity this)
-{
- if (this.noise3 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
- if (!(this.spawnflags & SECRET_OPEN_ONCE))
- {
- this.nextthink = this.ltime + this.wait;
- setthink(this, fd_secret_move4);
- }
-}
-
-// Move backward...
-void fd_secret_move4(entity this)
-{
- if (this.noise2 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- SUB_CalcMove(this, this.dest1, TSPEED_LINEAR, this.speed, fd_secret_move5);
-}
-
-// Wait 1 second...
-void fd_secret_move5(entity this)
-{
- this.nextthink = this.ltime + 1.0;
- setthink(this, fd_secret_move6);
- if (this.noise3 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-void fd_secret_move6(entity this)
-{
- if (this.noise2 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise2, VOL_BASE, ATTEN_NORM);
- SUB_CalcMove(this, this.oldorigin, TSPEED_LINEAR, this.speed, fd_secret_done);
-}
-
-void fd_secret_done(entity this)
-{
- if (this.spawnflags&SECRET_YES_SHOOT)
- {
- this.health = 10000;
- this.takedamage = DAMAGE_YES;
- //this.th_pain = fd_secret_use;
- }
- if (this.noise3 != "")
- _sound(this, CH_TRIGGER_SINGLE, this.noise3, VOL_BASE, ATTEN_NORM);
-}
-
-.float door_finished;
-
-void secret_blocked(entity this, entity blocker)
-{
- if (time < this.door_finished)
- return;
- this.door_finished = time + 0.5;
- //T_Damage (other, this, this, this.dmg, this.dmg, this.deathtype, DT_IMPACT, (this.absmin + this.absmax) * 0.5, '0 0 0', Obituary_Generic);
-}
-
-/*
-==============
-secret_touch
-
-Prints messages
-================
-*/
-void secret_touch(entity this, entity toucher)
-{
- if (!toucher.iscreature)
- return;
- if (this.door_finished > time)
- return;
-
- this.door_finished = time + 2;
-
- if (this.message)
- {
- if (IS_CLIENT(toucher))
- centerprint(toucher, this.message);
- play2(toucher, this.noise);
- }
-}
-
-void secret_reset(entity this)
-{
- if (this.spawnflags & SECRET_YES_SHOOT)
- {
- this.health = 10000;
- this.takedamage = DAMAGE_YES;
- }
- setorigin(this, this.oldorigin);
- setthink(this, func_null);
- this.nextthink = 0;
-}
-
-/*QUAKED spawnfunc_func_door_secret (0 .5 .8) ? open_once 1st_left 1st_down no_shoot always_shoot
-Basic secret door. Slides back, then to the side. Angle determines direction.
-wait = # of seconds before coming back
-1st_left = 1st move is left of arrow
-1st_down = 1st move is down from arrow
-always_shoot = even if targeted, keep shootable
-t_width = override WIDTH to move back (or height if going down)
-t_length = override LENGTH to move sideways
-"dmg" damage to inflict when blocked (2 default)
-
-If a secret door has a targetname, it will only be opened by it's botton or trigger, not by damage.
-"sounds"
-1) medieval
-2) metal
-3) base
-*/
-
-spawnfunc(func_door_secret)
-{
- /*if (!this.deathtype) // map makers can override this
- this.deathtype = " got in the way";*/
-
- if (!this.dmg) this.dmg = 2;
-
- // Magic formula...
- this.mangle = this.angles;
- this.angles = '0 0 0';
- this.classname = "door";
- if (!InitMovingBrushTrigger(this)) return;
- this.effects |= EF_LOWPRECISION;
-
- if (this.noise == "") this.noise = "misc/talk.wav";
- precache_sound(this.noise);
-
- settouch(this, secret_touch);
- setblocked(this, secret_blocked);
- this.speed = 50;
- this.use = fd_secret_use;
- IFTARGETED
- {
- }
- else
- this.spawnflags |= SECRET_YES_SHOOT;
-
- if (this.spawnflags & SECRET_YES_SHOOT)
- {
- //this.canteamdamage = true; // TODO
- this.health = 10000;
- this.takedamage = DAMAGE_YES;
- this.event_damage = fd_secret_damage;
- }
- this.oldorigin = this.origin;
- if (!this.wait) this.wait = 5; // seconds before closing
-
- this.reset = secret_reset;
- this.reset(this);
-}
-#endif
+++ /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);
-
- WriteVector(MSG_ENTITY, this.pos1);
- WriteVector(MSG_ENTITY, this.pos2);
-
- WriteVector(MSG_ENTITY, this.size);
-
- WriteAngle(MSG_ENTITY, this.mangle_x);
- WriteAngle(MSG_ENTITY, this.mangle_y);
- WriteAngle(MSG_ENTITY, this.mangle_z);
-
- WriteShort(MSG_ENTITY, this.speed);
- WriteShort(MSG_ENTITY, this.height);
- WriteByte(MSG_ENTITY, this.lip);
- WriteByte(MSG_ENTITY, this.state);
-
- WriteShort(MSG_ENTITY, this.dmg);
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- // used on client
- }
-
- return true;
-}
-
-void plat_link(entity this)
-{
- //Net_LinkEntity(this, 0, false, plat_send);
-}
-
-spawnfunc(func_plat)
-{
- if (this.sounds == 0) this.sounds = 2;
-
- if (this.spawnflags & 4) this.dmg = 10000;
-
- if (this.dmg && (this.message == "")) this.message = "was squished";
- if (this.dmg && (this.message2 == "")) this.message2 = "was squished by";
-
- if (this.sounds == 1)
- {
- this.noise = "plats/plat1.wav";
- this.noise1 = "plats/plat2.wav";
- }
-
- if (this.sounds == 2)
- {
- this.noise = "plats/medplat1.wav";
- this.noise1 = "plats/medplat2.wav";
- }
-
- if (this.sound1)
- this.noise = this.sound1;
- if (this.sound2)
- this.noise1 = this.sound2;
-
- if(this.noise && this.noise != "") { precache_sound(this.noise); }
- if(this.noise1 && this.noise1 != "") { precache_sound(this.noise1); }
-
- this.mangle = this.angles;
- this.angles = '0 0 0';
-
- this.classname = "plat";
- if (!InitMovingBrushTrigger(this))
- return;
- this.effects |= EF_LOWPRECISION;
- setsize (this, this.mins , this.maxs);
-
- setblocked(this, plat_crush);
-
- if (!this.speed) this.speed = 150;
- if (!this.lip) this.lip = 16;
- if (!this.height) this.height = this.size.z - this.lip;
-
- this.pos1 = this.origin;
- this.pos2 = this.origin;
- this.pos2_z = this.origin.z - this.height;
-
- this.reset = plat_reset;
- this.reset(this);
-
- InitializeEntity(this, plat_delayedinit, INITPRIO_FINDTARGET);
-}
-#elif defined(CSQC)
-void plat_draw(entity this)
-{
- Movetype_Physics_NoMatchServer(this);
- //Movetype_Physics_MatchServer(autocvar_cl_projectiles_sloppy);
-}
-
-NET_HANDLE(ENT_CLIENT_PLAT, bool isnew)
-{
- float sf = ReadByte();
-
- if(sf & SF_TRIGGER_INIT)
- {
- this.platmovetype_start = ReadByte();
- this.platmovetype_turn = ReadByte();
- this.platmovetype_end = ReadByte();
- this.spawnflags = ReadByte();
-
- this.model = strzone(ReadString());
- _setmodel(this, this.model);
-
- trigger_common_read(this, true);
-
- this.pos1 = ReadVector();
- this.pos2 = ReadVector();
-
- this.size = ReadVector();
-
- this.mangle_x = ReadAngle();
- this.mangle_y = ReadAngle();
- this.mangle_z = ReadAngle();
-
- this.speed = ReadShort();
- this.height = ReadShort();
- this.lip = ReadByte();
- this.state = ReadByte();
-
- this.dmg = ReadShort();
-
- this.classname = "plat";
- this.solid = SOLID_BSP;
- set_movetype(this, MOVETYPE_PUSH);
- this.drawmask = MASK_NORMAL;
- this.draw = plat_draw;
- if (isnew) IL_PUSH(g_drawables, this);
- this.use = plat_use;
- this.entremove = trigger_remove_generic;
-
- plat_reset(this); // also called here
-
- set_movetype(this, MOVETYPE_PUSH);
- this.move_time = time;
-
- plat_spawn_inside_trigger(this);
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- plat_reset(this);
-
- this.move_time = time;
- }
- return true;
-}
-#endif
+++ /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)
- {
- WriteVector(MSG_ENTITY, this.origin);
- }
- if(fl & 1)
- {
- if(this.model != "null")
- {
- WriteShort(MSG_ENTITY, this.modelindex);
- if(fl & 0x80)
- {
- WriteVector(MSG_ENTITY, this.mins);
- WriteVector(MSG_ENTITY, this.maxs);
- }
- }
- else
- {
- WriteShort(MSG_ENTITY, 0);
- if(fl & 0x80)
- {
- WriteVector(MSG_ENTITY, this.maxs);
- }
- }
- WriteShort(MSG_ENTITY, this.cnt);
- WriteString(MSG_ENTITY, this.mdl);
- if(fl & 0x20)
- {
- WriteShort(MSG_ENTITY, compressShortVector(this.velocity));
- WriteShort(MSG_ENTITY, compressShortVector(this.movedir));
- }
- if(fl & 0x40)
- {
- WriteShort(MSG_ENTITY, this.waterlevel * 16.0);
- WriteByte(MSG_ENTITY, this.count * 16.0);
- }
- WriteString(MSG_ENTITY, this.noise);
- if(this.noise != "")
- {
- WriteByte(MSG_ENTITY, floor(this.atten * 64));
- WriteByte(MSG_ENTITY, floor(this.volume * 255));
- }
- WriteString(MSG_ENTITY, this.bgmscript);
- if(this.bgmscript != "")
- {
- WriteByte(MSG_ENTITY, floor(this.bgmscriptattack * 64));
- WriteByte(MSG_ENTITY, floor(this.bgmscriptdecay * 64));
- WriteByte(MSG_ENTITY, floor(this.bgmscriptsustain * 255));
- WriteByte(MSG_ENTITY, floor(this.bgmscriptrelease * 64));
- }
- }
- return 1;
-}
-
-void pointparticles_use(entity this, entity actor, entity trigger)
-{
- this.state = !this.state;
- this.SendFlags |= 2;
-}
-
-void pointparticles_think(entity this)
-{
- if(this.origin != this.oldorigin)
- {
- this.SendFlags |= 4;
- this.oldorigin = this.origin;
- }
- this.nextthink = time;
-}
-
-void pointparticles_reset(entity this)
-{
- if(this.spawnflags & 1)
- this.state = 1;
- else
- this.state = 0;
-}
-
-spawnfunc(func_pointparticles)
-{
- if(this.model != "") { precache_model(this.model); _setmodel(this, this.model); }
- if(this.noise != "") precache_sound(this.noise);
- if(this.mdl != "") this.cnt = 0; // use a good handler
-
- if(!this.bgmscriptsustain) this.bgmscriptsustain = 1;
- else if(this.bgmscriptsustain < 0) this.bgmscriptsustain = 0;
-
- if(!this.atten) this.atten = ATTEN_NORM;
- else if(this.atten < 0) this.atten = 0;
- if(!this.volume) this.volume = 1;
- if(!this.count) this.count = 1;
- if(!this.impulse) this.impulse = 1;
-
- if(!this.modelindex)
- {
- setorigin(this, this.origin + this.mins);
- setsize(this, '0 0 0', this.maxs - this.mins);
- }
- //if(!this.cnt) this.cnt = _particleeffectnum(this.mdl);
-
- Net_LinkEntity(this, (this.spawnflags & 4), 0, pointparticles_SendEntity);
-
- IFTARGETED
- {
- this.use = pointparticles_use;
- this.reset = pointparticles_reset;
- this.reset(this);
- }
- else
- this.state = 1;
- setthink(this, pointparticles_think);
- this.nextthink = time;
-}
-
-spawnfunc(func_sparks)
-{
- // this.cnt is the amount of sparks that one burst will spawn
- if(this.cnt < 1) {
- this.cnt = 25.0; // nice default value
- }
-
- // this.wait is the probability that a sparkthink will spawn a spark shower
- // range: 0 - 1, but 0 makes little sense, so...
- if(this.wait < 0.05) {
- this.wait = 0.25; // nice default value
- }
-
- this.count = this.cnt;
- this.mins = '0 0 0';
- this.maxs = '0 0 0';
- this.velocity = '0 0 -1';
- this.mdl = "TE_SPARK";
- this.impulse = 10 * this.wait; // by default 2.5/sec
- this.wait = 0;
- this.cnt = 0; // use mdl
-
- spawnfunc_func_pointparticles(this);
-}
-#elif defined(CSQC)
-
-.int dphitcontentsmask;
-
-entityclass(PointParticles);
-class(PointParticles) .int cnt; // effect number
-class(PointParticles) .vector velocity; // particle velocity
-class(PointParticles) .float waterlevel; // direction jitter
-class(PointParticles) .int count; // count multiplier
-class(PointParticles) .int impulse; // density
-class(PointParticles) .string noise; // sound
-class(PointParticles) .float atten;
-class(PointParticles) .float volume;
-class(PointParticles) .float absolute; // 1 = count per second is absolute, 2 = only spawn at toggle
-class(PointParticles) .vector movedir; // trace direction
-class(PointParticles) .float glow_color; // palette index
-
-void Draw_PointParticles(entity this)
-{
- float n, i, fail;
- vector p;
- vector sz;
- vector o;
- o = this.origin;
- sz = this.maxs - this.mins;
- n = doBGMScript(this);
- if(this.absolute == 2)
- {
- if(n >= 0)
- n = this.just_toggled ? this.impulse : 0;
- else
- n = this.impulse * drawframetime;
- }
- else
- {
- n *= this.impulse * drawframetime;
- if(this.just_toggled)
- if(n < 1)
- n = 1;
- }
- if(n == 0)
- return;
- fail = 0;
- for(i = random(); i <= n && fail <= 64*n; ++i)
- {
- p = o + this.mins;
- p.x += random() * sz.x;
- p.y += random() * sz.y;
- p.z += random() * sz.z;
- if(WarpZoneLib_BoxTouchesBrush(p, p, this, NULL))
- {
- if(this.movedir != '0 0 0')
- {
- traceline(p, p + normalize(this.movedir) * 4096, 0, NULL);
- p = trace_endpos;
- int eff_num;
- if(this.cnt)
- eff_num = this.cnt;
- else
- eff_num = _particleeffectnum(this.mdl);
- __pointparticles(eff_num, p, trace_plane_normal * vlen(this.movedir) + this.velocity + randomvec() * this.waterlevel, this.count);
- }
- else
- {
- int eff_num;
- if(this.cnt)
- eff_num = this.cnt;
- else
- eff_num = _particleeffectnum(this.mdl);
- __pointparticles(eff_num, p, this.velocity + randomvec() * this.waterlevel, this.count);
- }
- if(this.noise != "")
- {
- setorigin(this, p);
- _sound(this, CH_AMBIENT, this.noise, VOL_BASE * this.volume, this.atten);
- }
- this.just_toggled = 0;
- }
- else if(this.absolute)
- {
- ++fail;
- --i;
- }
- }
- setorigin(this, o);
-}
-
-void Ent_PointParticles_Remove(entity this)
-{
- if(this.noise)
- strunzone(this.noise);
- this.noise = string_null;
- if(this.bgmscript)
- strunzone(this.bgmscript);
- this.bgmscript = string_null;
- if(this.mdl)
- strunzone(this.mdl);
- this.mdl = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_POINTPARTICLES, bool isnew)
-{
- float i;
- vector v;
- int f = ReadByte();
- if(f & 2)
- {
- i = ReadCoord(); // density (<0: point, >0: volume)
- if(i && !this.impulse && (this.cnt || this.mdl)) // this.cnt check is so it only happens if the ent already existed
- this.just_toggled = 1;
- this.impulse = i;
- }
- if(f & 4)
- {
- this.origin = ReadVector();
- }
- if(f & 1)
- {
- this.modelindex = ReadShort();
- if(f & 0x80)
- {
- if(this.modelindex)
- {
- this.mins = ReadVector();
- this.maxs = ReadVector();
- }
- else
- {
- this.mins = '0 0 0';
- this.maxs = ReadVector();
- }
- }
- else
- {
- this.mins = this.maxs = '0 0 0';
- }
-
- this.cnt = ReadShort(); // effect number
- this.mdl = strzone(ReadString()); // effect string
-
- if(f & 0x20)
- {
- this.velocity = decompressShortVector(ReadShort());
- this.movedir = decompressShortVector(ReadShort());
- }
- else
- {
- this.velocity = this.movedir = '0 0 0';
- }
- if(f & 0x40)
- {
- this.waterlevel = ReadShort() / 16.0;
- this.count = ReadByte() / 16.0;
- }
- else
- {
- this.waterlevel = 0;
- this.count = 1;
- }
- if(this.noise)
- strunzone(this.noise);
- if(this.bgmscript)
- strunzone(this.bgmscript);
- this.noise = strzone(ReadString());
- if(this.noise != "")
- {
- this.atten = ReadByte() / 64.0;
- this.volume = ReadByte() / 255.0;
- }
- this.bgmscript = strzone(ReadString());
- if(this.bgmscript != "")
- {
- this.bgmscriptattack = ReadByte() / 64.0;
- this.bgmscriptdecay = ReadByte() / 64.0;
- this.bgmscriptsustain = ReadByte() / 255.0;
- this.bgmscriptrelease = ReadByte() / 64.0;
- }
- BGMScript_InitEntity(this);
- }
-
- return = true;
-
- if(f & 2)
- {
- this.absolute = (this.impulse >= 0);
- if(!this.absolute)
- {
- v = this.maxs - this.mins;
- this.impulse *= -v.x * v.y * v.z / 262144; // relative: particles per 64^3 cube
- }
- }
-
- if(f & 0x10)
- this.absolute = 2;
-
- setorigin(this, this.origin);
- setsize(this, this.mins, this.maxs);
- this.solid = SOLID_NOT;
- this.draw = Draw_PointParticles;
- if (isnew) IL_PUSH(g_drawables, this);
- this.entremove = Ent_PointParticles_Remove;
-}
-#endif
+++ /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)
-{
- vector myorg = this.origin + this.mins;
- vector mysize = this.maxs - this.mins;
- WriteHeader(MSG_ENTITY, ENT_CLIENT_RAINSNOW);
- WriteByte(MSG_ENTITY, this.state);
- WriteVector(MSG_ENTITY, myorg);
- WriteVector(MSG_ENTITY, mysize);
- WriteShort(MSG_ENTITY, compressShortVector(this.dest));
- WriteShort(MSG_ENTITY, this.count);
- WriteByte(MSG_ENTITY, this.cnt);
- return true;
-}
-
-/*QUAKED spawnfunc_func_rain (0 .5 .8) ?
-This is an invisible area like a trigger, which rain falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -700', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-spawnfunc(func_rain)
-{
- this.dest = this.velocity;
- this.velocity = '0 0 0';
- if (!this.dest)
- this.dest = '0 0 -700';
- this.angles = '0 0 0';
- set_movetype(this, MOVETYPE_NONE);
- this.solid = SOLID_NOT;
- SetBrushEntityModel(this);
- if (!this.cnt)
- this.cnt = 12;
- if (!this.count)
- this.count = 2000;
- this.count = 0.01 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
- if (this.count < 1)
- this.count = 1;
- if(this.count > 65535)
- this.count = 65535;
-
- this.state = 1; // 1 is rain, 0 is snow
- this.Version = 1;
-
- Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
-}
-
-
-/*QUAKED spawnfunc_func_snow (0 .5 .8) ?
-This is an invisible area like a trigger, which snow falls inside of.
-
-Keys:
-"velocity"
- falling direction (should be something like '0 0 -300', use the X and Y velocity for wind)
-"cnt"
- sets color of rain (default 12 - white)
-"count"
- adjusts density, this many particles fall every second for a 1024x1024 area, default is 2000
-*/
-spawnfunc(func_snow)
-{
- this.dest = this.velocity;
- this.velocity = '0 0 0';
- if (!this.dest)
- this.dest = '0 0 -300';
- this.angles = '0 0 0';
- set_movetype(this, MOVETYPE_NONE);
- this.solid = SOLID_NOT;
- SetBrushEntityModel(this);
- if (!this.cnt)
- this.cnt = 12;
- if (!this.count)
- this.count = 2000;
- this.count = 0.01 * this.count * (this.size_x / 1024) * (this.size_y / 1024);
- if (this.count < 1)
- this.count = 1;
- if(this.count > 65535)
- this.count = 65535;
-
- this.state = 0; // 1 is rain, 0 is snow
- this.Version = 1;
-
- Net_LinkEntity(this, false, 0, rainsnow_SendEntity);
-}
-#elif defined(CSQC)
-float autocvar_cl_rainsnow_maxdrawdist = 2048;
-
-void Draw_Rain(entity this)
-{
- vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
- maxdist.z = 5;
- if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
- //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
- te_particlerain(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
-}
-
-void Draw_Snow(entity this)
-{
- vector maxdist = '1 1 0' * autocvar_cl_rainsnow_maxdrawdist;
- maxdist.z = 5;
- if(boxesoverlap(vec2(view_origin) - maxdist, vec2(view_origin) + maxdist, vec2(this.absmin) - '0 0 5', vec2(this.absmax) + '0 0 5'))
- //if(autocvar_cl_rainsnow_maxdrawdist <= 0 || vdist(vec2(this.origin) - vec2(this.absmin + this.absmax * 0.5), <=, autocvar_cl_rainsnow_maxdrawdist))
- te_particlesnow(this.origin + this.mins, this.origin + this.maxs, this.velocity, floor(this.count * drawframetime + random()), this.glow_color);
-}
-
-NET_HANDLE(ENT_CLIENT_RAINSNOW, bool isnew)
-{
- this.impulse = ReadByte(); // Rain, Snow, or Whatever
- this.origin = ReadVector();
- this.maxs = ReadVector();
- this.velocity = decompressShortVector(ReadShort());
- this.count = ReadShort() * 10;
- this.glow_color = ReadByte(); // color
-
- return = true;
-
- this.mins = -0.5 * this.maxs;
- this.maxs = 0.5 * this.maxs;
- this.origin = this.origin - this.mins;
-
- setorigin(this, this.origin);
- setsize(this, this.mins, this.maxs);
- this.solid = SOLID_NOT;
- if (isnew) IL_PUSH(g_drawables, this);
- if(this.impulse)
- this.draw = Draw_Rain;
- else
- this.draw = Draw_Snow;
-}
-#endif
+++ /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);
-
- WriteVector(MSG_ENTITY, this.pos1);
- WriteVector(MSG_ENTITY, this.pos2);
-
- WriteVector(MSG_ENTITY, this.size);
-
- WriteVector(MSG_ENTITY, this.view_ofs);
-
- WriteAngle(MSG_ENTITY, this.mangle_x);
- WriteAngle(MSG_ENTITY, this.mangle_y);
- WriteAngle(MSG_ENTITY, this.mangle_z);
-
- WriteShort(MSG_ENTITY, this.speed);
- WriteShort(MSG_ENTITY, this.height);
- WriteByte(MSG_ENTITY, this.lip);
- WriteByte(MSG_ENTITY, this.state);
- WriteByte(MSG_ENTITY, this.wait);
-
- WriteShort(MSG_ENTITY, this.dmg);
- WriteByte(MSG_ENTITY, this.dmgtime);
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- // used on client
- }
-
- return true;
-}
-
-void train_link(entity this)
-{
- //Net_LinkEntity(this, 0, false, train_send);
-}
-
-void train_use(entity this, entity actor, entity trigger)
-{
- this.nextthink = this.ltime + 1;
- setthink(this, train_next);
- this.use = func_null; // not again
- if(trigger.target2 && trigger.target2 != "")
- this.future_target = find(NULL, targetname, trigger.target2);
-}
-
-void func_train_find(entity this)
-{
- entity targ = train_next_find(this);
- this.target = targ.target;
- this.target_random = targ.target_random;
- // save the future target for later
- this.future_target = train_next_find(targ);
- if (this.target == "")
- objerror(this, "func_train_find: no next target");
- setorigin(this, targ.origin - this.view_ofs);
-
- if(!(this.spawnflags & 4))
- {
- this.nextthink = this.ltime + 1;
- setthink(this, train_next);
- }
-
- train_link(this);
-}
-
-#endif
-
-/*QUAKED spawnfunc_func_train (0 .5 .8) ?
-Ridable platform, targets spawnfunc_path_corner path to follow.
-speed : speed the train moves (can be overridden by each spawnfunc_path_corner)
-target : targetname of first spawnfunc_path_corner (starts here)
-*/
-#ifdef SVQC
-spawnfunc(func_train)
-{
- if (this.noise != "")
- precache_sound(this.noise);
-
- if (this.target == "")
- objerror(this, "func_train without a target");
- if (!this.speed)
- this.speed = 100;
-
- if (!InitMovingBrushTrigger(this))
- return;
- this.effects |= EF_LOWPRECISION;
-
- if(this.spawnflags & 4)
- this.use = train_use;
-
- if (this.spawnflags & 2)
- {
- this.platmovetype_turn = true;
- this.view_ofs = '0 0 0'; // don't offset a rotating train, origin works differently now
- }
- else
- this.view_ofs = this.mins;
-
- // wait for targets to spawn
- InitializeEntity(this, func_train_find, INITPRIO_FINDTARGET);
-
- setblocked(this, generic_plat_blocked);
- if(this.dmg && (this.message == ""))
- this.message = " was squished";
- if(this.dmg && (this.message2 == ""))
- this.message2 = "was squished by";
- if(this.dmg && (!this.dmgtime))
- this.dmgtime = 0.25;
- this.dmgtime2 = time;
-
- if(!set_platmovetype(this, this.platmovetype))
- return;
- this.platmovetype_start_default = this.platmovetype_start;
- this.platmovetype_end_default = this.platmovetype_end;
-
- // TODO make a reset function for this one
-}
-#elif defined(CSQC)
-void train_draw(entity this)
-{
- //Movetype_Physics_NoMatchServer();
- Movetype_Physics_MatchServer(this, autocvar_cl_projectiles_sloppy);
-}
-
-NET_HANDLE(ENT_CLIENT_TRAIN, bool isnew)
-{
- float sf = ReadByte();
-
- if(sf & SF_TRIGGER_INIT)
- {
- this.platmovetype = strzone(ReadString());
- this.platmovetype_turn = ReadByte();
- this.spawnflags = ReadByte();
-
- this.model = strzone(ReadString());
- _setmodel(this, this.model);
-
- trigger_common_read(this, true);
-
- this.curvetarget = strzone(ReadString());
-
- this.pos1 = ReadVector();
- this.pos2 = ReadVector();
-
- this.size = ReadVector();
-
- this.view_ofs = ReadVector();
-
- this.mangle_x = ReadAngle();
- this.mangle_y = ReadAngle();
- this.mangle_z = ReadAngle();
-
- this.speed = ReadShort();
- this.height = ReadShort();
- this.lip = ReadByte();
- this.state = ReadByte();
- this.wait = ReadByte();
-
- this.dmg = ReadShort();
- this.dmgtime = ReadByte();
-
- this.classname = "func_train";
- this.solid = SOLID_BSP;
- set_movetype(this, MOVETYPE_PUSH);
- this.drawmask = MASK_NORMAL;
- this.draw = train_draw;
- if (isnew) IL_PUSH(g_drawables, this);
- this.entremove = trigger_remove_generic;
-
- if(set_platmovetype(this, this.platmovetype))
- {
- this.platmovetype_start_default = this.platmovetype_start;
- this.platmovetype_end_default = this.platmovetype_end;
- }
-
- // everything is set up by the time the train is linked, we shouldn't need this
- //func_train_find();
-
- // but we will need these
- train_next(this);
-
- set_movetype(this, MOVETYPE_PUSH);
- this.move_time = time;
- }
-
- if(sf & SF_TRIGGER_RESET)
- {
- // TODO: make a reset function for trains
- }
-
- return true;
-}
-
-#endif
+++ /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);
-
- WriteVector(MSG_ENTITY, this.origin);
-
- WriteString(MSG_ENTITY, this.target);
- WriteString(MSG_ENTITY, this.target2);
- WriteString(MSG_ENTITY, this.target3);
- WriteString(MSG_ENTITY, this.target4);
- WriteString(MSG_ENTITY, this.targetname);
- WriteByte(MSG_ENTITY, this.target_random);
-
- WriteByte(MSG_ENTITY, this.wait);
-
- return true;
-}
-
-void corner_link(entity this)
-{
- //Net_LinkEntity(this, false, 0, corner_send);
-}
-
-spawnfunc(path_corner)
-{
- // setup values for overriding train movement
- // if a second value does not exist, both start and end speeds are the single value specified
- set_platmovetype(this, this.platmovetype);
-
- corner_link(this);
-}
-#elif defined(CSQC)
-
-void corner_remove(entity this)
-{
- if(this.target) { strunzone(this.target); }
- this.target = string_null;
-
- if(this.target2) { strunzone(this.target2); }
- this.target2 = string_null;
-
- if(this.target3) { strunzone(this.target3); }
- this.target3 = string_null;
-
- if(this.target4) { strunzone(this.target4); }
- this.target4 = string_null;
-
- if(this.targetname) { strunzone(this.targetname); }
- this.targetname = string_null;
-
- if(this.platmovetype) { strunzone(this.platmovetype); }
- this.platmovetype = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_CORNER, bool isnew)
-{
- this.platmovetype = strzone(ReadString());
-
- this.origin = ReadVector();
- setorigin(this, this.origin);
-
- this.target = strzone(ReadString());
- this.target2 = strzone(ReadString());
- this.target3 = strzone(ReadString());
- this.target4 = strzone(ReadString());
- this.targetname = strzone(ReadString());
- this.target_random = ReadByte();
-
- this.wait = ReadByte();
-
- return = true;
-
- this.classname = "path_corner";
- this.drawmask = MASK_NORMAL;
- this.entremove = corner_remove;
-
- set_platmovetype(this, this.platmovetype);
-}
-
-#endif
+++ /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, DMG_NOWEP, hitloc, '0 0 0');
- }
-}
-
-bool laser_SendEntity(entity this, entity to, float fl)
-{
- WriteHeader(MSG_ENTITY, ENT_CLIENT_LASER);
- fl = fl - (fl & 0xF0); // use that bit to indicate finite length laser
- if(this.spawnflags & 2)
- fl |= 0x80;
- if(this.alpha)
- fl |= 0x40;
- if(this.scale != 1 || this.modelscale != 1)
- fl |= 0x20;
- if(this.spawnflags & 4)
- fl |= 0x10;
- WriteByte(MSG_ENTITY, fl);
- if(fl & 1)
- {
- WriteVector(MSG_ENTITY, this.origin);
- }
- if(fl & 8)
- {
- WriteByte(MSG_ENTITY, this.colormod_x * 255.0);
- WriteByte(MSG_ENTITY, this.colormod_y * 255.0);
- WriteByte(MSG_ENTITY, this.colormod_z * 255.0);
- if(fl & 0x40)
- WriteByte(MSG_ENTITY, this.alpha * 255.0);
- if(fl & 0x20)
- {
- WriteByte(MSG_ENTITY, bound(0, this.scale * 16.0, 255));
- WriteByte(MSG_ENTITY, bound(0, this.modelscale * 16.0, 255));
- }
- if((fl & 0x80) || !(fl & 0x10)) // effect doesn't need sending if the laser is infinite and has collision testing turned off
- WriteShort(MSG_ENTITY, this.cnt + 1);
- }
- if(fl & 2)
- {
- if(fl & 0x80)
- {
- WriteVector(MSG_ENTITY, this.enemy.origin);
- }
- else
- {
- WriteAngle(MSG_ENTITY, this.mangle_x);
- WriteAngle(MSG_ENTITY, this.mangle_y);
- }
- }
- if(fl & 4)
- WriteByte(MSG_ENTITY, this.state);
- return 1;
-}
-
-/*QUAKED spawnfunc_misc_laser (.5 .5 .5) ? START_ON DEST_IS_FIXED
-Any object touching the beam will be hurt
-Keys:
-"target"
- spawnfunc_target_position where the laser ends
-"mdl"
- name of beam end effect to use
-"colormod"
- color of the beam (default: red)
-"dmg"
- damage per second (-1 for a laser that kills immediately)
-*/
-void laser_use(entity this, entity actor, entity trigger)
-{
- this.state = !this.state;
- this.SendFlags |= 4;
- misc_laser_aim(this);
-}
-
-void laser_reset(entity this)
-{
- if(this.spawnflags & 1)
- this.state = 1;
- else
- this.state = 0;
-}
-
-spawnfunc(misc_laser)
-{
- if(this.mdl)
- {
- if(this.mdl == "none")
- this.cnt = -1;
- else
- {
- this.cnt = _particleeffectnum(this.mdl);
- if(this.cnt < 0 && this.dmg)
- this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
- }
- }
- else if(!this.cnt)
- {
- if(this.dmg)
- this.cnt = particleeffectnum(EFFECT_LASER_DEADLY);
- else
- this.cnt = -1;
- }
- if(this.cnt < 0)
- this.cnt = -1;
-
- if(this.colormod == '0 0 0')
- if(!this.alpha)
- this.colormod = '1 0 0';
- if(this.message == "") this.message = "saw the light";
- if (this.message2 == "") this.message2 = "was pushed into a laser by";
- if(!this.scale) this.scale = 1;
- if(!this.modelscale) this.modelscale = 1;
- else if(this.modelscale < 0) this.modelscale = 0;
- setthink(this, misc_laser_think);
- this.nextthink = time;
- InitializeEntity(this, misc_laser_init, INITPRIO_FINDTARGET);
-
- this.mangle = this.angles;
-
- Net_LinkEntity(this, false, 0, laser_SendEntity);
-
- IFTARGETED
- {
- this.reset = laser_reset;
- this.reset(this);
- this.use = laser_use;
- }
- else
- this.state = 1;
-}
-#elif defined(CSQC)
-
-// a laser goes from origin in direction angles
-// it has color 'colormod'
-// and stops when something is in the way
-entityclass(Laser);
-class(Laser) .int cnt; // end effect
-class(Laser) .vector colormod;
-class(Laser) .int state; // on-off
-class(Laser) .int count; // flags for the laser
-class(Laser) .vector velocity;
-class(Laser) .float alpha;
-class(Laser) .float scale; // scaling factor of the thickness
-class(Laser) .float modelscale; // scaling factor of the dlight
-
-void Draw_Laser(entity this)
-{
- if(!this.state)
- return;
- InterpolateOrigin_Do(this);
- if(this.count & 0x80)
- {
- if(this.count & 0x10)
- {
- trace_endpos = this.velocity;
- trace_dphitq3surfaceflags = 0;
- }
- else
- traceline(this.origin, this.velocity, 0, this);
- }
- else
- {
- if(this.count & 0x10)
- {
- makevectors(this.angles);
- trace_endpos = this.origin + v_forward * 1048576;
- trace_dphitq3surfaceflags = Q3SURFACEFLAG_SKY;
- }
- else
- {
- makevectors(this.angles);
- traceline(this.origin, this.origin + v_forward * 32768, 0, this);
- if(trace_dphitq3surfaceflags & Q3SURFACEFLAG_SKY)
- trace_endpos = this.origin + v_forward * 1048576;
- }
- }
- if(this.scale != 0)
- {
- if(this.alpha)
- {
- Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, this.alpha, DRAWFLAG_NORMAL, view_origin);
- }
- else
- {
- Draw_CylindricLine(this.origin, trace_endpos, this.scale, "particles/laserbeam", 0, time * 3, this.colormod, 0.5, DRAWFLAG_ADDITIVE, view_origin);
- }
- }
- if (!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
- {
- if(this.cnt >= 0)
- __pointparticles(this.cnt, trace_endpos, trace_plane_normal, drawframetime * 1000);
- if(this.colormod != '0 0 0' && this.modelscale != 0)
- adddynamiclight(trace_endpos + trace_plane_normal * 1, this.modelscale, this.colormod * 5);
- }
-}
-
-NET_HANDLE(ENT_CLIENT_LASER, bool isnew)
-{
- InterpolateOrigin_Undo(this);
-
- // 30 bytes, or 13 bytes for just moving
- int f = ReadByte();
- this.count = (f & 0xF0);
-
- if(this.count & 0x80)
- this.iflags = IFLAG_VELOCITY | IFLAG_ORIGIN;
- else
- this.iflags = IFLAG_ANGLES | IFLAG_ORIGIN;
-
- if(f & 1)
- {
- this.origin = ReadVector();
- setorigin(this, this.origin);
- }
- if(f & 8)
- {
- this.colormod_x = ReadByte() / 255.0;
- this.colormod_y = ReadByte() / 255.0;
- this.colormod_z = ReadByte() / 255.0;
- if(f & 0x40)
- this.alpha = ReadByte() / 255.0;
- else
- this.alpha = 0;
- this.scale = 2;
- this.modelscale = 50;
- if(f & 0x20)
- {
- this.scale *= ReadByte() / 16.0; // beam radius
- this.modelscale *= ReadByte() / 16.0; // dlight radius
- }
- if((f & 0x80) || !(f & 0x10))
- this.cnt = ReadShort() - 1; // effect number
- else
- this.cnt = 0;
- }
- if(f & 2)
- {
- if(f & 0x80)
- {
- this.velocity = ReadVector();
- }
- else
- {
- this.angles_x = ReadAngle();
- this.angles_y = ReadAngle();
- }
- }
- if(f & 4)
- this.state = ReadByte();
-
- return = true;
-
- InterpolateOrigin_Note(this);
- this.draw = Draw_Laser;
- if (isnew) IL_PUSH(g_drawables, this);
-}
-#endif
+++ /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);
- WriteVector(MSG_ENTITY, this.origin);
-
- WriteAngle(MSG_ENTITY, this.mangle_x);
- WriteAngle(MSG_ENTITY, this.mangle_y);
- WriteAngle(MSG_ENTITY, this.mangle_z);
- }
-
- return true;
-}
-
-void teleport_dest_link(entity this)
-{
- Net_LinkEntity(this, false, 0, teleport_dest_send);
- this.SendFlags |= 1; // update
-}
-
-spawnfunc(info_teleport_destination)
-{
- this.classname = "info_teleport_destination";
-
- this.mangle = this.angles;
- this.angles = '0 0 0';
-
- //setorigin(this, this.origin + '0 0 27'); // To fix a mappers' habit as old as Quake
- setorigin(this, this.origin);
-
- IFTARGETED
- {
- }
- else
- objerror (this, "^3Teleport destination without a targetname");
-
- teleport_dest_link(this);
-}
-
-spawnfunc(misc_teleporter_dest)
-{
- spawnfunc_info_teleport_destination(this);
-}
-
-#elif defined(CSQC)
-
-void teleport_dest_remove(entity this)
-{
- //if(this.classname)
- //strunzone(this.classname);
- //this.classname = string_null;
-
- if(this.targetname)
- strunzone(this.targetname);
- this.targetname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TELEPORT_DEST, bool isnew)
-{
- int sf = ReadByte();
-
- if(sf & 1)
- {
- this.classname = "info_teleport_destination";
- this.cnt = ReadByte();
- this.speed = ReadCoord();
- this.targetname = strzone(ReadString());
- this.origin = ReadVector();
-
- this.mangle_x = ReadAngle();
- this.mangle_y = ReadAngle();
- this.mangle_z = ReadAngle();
-
- setorigin(this, this.origin);
-
- this.drawmask = MASK_NORMAL;
- this.entremove = teleport_dest_remove;
- }
-
- return = true;
-}
-
-#endif
+++ /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, DMG_NOWEP, blocker.origin, '0 0 0');
- this.dmgtime2 = time + this.dmgtime;
- }
-
- // Gib dead/dying stuff
- if(IS_DEAD(blocker))
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
- }
-#endif
-}
-
-void plat_spawn_inside_trigger(entity this)
-{
- entity trigger;
- vector tmin, tmax;
-
- trigger = spawn();
- settouch(trigger, plat_center_touch);
- set_movetype(trigger, MOVETYPE_NONE);
- trigger.solid = SOLID_TRIGGER;
- trigger.enemy = this;
-
- tmin = this.absmin + '25 25 0';
- tmax = this.absmax - '25 25 -8';
- tmin_z = tmax_z - (this.pos1_z - this.pos2_z + 8);
- if (this.spawnflags & PLAT_LOW_TRIGGER)
- tmax_z = tmin_z + 8;
-
- if (this.size_x <= 50)
- {
- tmin_x = (this.mins_x + this.maxs_x) / 2;
- tmax_x = tmin_x + 1;
- }
- if (this.size_y <= 50)
- {
- tmin_y = (this.mins_y + this.maxs_y) / 2;
- tmax_y = tmin_y + 1;
- }
-
- if(tmin_x < tmax_x)
- if(tmin_y < tmax_y)
- if(tmin_z < tmax_z)
- {
- setsize (trigger, tmin, tmax);
- return;
- }
-
- // otherwise, something is fishy...
- delete(trigger);
- objerror(this, "plat_spawn_inside_trigger: platform has odd size or lip, can't spawn");
-}
-
-void plat_hit_top(entity this)
-{
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = 1;
-
- setthink(this, plat_go_down);
- this.nextthink = this.ltime + 3;
-}
-
-void plat_hit_bottom(entity this)
-{
- _sound (this, CH_TRIGGER_SINGLE, this.noise1, VOL_BASE, ATTEN_NORM);
- this.state = 2;
-}
-
-void plat_go_down(entity this)
-{
- _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
- this.state = 3;
- SUB_CalcMove (this, this.pos2, TSPEED_LINEAR, this.speed, plat_hit_bottom);
-}
-
-void plat_go_up(entity this)
-{
- _sound (this, CH_TRIGGER_SINGLE, this.noise, VOL_BASE, ATTEN_NORM);
- this.state = 4;
- SUB_CalcMove (this, this.pos1, TSPEED_LINEAR, this.speed, plat_hit_top);
-}
-
-void plat_center_touch(entity this, entity toucher)
-{
-#ifdef SVQC
- if (!toucher.iscreature)
- return;
-
- if (toucher.health <= 0)
- return;
-#elif defined(CSQC)
- if (!IS_PLAYER(toucher))
- return;
- if(IS_DEAD(toucher))
- return;
-#endif
-
- if (this.enemy.state == 2) {
- plat_go_up(this.enemy);
- } else if (this.enemy.state == 1)
- this.enemy.nextthink = this.enemy.ltime + 1;
-}
-
-void plat_outside_touch(entity this, entity toucher)
-{
-#ifdef SVQC
- if (!toucher.iscreature)
- return;
-
- if (toucher.health <= 0)
- return;
-#elif defined(CSQC)
- if (!IS_PLAYER(toucher))
- return;
-#endif
-
- if (this.enemy.state == 1) {
- entity e = this.enemy;
- plat_go_down(e);
- }
-}
-
-void plat_trigger_use(entity this, entity actor, entity trigger)
-{
- if (getthink(this))
- return; // already activated
- plat_go_down(this);
-}
-
-
-void plat_crush(entity this, entity blocker)
-{
- if((this.spawnflags & 4) && (blocker.takedamage != DAMAGE_NO))
- { // KIll Kill Kill!!
-#ifdef SVQC
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
-#endif
- }
- else
- {
-#ifdef SVQC
- if((this.dmg) && (blocker.takedamage != DAMAGE_NO))
- { // Shall we bite?
- Damage (blocker, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
- // Gib dead/dying stuff
- if(IS_DEAD(blocker))
- Damage (blocker, this, this, 10000, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, blocker.origin, '0 0 0');
- }
-#endif
-
- if (this.state == 4)
- plat_go_down (this);
- else if (this.state == 3)
- plat_go_up (this);
- // when in other states, then the plat_crush event came delayed after
- // plat state already had changed
- // this isn't a bug per se!
- }
-}
-
-void plat_use(entity this, entity actor, entity trigger)
-{
- this.use = func_null;
- if (this.state != 4)
- objerror (this, "plat_use: not in up state");
- plat_go_down(this);
-}
-
-.string sound1, sound2;
-
-void plat_reset(entity this)
-{
- IFTARGETED
- {
- setorigin(this, this.pos1);
- this.state = 4;
- this.use = plat_use;
- }
- else
- {
- setorigin(this, this.pos2);
- this.state = 2;
- this.use = plat_trigger_use;
- }
-
-#ifdef SVQC
- this.SendFlags |= SF_TRIGGER_RESET;
-#endif
-}
-
-.float platmovetype_start_default, platmovetype_end_default;
-bool set_platmovetype(entity e, string s)
-{
- // sets platmovetype_start and platmovetype_end based on a string consisting of two values
-
- int n = tokenize_console(s);
- if(n > 0)
- e.platmovetype_start = stof(argv(0));
- else
- e.platmovetype_start = 0;
-
- if(n > 1)
- e.platmovetype_end = stof(argv(1));
- else
- e.platmovetype_end = e.platmovetype_start;
-
- if(n > 2)
- if(argv(2) == "force")
- return true; // no checking, return immediately
-
- if(!cubic_speedfunc_is_sane(e.platmovetype_start, e.platmovetype_end))
- {
- objerror(e, "Invalid platform move type; platform would go in reverse, which is not allowed.");
- return false;
- }
-
- return true;
-}
+++ /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/spawnpoint.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/spawnpoint.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 "spawnpoint.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, 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.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)
- {
- WriteVector(MSG_ENTITY, this.origin);
- }
- if(sf & 1)
- {
- if(this.model != "null")
- {
- WriteShort(MSG_ENTITY, this.modelindex);
- WriteVector(MSG_ENTITY, this.mins);
- WriteVector(MSG_ENTITY, this.maxs);
- }
- else
- {
- WriteShort(MSG_ENTITY, 0);
- WriteVector(MSG_ENTITY, this.maxs);
- }
- WriteByte(MSG_ENTITY, this.volume * 255.0);
- WriteByte(MSG_ENTITY, this.fade_time * 16.0);
- WriteByte(MSG_ENTITY, this.fade_rate * 16.0);
- WriteString(MSG_ENTITY, this.noise);
- }
- return 1;
-}
-void trigger_music_reset(entity this)
-{
- this.cnt = !(this.spawnflags & 1);
- this.SendFlags |= 0x80;
-}
-void trigger_music_use(entity this, entity actor, entity trigger)
-{
- this.cnt = !this.cnt;
- this.SendFlags |= 0x80;
-}
-spawnfunc(trigger_music)
-{
- if(this.model != "") _setmodel(this, this.model);
- if(!this.volume) this.volume = 1;
- if(!this.modelindex)
- {
- setorigin(this, this.origin + this.mins);
- setsize(this, '0 0 0', this.maxs - this.mins);
- }
- trigger_music_reset(this);
-
- this.use = trigger_music_use;
- this.reset = trigger_music_reset;
-
- Net_LinkEntity(this, false, 0, trigger_music_SendEntity);
-}
-#elif defined(CSQC)
-
-entity TargetMusic_list;
-STATIC_INIT(TargetMusic_list)
-{
- TargetMusic_list = LL_NEW();
-}
-
-void TargetMusic_Advance()
-{
- // run AFTER all the thinks!
- entity best = music_default;
- if (music_target && time < music_target.lifetime) best = music_target;
- if (music_trigger) best = music_trigger;
- LL_EACH(TargetMusic_list, it.noise, {
- const float vol0 = (getsoundtime(it, CH_BGM_SINGLE) >= 0) ? it.lastvol : -1;
- if (it == best)
- {
- // increase volume
- it.state = (it.fade_time > 0) ? bound(0, it.state + frametime / it.fade_time, 1) : 1;
- }
- else
- {
- // decrease volume
- it.state = (it.fade_rate > 0) ? bound(0, it.state - frametime / it.fade_rate, 1) : 0;
- }
- const float vol = it.state * it.volume * autocvar_bgmvolume;
- if (vol != vol0)
- {
- if(vol0 < 0)
- _sound(it, CH_BGM_SINGLE, it.noise, vol, ATTEN_NONE); // restart
- else
- _sound(it, CH_BGM_SINGLE, "", vol, ATTEN_NONE);
- it.lastvol = vol;
- }
- });
- music_trigger = NULL;
- bgmtime = (best) ? getsoundtime(best, CH_BGM_SINGLE) : gettime(GETTIME_CDTRACK);
-}
-
-NET_HANDLE(TE_CSQC_TARGET_MUSIC, bool isNew)
-{
- Net_TargetMusic();
- return true;
-}
-
-void Net_TargetMusic()
-{
- const int id = ReadShort();
- const float vol = ReadByte() / 255.0;
- const float fai = ReadByte() / 16.0;
- const float fao = ReadByte() / 16.0;
- const float tim = ReadByte();
- const string noi = ReadString();
-
- entity e = NULL;
- LL_EACH(TargetMusic_list, it.count == id, { e = it; break; });
- if (!e)
- {
- LL_PUSH(TargetMusic_list, e = new_pure(TargetMusic));
- e.count = id;
- }
- if(e.noise != noi)
- {
- if(e.noise)
- strunzone(e.noise);
- e.noise = strzone(noi);
- precache_sound(e.noise);
- _sound(e, CH_BGM_SINGLE, e.noise, 0, ATTEN_NONE);
- if(getsoundtime(e, CH_BGM_SINGLE) < 0)
- {
- LOG_TRACEF("Cannot initialize sound %s", e.noise);
- strunzone(e.noise);
- e.noise = string_null;
- }
- }
- e.volume = vol;
- e.fade_time = fai;
- e.fade_rate = fao;
- if(vol > 0)
- {
- if(tim == 0)
- {
- music_default = e;
- if(!music_disabled)
- {
- e.state = 2;
- cvar_settemp("music_playlist_index", "-1"); // don't use playlists
- localcmd("cd stop\n"); // just in case
- music_disabled = 1;
- }
- }
- else
- {
- music_target = e;
- e.lifetime = time + tim;
- }
- }
-}
-
-void Ent_TriggerMusic_Think(entity this)
-{
- if(WarpZoneLib_BoxTouchesBrush(view_origin, view_origin, this, NULL))
- {
- music_trigger = this;
- }
- this.nextthink = time;
-}
-
-void Ent_TriggerMusic_Remove(entity this)
-{
- if(this.noise)
- strunzone(this.noise);
- this.noise = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TRIGGER_MUSIC, bool isnew)
-{
- int f = ReadByte();
- if(f & 4)
- {
- this.origin = ReadVector();
- }
- if(f & 1)
- {
- this.modelindex = ReadShort();
- if(this.modelindex)
- {
- this.mins = ReadVector();
- this.maxs = ReadVector();
- }
- else
- {
- this.mins = '0 0 0';
- this.maxs = ReadVector();
- }
-
- this.volume = ReadByte() / 255.0;
- this.fade_time = ReadByte() / 16.0;
- this.fade_rate = ReadByte() / 16.0;
- string s = this.noise;
- if(this.noise)
- strunzone(this.noise);
- this.noise = strzone(ReadString());
- if(this.noise != s)
- {
- precache_sound(this.noise);
- _sound(this, CH_BGM_SINGLE, this.noise, 0, ATTEN_NONE);
- if(getsoundtime(this, CH_BGM_SINGLE) < 0)
- {
- LOG_TRACEF("Cannot initialize sound %s", this.noise);
- strunzone(this.noise);
- this.noise = string_null;
- }
- }
- }
-
- setorigin(this, this.origin);
- setsize(this, this.mins, this.maxs);
- this.cnt = 1;
- setthink(this, Ent_TriggerMusic_Think);
- this.nextthink = time;
- return true;
-}
-
-#endif
+++ /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 "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 & 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, 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
-
-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, DMG_NOWEP, toucher.origin, '0 0 0');
- }
- }
- else if(toucher.damagedbytriggers)
- {
- if(toucher.takedamage)
- {
- EXACTTRIGGER_TOUCH(this, toucher);
- Damage(toucher, this, this, this.dmg, DEATH_HURTTRIGGER.m_id, DMG_NOWEP, toucher.origin, '0 0 0');
- }
- }
-
- return;
-}
-
-/*QUAKED spawnfunc_trigger_hurt (.5 .5 .5) ?
-Any object touching this will be hurt
-set dmg to damage amount
-defalt dmg = 5
-*/
-.entity trigger_hurt_next;
-entity trigger_hurt_last;
-entity trigger_hurt_first;
-spawnfunc(trigger_hurt)
-{
- EXACTTRIGGER_INIT;
- this.active = ACTIVE_ACTIVE;
- settouch(this, trigger_hurt_touch);
- this.use = trigger_hurt_use;
- this.enemy = world; // I hate you all
- if (!this.dmg)
- this.dmg = 1000;
- if (this.message == "")
- this.message = "was in the wrong place";
- if (this.message2 == "")
- this.message2 = "was thrown into a world of hurt by";
- // this.message = "someone like %s always gets wrongplaced";
-
- if(!trigger_hurt_first)
- trigger_hurt_first = this;
- if(trigger_hurt_last)
- trigger_hurt_last.trigger_hurt_next = this;
- trigger_hurt_last = this;
-}
-
-float tracebox_hits_trigger_hurt(vector start, vector mi, vector ma, vector end)
-{
- entity th;
-
- for(th = trigger_hurt_first; th; th = th.trigger_hurt_next)
- if(tracebox_hits_box(start, mi, ma, end, th.absmin, th.absmax))
- return true;
-
- return false;
-}
-#endif
+++ /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);
-
- WriteVector(MSG_ENTITY, this.movedir);
-
- trigger_common_write(this, true);
-
- return true;
-}
-
-void trigger_push_updatelink(entity this)
-{
- this.SendFlags |= 1;
-}
-
-void trigger_push_link(entity this)
-{
- trigger_link(this, trigger_push_send);
-}
-
-/*
- * ENTITY PARAMETERS:
- *
- * target: target of jump
- * height: the absolute value is the height of the highest point of the jump
- * trajectory above the higher one of the player and the target.
- * the sign indicates whether the highest point is INSIDE (positive)
- * or OUTSIDE (negative) of the jump trajectory. General rule: use
- * positive values for targets mounted on the floor, and use negative
- * values to target a point on the ceiling.
- * movedir: if target is not set, this * speed * 10 is the velocity to be reached.
- */
-spawnfunc(trigger_push)
-{
- SetMovedir(this);
-
- trigger_init(this);
-
- this.active = ACTIVE_ACTIVE;
- this.use = trigger_push_use;
- settouch(this, trigger_push_touch);
-
- // normal push setup
- if (!this.speed)
- this.speed = 1000;
- this.movedir = this.movedir * this.speed * 10;
-
- if (!this.noise)
- this.noise = "misc/jumppad.wav";
- precache_sound (this.noise);
-
- trigger_push_link(this); // link it now
-
- IL_PUSH(g_jumppads, this);
-
- // this must be called to spawn the teleport waypoints for bots
- InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
-}
-
-
-bool target_push_send(entity this, entity to, float sf)
-{
- WriteHeader(MSG_ENTITY, ENT_CLIENT_TARGET_PUSH);
-
- WriteByte(MSG_ENTITY, this.cnt);
- WriteString(MSG_ENTITY, this.targetname);
- WriteVector(MSG_ENTITY, this.origin);
-
- WriteAngle(MSG_ENTITY, this.angles_x);
- WriteAngle(MSG_ENTITY, this.angles_y);
- WriteAngle(MSG_ENTITY, this.angles_z);
-
- return true;
-}
-
-void target_push_use(entity this, entity actor, entity trigger)
-{
- if(trigger.classname == "trigger_push" || trigger == this)
- return; // WTF, why is this a thing
-
- jumppad_push(this, actor);
-}
-
-void target_push_link(entity this)
-{
- BITSET_ASSIGN(this.effects, EF_NODEPTHTEST);
- Net_LinkEntity(this, false, 0, target_push_send);
- //this.SendFlags |= 1; // update
-}
-
-void target_push_init(entity this)
-{
- this.mangle = this.angles;
- setorigin(this, this.origin);
- target_push_link(this);
-}
-
-void target_push_init2(entity this)
-{
- if(this.target && this.target != "") // we have an old style pusher!
- {
- InitializeEntity(this, trigger_push_findtarget, INITPRIO_FINDTARGET);
- this.use = target_push_use;
- }
-
- target_push_init(this); // normal push target behaviour can be combined with a legacy pusher?
-}
-
-spawnfunc(target_push) { target_push_init2(this); }
-spawnfunc(info_notnull) { target_push_init(this); }
-spawnfunc(target_position) { target_push_init(this); }
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_TRIGGER_PUSH, bool isnew)
-{
- this.classname = "jumppad";
- int mytm = ReadByte(); if(mytm) { this.team = mytm - 1; }
- this.spawnflags = ReadInt24_t();
- this.active = ReadByte();
- this.height = ReadCoord();
-
- this.movedir = ReadVector();
-
- trigger_common_read(this, true);
-
- this.entremove = trigger_remove_generic;
- this.solid = SOLID_TRIGGER;
- settouch(this, trigger_push_touch);
- this.move_time = time;
- defer(this, 0.25, trigger_push_findtarget);
-
- return true;
-}
-
-void target_push_remove(entity this)
-{
- //if(this.classname)
- //strunzone(this.classname);
- //this.classname = string_null;
-
- if(this.targetname)
- strunzone(this.targetname);
- this.targetname = string_null;
-}
-
-NET_HANDLE(ENT_CLIENT_TARGET_PUSH, bool isnew)
-{
- this.classname = "push_target";
- this.cnt = ReadByte();
- this.targetname = strzone(ReadString());
- this.origin = ReadVector();
-
- this.angles_x = ReadAngle();
- this.angles_y = ReadAngle();
- this.angles_z = ReadAngle();
-
- return = true;
-
- setorigin(this, this.origin);
-
- this.drawmask = MASK_NORMAL;
- this.entremove = target_push_remove;
-}
-#endif
+++ /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, .entity weaponentity, vector hitloc, vector force)
-{
- if(!this.takedamage)
- return;
- if(this.spawnflags & DOOR_NOSPLASH)
- if(!(DEATH_ISSPECIAL(deathtype)) && (deathtype & HITTYPE_SPLASH))
- return;
- if(this.team)
- if(((this.spawnflags & 4) == 0) == (this.team != attacker.team))
- return;
- this.health = this.health - damage;
- if (this.health <= 0)
- {
- this.enemy = attacker;
- this.goalentity = inflictor;
- multi_trigger(this);
- }
-}
-
-void multi_reset(entity this)
-{
- if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
- settouch(this, multi_touch);
- if (this.max_health)
- {
- this.health = this.max_health;
- this.takedamage = DAMAGE_YES;
- this.solid = SOLID_BBOX;
- }
- setthink(this, func_null);
- this.nextthink = 0;
- this.team = this.team_saved;
-}
-
-/*QUAKED spawnfunc_trigger_multiple (.5 .5 .5) ? notouch
-Variable sized repeatable trigger. Must be targeted at one or more entities. If "health" is set, the trigger must be killed to activate each time.
-If "delay" is set, the trigger waits some time after activating before firing.
-"wait" : Seconds between triggerings. (.2 default)
-If notouch is set, the trigger is only fired by other entities, not by touching.
-NOTOUCH has been obsoleted by spawnfunc_trigger_relay!
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-spawnfunc(trigger_multiple)
-{
- this.reset = multi_reset;
- if (this.sounds == 1)
- this.noise = "misc/secret.wav";
- else if (this.sounds == 2)
- this.noise = strzone(SND(TALK));
- else if (this.sounds == 3)
- this.noise = "misc/trigger1.wav";
-
- if(this.noise)
- precache_sound(this.noise);
-
- if (!this.wait)
- this.wait = 0.2;
- else if(this.wait < -1)
- this.wait = 0;
- this.use = multi_use;
-
- EXACTTRIGGER_INIT;
-
- this.team_saved = this.team;
- IL_PUSH(g_saved_team, this);
-
- if (this.health)
- {
- if (this.spawnflags & SPAWNFLAG_NOTOUCH)
- objerror (this, "health and notouch don't make sense\n");
- this.canteamdamage = true;
- this.max_health = this.health;
- this.event_damage = multi_eventdamage;
- this.takedamage = DAMAGE_YES;
- this.solid = SOLID_BBOX;
- setorigin(this, this.origin); // make sure it links into the world
- }
- else
- {
- if ( !(this.spawnflags & SPAWNFLAG_NOTOUCH) )
- {
- settouch(this, multi_touch);
- setorigin(this, this.origin); // make sure it links into the world
- }
- }
-}
-
-
-/*QUAKED spawnfunc_trigger_once (.5 .5 .5) ? notouch
-Variable sized trigger. Triggers once, then removes itself. You must set the key "target" to the name of another object in the level that has a matching
-"targetname". If "health" is set, the trigger must be killed to activate.
-If notouch is set, the trigger is only fired by other entities, not by touching.
-if "killtarget" is set, any objects that have a matching "target" will be removed when the trigger is fired.
-if "angle" is set, the trigger will only fire when someone is facing the direction of the angle. Use "360" for an angle of 0.
-sounds
-1) secret
-2) beep beep
-3) large switch
-4)
-set "message" to text string
-*/
-spawnfunc(trigger_once)
-{
- this.wait = -1;
- spawnfunc_trigger_multiple(this);
-}
-#endif
+++ /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
-
-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");
- 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)
-{
- // TODO: use global stats!
- STAT(SECRETS_TOTAL, this) = secrets_total;
- STAT(SECRETS_FOUND, this) = secrets_found;
-}
-
-/**
- * A secret has been found (maybe :P)
- */
-void trigger_secret_touch(entity this, entity toucher)
-{
- // only a player can trigger this
- if (!IS_PLAYER(toucher))
- return;
-
- // update secrets found counter
- secrets_found += 1;
- //print("Secret found: ", ftos(secret_counter.cnt), "/");
- //print(ftos(secret_counter.count), "\n");
-
- // centerprint message (multi_touch() doesn't always call centerprint())
- centerprint(toucher, this.message);
- this.message = "";
-
- // handle normal trigger features
- multi_touch(this, toucher);
- // we can't just delete(this) here, because this is a touch function
- // called while C code is looping through area links...
- //delete(this);
-}
-
-/*QUAKED trigger_secret (.5 .5 .5) ?
-Variable sized secret trigger. Can be targeted at one or more entities.
-Basically, it's a trigger_once (with restrictions, see notes) that additionally updates the number of secrets found.
--------- KEYS --------
-sounds: 1 to play misc/secret.wav, 2 to play misc/talk.wav, 3 to play misc/trigger1.wav (default: 1)
-noise: path to sound file, if you want to play something else
-target: trigger all entities with this targetname when triggered
-message: print this message to the player who activated the trigger instead of the standard 'You found a secret!'
-killtarget: remove all entities with this targetname when triggered
--------- NOTES --------
-You should create a common/trigger textured brush covering the entrance to a secret room/area.
-Trigger secret can only be trigger by a player's touch and can not be a target itself.
-*/
-spawnfunc(trigger_secret)
-{
- // FIXME: should it be disabled in most modes?
-
- // update secrets count
- secrets_total += 1;
-
- // add default message
- if (this.message == "")
- this.message = "You found a secret!";
-
- // set default sound
- if (this.noise == "")
- if (!this.sounds)
- this.sounds = 1; // misc/secret.wav
-
- // this entity can't be a target itself!!!!
- this.targetname = "";
-
- // you can't just shoot a room to find it, can you?
- this.health = 0;
-
- // a secret can not be delayed
- this.delay = 0;
-
- // convert this trigger to trigger_once
- //this.classname = "trigger_once";
- spawnfunc_trigger_once(this);
-
- // take over the touch() function, so we can mark secret as found
- settouch(this, trigger_secret_touch);
- // ignore triggering;
- this.use = func_null;
-}
-#endif
+++ /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 (!?)
-.entity swampslug;
-
-#ifdef SVQC
-spawnfunc(trigger_swamp);
-#endif
-void swamp_touch(entity this, entity toucher);
-void swampslug_think(entity this);
-
-
-/*
-* Uses a entity calld swampslug to handle players in the swamp
-* It works like this: When the plyer enters teh swamp the spawnfunc_trigger_swamp
-* attaches a new "swampslug" to the player. As long as the plyer is inside
-* the swamp the swamp gives the slug new health. But the slug slowly kills itself
-* so when the player goes outside the swamp, it dies and releases the player from the
-* swamps curses (dmg/slowdown)
-*
-* I do it this way becuz there is no "untouch" event.
-*/
-void swampslug_think(entity this)
-{
- //Slowly kill the slug
- this.health = this.health - 1;
-
- //Slug dead? then remove curses.
- if(this.health <= 0)
- {
- this.owner.in_swamp = 0;
- delete(this);
- //centerprint(this.owner,"Killing slug...\n");
- return;
- }
-
- // Slug still alive, so we are still in the swamp
- // Or we have exited it very recently.
- // Do the damage and renew the timer.
-#ifdef SVQC
- Damage (this.owner, this, this, this.dmg, DEATH_SWAMP.m_id, DMG_NOWEP, this.owner.origin, '0 0 0');
-#endif
-
- this.nextthink = time + this.swamp_interval;
-}
-
-void swamp_touch(entity this, entity toucher)
-{
- // If whatever thats touching the swamp is not a player
- // or if its a dead player, just dont care abt it.
- if(!IS_PLAYER(toucher) || IS_DEAD(toucher))
- return;
-
- EXACTTRIGGER_TOUCH(this, toucher);
-
- // Chech if player alredy got a swampslug.
- if(toucher.in_swamp != 1)
- {
- // If not attach one.
- //centerprint(toucher,"Entering swamp!\n");
- toucher.swampslug = spawn();
- toucher.swampslug.health = 2;
- setthink(toucher.swampslug, swampslug_think);
- toucher.swampslug.nextthink = time;
- toucher.swampslug.owner = toucher;
- toucher.swampslug.dmg = this.dmg;
- toucher.swampslug.swamp_interval = this.swamp_interval;
- toucher.swamp_slowdown = this.swamp_slowdown;
- toucher.in_swamp = 1;
- return;
- }
-
- //toucher.in_swamp = 1;
-
- //Revitalize players swampslug
- toucher.swampslug.health = 2;
-}
-
-REGISTER_NET_LINKED(ENT_CLIENT_SWAMP)
-
-#ifdef SVQC
-float swamp_send(entity this, entity to, float sf)
-{
- WriteHeader(MSG_ENTITY, ENT_CLIENT_SWAMP);
-
- WriteByte(MSG_ENTITY, this.dmg); // can probably get away with using a single byte here
- WriteByte(MSG_ENTITY, this.swamp_slowdown);
- WriteByte(MSG_ENTITY, this.swamp_interval);
-
- trigger_common_write(this, false);
-
- return true;
-}
-
-void swamp_link(entity this)
-{
- trigger_link(this, swamp_send);
-}
-
-/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
-Players gettin into the swamp will
-get slowd down and damaged
-*/
-spawnfunc(trigger_swamp)
-{
- // Init stuff
- trigger_init(this);
- settouch(this, swamp_touch);
-
- // Setup default keys, if missing
- if(this.dmg <= 0)
- this.dmg = 5;
- if(this.swamp_interval <= 0)
- this.swamp_interval = 1;
- if(this.swamp_slowdown <= 0)
- this.swamp_slowdown = 0.5;
-
- swamp_link(this);
-}
-
-#elif defined(CSQC)
-
-NET_HANDLE(ENT_CLIENT_SWAMP, bool isnew)
-{
- this.dmg = ReadByte();
- this.swamp_slowdown = ReadByte();
- this.swamp_interval = ReadByte();
-
- trigger_common_read(this, false);
-
- return = true;
-
- this.classname = "trigger_swamp";
- this.solid = SOLID_TRIGGER;
- settouch(this, swamp_touch);
- this.drawmask = MASK_NORMAL;
- this.move_time = time;
- this.entremove = trigger_remove_generic;
-}
-#endif
+++ /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(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
-
-.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);
- if(this.movedir != '0 0 0')
- BITSET_ASSIGN(f, 8);
- if(this.angles != '0 0 0')
- BITSET_ASSIGN(f, 16);
- WriteByte(MSG_ENTITY, f);
-
- if(withtarget)
- {
- // probably some way to clean this up...
- int targbits = 0;
- if(this.target && this.target != "") targbits |= BIT(0);
- if(this.target2 && this.target2 != "") targbits |= BIT(1);
- if(this.target3 && this.target3 != "") targbits |= BIT(2);
- if(this.target4 && this.target4 != "") targbits |= BIT(3);
- if(this.targetname && this.targetname != "") targbits |= BIT(4);
- if(this.killtarget && this.killtarget != "") targbits |= BIT(5);
-
- WriteByte(MSG_ENTITY, targbits);
-
- if(targbits & BIT(0))
- WriteString(MSG_ENTITY, this.target);
- if(targbits & BIT(1))
- WriteString(MSG_ENTITY, this.target2);
- if(targbits & BIT(2))
- WriteString(MSG_ENTITY, this.target3);
- if(targbits & BIT(3))
- WriteString(MSG_ENTITY, this.target4);
- if(targbits & BIT(4))
- WriteString(MSG_ENTITY, this.targetname);
- if(targbits & BIT(5))
- WriteString(MSG_ENTITY, this.killtarget);
- }
-
- if(f & 4)
- WriteVector(MSG_ENTITY, this.origin);
-
- if(f & 8)
- WriteVector(MSG_ENTITY, this.movedir);
-
- if(f & 16)
- WriteVector(MSG_ENTITY, this.angles);
-
- WriteShort(MSG_ENTITY, this.modelindex);
- WriteVector(MSG_ENTITY, this.mins);
- WriteVector(MSG_ENTITY, this.maxs);
- WriteByte(MSG_ENTITY, bound(1, this.scale * 16, 255));
-}
-
-#elif defined(CSQC)
-
-void trigger_common_read(entity this, bool withtarget)
-{
- int f = ReadByte();
- this.warpzone_isboxy = (f & 1);
-
- if(withtarget)
- {
- if(this.target) { strunzone(this.target); }
- if(this.target2) { strunzone(this.target2); }
- if(this.target3) { strunzone(this.target3); }
- if(this.target4) { strunzone(this.target4); }
- if(this.targetname) { strunzone(this.targetname); }
- if(this.killtarget) { strunzone(this.killtarget); }
-
- int targbits = ReadByte();
-
- #define X(xs,b) MACRO_BEGIN { \
- if(targbits & BIT(b)) \
- xs = strzone(ReadString()); \
- else \
- xs = string_null; \
- } MACRO_END
-
- X(this.target, 0);
- X(this.target2, 1);
- X(this.target3, 2);
- X(this.target4, 3);
- X(this.targetname, 4);
- X(this.killtarget, 5);
- #undef X
- }
-
- if(f & 4)
- this.origin = ReadVector();
- else
- this.origin = '0 0 0';
- setorigin(this, this.origin);
-
- if(f & 8)
- this.movedir = ReadVector();
- else
- this.movedir = '0 0 0';
-
- if(f & 16)
- this.angles = ReadVector();
- else
- this.angles = '0 0 0';
-
- this.modelindex = ReadShort();
- this.mins = ReadVector();
- this.maxs = ReadVector();
- this.scale = ReadByte() / 16;
- setsize(this, this.mins, this.maxs);
-}
-
-void trigger_remove_generic(entity this)
-{
- if(this.target) { strunzone(this.target); }
- this.target = string_null;
-
- if(this.target2) { strunzone(this.target2); }
- this.target2 = string_null;
-
- if(this.target3) { strunzone(this.target3); }
- this.target3 = string_null;
-
- if(this.target4) { strunzone(this.target4); }
- this.target4 = string_null;
-
- if(this.targetname) { strunzone(this.targetname); }
- this.target = string_null;
-
- if(this.killtarget) { strunzone(this.killtarget); }
- this.killtarget = string_null;
-}
-#endif
-
-
-/*
-==============================
-SUB_UseTargets
-
-the global "activator" should be set to the entity that initiated the firing.
-
-If this.delay is set, a DelayedUse entity will be created that will actually
-do the SUB_UseTargets after that many seconds have passed.
-
-Centerprints any this.message to the activator.
-
-Removes all entities with a targetname that match this.killtarget,
-and removes them, so some events can remove other triggers.
-
-Search for (string)targetname in all entities that
-match (string)this.target and call their .use function
-
-==============================
-*/
-
-void SUB_UseTargets_Ex(entity this, entity actor, entity trigger, bool preventReuse)
-{
-//
-// check for a delay
-//
- if (this.delay)
- {
- // create a temp object to fire at a later time
- entity t = new(DelayedUse);
- t.nextthink = time + this.delay;
- setthink(t, DelayThink);
- t.enemy = actor;
- t.message = this.message;
- t.killtarget = this.killtarget;
- t.target = this.target;
- t.target2 = this.target2;
- t.target3 = this.target3;
- t.target4 = this.target4;
- t.antiwall_flag = this.antiwall_flag;
- return;
- }
-
- string s;
-
-//
-// print the message
-//
-#ifdef SVQC
- if(this)
- if(IS_PLAYER(actor) && this.message != "")
- if(IS_REAL_CLIENT(actor))
- {
- centerprint(actor, this.message);
- if (this.noise == "")
- play2(actor, SND(TALK));
- }
-
-//
-// kill the killtagets
-//
- s = this.killtarget;
- if (s != "")
- {
- for(entity t = NULL; (t = find(t, targetname, s)); )
- delete(t);
- }
-#endif
-
-//
-// fire targets
-//
-
- if(this.target_random)
- RandomSelection_Init();
-
- for(int i = 0; i < 4; ++i)
- {
- switch(i)
- {
- default:
- case 0: s = this.target; break;
- case 1: s = this.target2; break;
- case 2: s = this.target3; break;
- case 3: s = this.target4; break;
- }
- if (s != "")
- {
- // Flag to set func_clientwall state
- // 1 == deactivate, 2 == activate, 0 == do nothing
- int aw_flag = this.antiwall_flag;
- for(entity t = NULL; (t = find(t, targetname, s)); )
- {
- if(t.use && (t.sub_target_used != time || !preventReuse))
- {
- if(this.target_random)
- {
- RandomSelection_AddEnt(t, 1, 0);
- }
- else
- {
- if (t.classname == "func_clientwall" || t.classname == "func_clientillusionary")
- t.antiwall_flag = aw_flag;
-
- t.use(t, actor, this);
- if(preventReuse)
- t.sub_target_used = time;
- }
- }
- }
- }
- }
-
- if(this.target_random && RandomSelection_chosen_ent)
- {
- RandomSelection_chosen_ent.use(RandomSelection_chosen_ent, actor, this);
- if(preventReuse)
- RandomSelection_chosen_ent.sub_target_used = time;
- }
-}
-
-void SUB_UseTargets(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, false); }
-void SUB_UseTargets_PreventReuse(entity this, entity actor, entity trigger) { SUB_UseTargets_Ex(this, actor, trigger, true); }
+++ /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
#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");
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);
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)
{
#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)
{
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
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(); }
#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)
}
}
+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)
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)
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 */
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);
#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;
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_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;
}
if(a)
f *= a;
- float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius),
+ float totaldamage = RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(crylink, isprimary, damage) * f, WEP_CVAR_BOTH(crylink, isprimary, edgedamage) * f, WEP_CVAR_BOTH(crylink, isprimary, radius),
NULL, NULL, WEP_CVAR_BOTH(crylink, isprimary, force) * f, this.projectiledeathtype, this.weaponentity_fld, toucher);
if(totaldamage && ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 2) || ((WEP_CVAR_BOTH(crylink, isprimary, linkexplode) == 1) && !W_Crylink_Touch_WouldHitFriendly(this, WEP_CVAR_BOTH(crylink, isprimary, radius)))))
.entity queuenext;
.entity queueprev;
+
+void W_Crylink_Dequeue(entity e);
#endif
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
/* 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");
PROJECTILE_MAKETRIGGER(proj);
proj.projectiledeathtype = WEP_FIREBALL.m_id;
proj.weaponentity_fld = weaponentity;
- proj.weaponentity_fld = weaponentity;
setorigin(proj, w_shotorg);
set_movetype(proj, MOVETYPE_FLY);
isprimary = !(this.projectiledeathtype & HITTYPE_SECONDARY);
- RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius),
+ RadiusDamage(this, this.realowner, WEP_CVAR_BOTH(hlac, isprimary, damage), WEP_CVAR_BOTH(hlac, isprimary, edgedamage), WEP_CVAR_BOTH(hlac, isprimary, radius),
NULL, NULL, WEP_CVAR_BOTH(hlac, isprimary, force), this.projectiledeathtype, this.weaponentity_fld, toucher);
delete(this);
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(this.move_movetype == MOVETYPE_NONE || this.move_movetype == MOVETYPE_FOLLOW)
this.velocity = this.mine_orientation; // particle fx and decals need .velocity
- RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius),
+ RadiusDamage(this, this.realowner, WEP_CVAR(minelayer, remote_damage), WEP_CVAR(minelayer, remote_edgedamage), WEP_CVAR(minelayer, remote_radius),
NULL, NULL, WEP_CVAR(minelayer, remote_force), this.projectiledeathtype | HITTYPE_BOUNCE, this.weaponentity_fld, NULL);
.entity weaponentity = this.weaponentity_fld;
/* 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);
.float porto_v_angle_held;
.vector right_vector;
.float porto_forbidden;
+
+void W_Porto_Fail(entity this, float failhard);
#endif
}
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))
{
/* 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");
#ifdef SVQC
-void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary)
+void W_Shotgun_Attack(Weapon thiswep, entity actor, .entity weaponentity, float isprimary, float ammocount, float damage, float bullets, float spread, float solidpenetration, float force)
{
- W_DecreaseAmmo(thiswep, actor, WEP_CVAR_PRI(shotgun, ammo), weaponentity);
+ W_DecreaseAmmo(thiswep, actor, ammocount, weaponentity);
- W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), WEP_CVAR_PRI(shotgun, damage) * WEP_CVAR_PRI(shotgun, bullets), WEP_SHOTGUN.m_id);
- for(int sc = 0;sc < WEP_CVAR_PRI(shotgun, bullets);sc = sc + 1)
- fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR_PRI(shotgun, spread), WEP_CVAR_PRI(shotgun, solidpenetration), WEP_CVAR_PRI(shotgun, damage), WEP_CVAR_PRI(shotgun, force), WEP_SHOTGUN.m_id, 0);
+ W_SetupShot(actor, weaponentity, true, 5, SND_SHOTGUN_FIRE, ((isprimary) ? CH_WEAPON_A : CH_WEAPON_SINGLE), damage * bullets, WEP_SHOTGUN.m_id);
+ for(int sc = 0;sc < bullets;sc = sc + 1)
+ fireBullet(actor, weaponentity, w_shotorg, w_shotdir, spread, solidpenetration, damage, force, WEP_SHOTGUN.m_id, 0);
- Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, WEP_CVAR_PRI(shotgun, ammo));
+
+ Send_Effect(EFFECT_SHOTGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, ammocount);
// casing code
if(autocvar_g_casings >= 1)
}
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);
}
#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
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(!(trace_dphitq3surfaceflags & (Q3SURFACEFLAG_SKY | Q3SURFACEFLAG_NOIMPACT)))
W_RocketMinsta_Explosion(actor, weaponentity, trace_endpos);
- W_DecreaseAmmo(thiswep, actor, ((g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)), weaponentity);
+ W_DecreaseAmmo(thiswep, actor, ((autocvar_g_instagib) ? 1 : WEP_CVAR_PRI(vaporizer, ammo)), weaponentity);
}
void W_RocketMinsta_Laser_Explode (entity this, entity directhitentity)
}
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);
}
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) \
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, WEP_VORTEX.m_id);
+ W_SetupShot(actor, weaponentity, true, 5, SND_NEXFIRE, CH_WEAPON_A, mydmg, dtype);
if(charge > WEP_CVAR(vortex, charge_animlimit) && WEP_CVAR(vortex, charge_animlimit)) // if the Vortex is overcharged, we play an extra sound
{
sound(actor, CH_WEAPON_B, SND_NEXCHARGE, VOL_BASE * (charge - 0.5 * WEP_CVAR(vortex, charge_animlimit)) / (1 - 0.5 * WEP_CVAR(vortex, charge_animlimit)), ATTN_NORM);
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);
/* 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) \
{ WriteByte(chan, this.vortex_charge * 255); }, \
{ (viewmodels[this.m_wepent_slot]).vortex_charge = ReadByte() / 255; }) \
\
+ PROP(false, oknex_charge, WEPENT_SET_NORMAL, \
+ { WriteByte(chan, this.oknex_charge * 16); }, \
+ { (viewmodels[this.m_wepent_slot]).oknex_charge = ReadByte() / 16; }) \
+ \
PROP(false, m_gunalign, WEPENT_SET_NORMAL, \
{ WriteByte(chan, this.m_gunalign); }, \
{ (viewmodels[this.m_wepent_slot]).m_gunalign = ReadByte(); }) \
{ WriteByte(chan, this.vortex_chargepool_ammo * 16); }, \
{ (viewmodels[this.m_wepent_slot]).vortex_chargepool_ammo = ReadByte() / 16; }) \
\
- PROP(false, clip_load, WEPENT_SET_NORMAL, \
+ PROP(false, oknex_chargepool_ammo, WEPENT_SET_NORMAL, \
+ { WriteByte(chan, this.oknex_chargepool_ammo * 16); }, \
+ { (viewmodels[this.m_wepent_slot]).oknex_chargepool_ammo = ReadByte() / 16; }) \
+ \
+ PROP(false, clip_load, WEPENT_SET_NORMAL, \
{ WriteShort(chan, this.clip_load); }, \
{ (viewmodels[this.m_wepent_slot]).clip_load = ReadShort(); }) \
\
.float vortex_charge;
.float vortex_chargepool_ammo;
+.float oknex_charge;
+.float oknex_chargepool_ammo;
.int tuba_instrument;
.int minelayer_mines;
.float arc_heat_percent;
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)) {
LABEL(end)
if (IS_ONGROUND(this)) { this.lastground = time; }
// conveyors: then break velocity again
- if (this.conveyor.state) { this.velocity += this.conveyor.movedir; }
+ if (this.conveyor.active) { this.velocity += this.conveyor.movedir; }
this.lastflags = this.flags;
this.lastclassname = this.classname;
{
WarpZone_PlayerPhysics_FixVAngle(this);
Physics_UpdateStats(this);
+ PM_ClientMovement_UpdateStatus(this);
}
bool sys_phys_override(entity this, float dt)
#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
// 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, 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;
}
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>
#include "../menu.qh"
#include "../item.qh"
-#include "../mutators/events.qh"
+#include <menu/mutators/_mod.qh>
#include <common/command/_mod.qh>
void InputBox_setText(entity me, string txt)
{
- if (me.text) strunzone(me.text);
+ strfree(me.text);
SUPER(InputBox).setText(me, strzone(txt));
}
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 (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;
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);
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, ", ", _("Jet pack"));
if(cvar("g_buffs") > 0)
- s = strcat(s, ", ", _("Buffs"));
+ s = cons_mid(s, ", ", _("Buffs"));
if(cvar("g_overkill"))
- s = strcat(s, ", ", _("Overkill"));
+ s = cons_mid(s, ", ", _("Overkill"));
if(cvar("g_powerups") == 0)
- s = strcat(s, ", ", _("No powerups"));
+ s = cons_mid(s, ", ", _("No powerups"));
if(cvar("g_powerups") > 0)
- s = strcat(s, ", ", _("Powerups"));
+ s = cons_mid(s, ", ", _("Powerups"));
if(cvar("g_touchexplode") > 0)
- s = strcat(s, ", ", _("Touch explode"));
+ s = cons_mid(s, ", ", _("Touch explode"));
+ if(cvar("g_walljump"))
+ s = cons_mid(s, ", ", _("Wall jumping"));
if(s == "")
return ZCTX(_("MUT^None"));
else
- return substring(s, 2, strlen(s) - 2);
+ return s;
}
float checkCompatibility_pinata(entity me)
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"),
me.gotoRC(me, 0, 2); me.setFirstColumn(me, me.currentColumn);
me.TD(me, 1, 2, e = makeXonoticRadioButton(1, string_null, string_null, _("Regular (no arena)")));
+ string weaponarena_tooltip = strzone(_("Players will be given a set of weapons at spawn as well as unlimited ammo, without weapon pickups"));
me.TR(me);
- me.TD(me, 1, 2, e = makeXonoticRadioButton_T(1, "g_weaponarena", "menu_weaponarena", _("Weapon arenas:"),
- _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+ me.TD(me, 1, 2, makeXonoticTextLabel(0, _("Weapon arenas:")));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "menu_weaponarena", _("Custom weapons"), weaponarena_tooltip));
e.cvarValueIsAnotherCvar = true;
e.cvarOffValue = "0";
+
+ me.TDempty(me, 0.1); // fix initial position
for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
{
w = Weapons_from(i);
if(w.spawnflags & WEP_FLAG_HIDDEN)
continue;
if((j & 1) == 0)
+ me.TDempty(me, 0.2);
+ else
+ {
me.TR(me);
- me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
+ me.TDempty(me, 0.4);
+ }
+ me.TD(me, 1, 1.7, e = makeXonoticWeaponarenaCheckBox(strzone(w.netname), strzone(w.m_name)));
setDependentWeird(e, checkCompatibility_weaponarena_weapon);
++j;
}
+
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "most", _("Most weapons"),
- _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "most", _("Most weapons"), weaponarena_tooltip));
e.cvarOffValue = "0";
me.TR(me);
me.TDempty(me, 0.2);
- me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "all", _("All weapons"),
- _("Selecting a weapon arena will give all players that weapon at spawn as well as unlimited ammo, and disable all other weapon pickups.")));
+ me.TD(me, 1, 1.8, e = makeXonoticRadioButton_T(1, "g_weaponarena", "all", _("All weapons"), weaponarena_tooltip));
e.cvarOffValue = "0";
me.TR(me);
me.TD(me, 1, 4, makeXonoticTextLabel(0, _("Special arenas:")));
#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);
}
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);
}
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;
}
#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)
{
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);
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);
}
} } \
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);
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;
}
#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/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/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_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;
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;
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"
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;
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)
{
// 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"
{
if (item.health && player.health <= this.health) {return true;}
if (item.armorvalue && player.armorvalue <= this.armorvalue) {return true;}
- if (item.weapons && !(player.weapons & item.weapons)) {return true;}
- if (item.ammo_shells && player.ammo_shells <= this.ammo_shells) {return true;}
- if (item.ammo_nails && player.ammo_nails <= this.ammo_nails) {return true;}
- if (item.ammo_rockets && player.ammo_rockets <= this.ammo_rockets) {return true;}
- if (item.ammo_cells && player.ammo_cells <= this.ammo_cells) {return true;}
- if (item.ammo_plasma && player.ammo_plasma <= this.ammo_plasma) {return true;}
+ if (STAT(WEAPONS, item) && !(STAT(WEAPONS, player) & STAT(WEAPONS, item))) {return true;}
+ if (item.ammo_shells && GetResourceAmount(player, RESOURCE_SHELLS) <= GetResourceAmount(this, RESOURCE_SHELLS)) {return true;}
+ if (item.ammo_nails && GetResourceAmount(player, RESOURCE_BULLETS) <= GetResourceAmount(this, RESOURCE_BULLETS)) {return true;}
+ if (item.ammo_rockets && GetResourceAmount(player, RESOURCE_ROCKETS) <= GetResourceAmount(this, RESOURCE_ROCKETS)) {return true;}
+ if (item.ammo_cells && GetResourceAmount(player, RESOURCE_CELLS) <= GetResourceAmount(this, RESOURCE_CELLS)) {return true;}
+ if (item.ammo_plasma && GetResourceAmount(player, RESOURCE_PLASMA) <= GetResourceAmount(this, RESOURCE_PLASMA)) {return true;}
if (item.itemdef.instanceOfPowerup) {return true;}
return false;
#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)
//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))
LOG_DEBUG("jetpack ai: required fuel ", ftos(fuel), " this.ammo_fuel ", ftos(this.ammo_fuel));
// enough fuel ?
- if(this.ammo_fuel>fuel)
+ if(this.ammo_fuel>fuel || (this.items & IT_UNLIMITED_WEAPON_AMMO))
{
// Estimate cost
// (as onground costs calculation is mostly based on distances, here we do the same establishing some relationship
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) != "\'")
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;
+ SetResourceAmount(this.personal, RESOURCE_ROCKETS, GetResourceAmount(this, RESOURCE_ROCKETS));
+ SetResourceAmount(this.personal, RESOURCE_BULLETS, GetResourceAmount(this, RESOURCE_BULLETS));
+ SetResourceAmount(this.personal, RESOURCE_CELLS, GetResourceAmount(this, RESOURCE_CELLS));
+ SetResourceAmount(this.personal, RESOURCE_PLASMA, GetResourceAmount(this, RESOURCE_PLASMA));
+ SetResourceAmount(this.personal, RESOURCE_SHELLS, GetResourceAmount(this, RESOURCE_SHELLS));
+ SetResourceAmount(this.personal, RESOURCE_FUEL, GetResourceAmount(this, RESOURCE_FUEL));
this.personal.health = max(1, this.health);
this.personal.armorvalue = this.armorvalue;
- this.personal.weapons = this.weapons;
+ STAT(WEAPONS, this.personal) = STAT(WEAPONS, this);
this.personal.items = this.items;
this.personal.pauserotarmor_finished = this.pauserotarmor_finished;
this.personal.pauserothealth_finished = this.pauserothealth_finished;
MUTATOR_CALLHOOK(AbortSpeedrun, this);
}
- this.ammo_rockets = this.personal.ammo_rockets;
- this.ammo_nails = this.personal.ammo_nails;
- this.ammo_cells = this.personal.ammo_cells;
- this.ammo_plasma = this.personal.ammo_plasma;
- this.ammo_shells = this.personal.ammo_shells;
- this.ammo_fuel = this.personal.ammo_fuel;
+ SetResourceAmount(this, RESOURCE_ROCKETS, GetResourceAmount(this.personal, RESOURCE_ROCKETS));
+ SetResourceAmount(this, RESOURCE_BULLETS, GetResourceAmount(this.personal, RESOURCE_BULLETS));
+ SetResourceAmount(this, RESOURCE_CELLS, GetResourceAmount(this.personal, RESOURCE_CELLS));
+ SetResourceAmount(this, RESOURCE_PLASMA, GetResourceAmount(this.personal, RESOURCE_PLASMA));
+ SetResourceAmount(this, RESOURCE_SHELLS, GetResourceAmount(this.personal, RESOURCE_SHELLS));
+ SetResourceAmount(this, RESOURCE_FUEL, GetResourceAmount(this.personal, RESOURCE_FUEL));
this.health = this.personal.health;
this.armorvalue = this.personal.armorvalue;
- this.weapons = this.personal.weapons;
+ STAT(WEAPONS, this) = STAT(WEAPONS, this.personal);
this.items = this.personal.items;
this.pauserotarmor_finished = time + this.personal.pauserotarmor_finished - this.personal.teleport_time;
this.pauserothealth_finished = time + this.personal.pauserothealth_finished - this.personal.teleport_time;
END_CHEAT_FUNCTION();
}
-void DragBox_Think(entity this);
float drag_lastcnt;
float CheatCommand(entity this, int argc)
{
END_CHEAT_FUNCTION();
}
-float Drag(entity this, float force_allow_pick, float ischeat);
-void Drag_Begin(entity dragger, entity draggee, vector touchpoint);
-void Drag_Finish(entity dragger);
-float Drag_IsDraggable(entity draggee);
-float Drag_MayChangeAngles(entity draggee);
-void Drag_MoveForward(entity dragger);
-void Drag_SetSpeed(entity dragger, float s);
-void Drag_MoveBackward(entity dragger);
-void Drag_Update(entity dragger);
-float Drag_CanDrag(entity dragger);
-float Drag_IsDragging(entity dragger);
-void Drag_MoveDrag(entity from, entity to);
.entity dragentity;
float CheatFrame(entity this)
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 "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/triggers/target/spawnpoint.qh"
+#include "../common/mapobjects/func/conveyor.qh"
+#include "../common/mapobjects/teleporters.qh"
+#include "../common/mapobjects/target/spawnpoint.qh"
#include "../common/vehicles/all.qh"
#include "../common/net_linked.qh"
#include "../common/physics/player.qh"
+#include <common/vehicles/sv_vehicles.qh>
+
#include "../common/items/_mod.qh"
#include "../common/mutators/mutator/waypoints/all.qh"
+#include "../common/mutators/mutator/instagib/sv_instagib.qh"
+#include <common/gamemodes/_mod.qh>
-#include "../common/triggers/subs.qh"
-#include "../common/triggers/triggers.qh"
-#include "../common/triggers/trigger/secret.qh"
+#include "../common/mapobjects/subs.qh"
+#include "../common/mapobjects/triggers.qh"
+#include "../common/mapobjects/trigger/secret.qh"
#include "../common/minigames/sv_minigames.qh"
#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(this.bot_attack)
IL_REMOVE(g_bot_targets, this);
this.bot_attack = false;
+ if(this.monster_attack)
+ IL_REMOVE(g_monster_targets, this);
+ this.monster_attack = false;
STAT(HUD, this) = HUD_NORMAL;
TRANSMUTE(Observer, this);
this.iscreature = false;
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.revival_time = 0;
this.items = 0;
- this.weapons = '0 0 0';
+ STAT(WEAPONS, this) = '0 0 0';
this.drawonlytoclient = this;
this.viewloc = NULL;
this.effects = EF_TELEPORT_BIT | EF_RESTARTANIM_BIT;
if (warmup_stage) {
- this.ammo_shells = warmup_start_ammo_shells;
- this.ammo_nails = warmup_start_ammo_nails;
- this.ammo_rockets = warmup_start_ammo_rockets;
- this.ammo_cells = warmup_start_ammo_cells;
- this.ammo_plasma = warmup_start_ammo_plasma;
- this.ammo_fuel = warmup_start_ammo_fuel;
+ SetResourceAmount(this, RESOURCE_SHELLS, warmup_start_ammo_shells);
+ SetResourceAmount(this, RESOURCE_BULLETS, warmup_start_ammo_nails);
+ SetResourceAmount(this, RESOURCE_ROCKETS, warmup_start_ammo_rockets);
+ SetResourceAmount(this, RESOURCE_CELLS, warmup_start_ammo_cells);
+ SetResourceAmount(this, RESOURCE_PLASMA, warmup_start_ammo_plasma);
+ SetResourceAmount(this, RESOURCE_FUEL, warmup_start_ammo_fuel);
this.health = warmup_start_health;
this.armorvalue = warmup_start_armorvalue;
- this.weapons = WARMUP_START_WEAPONS;
+ STAT(WEAPONS, this) = WARMUP_START_WEAPONS;
} else {
- this.ammo_shells = start_ammo_shells;
- this.ammo_nails = start_ammo_nails;
- this.ammo_rockets = start_ammo_rockets;
- this.ammo_cells = start_ammo_cells;
- this.ammo_plasma = start_ammo_plasma;
- this.ammo_fuel = start_ammo_fuel;
+ SetResourceAmount(this, RESOURCE_SHELLS, start_ammo_shells);
+ SetResourceAmount(this, RESOURCE_BULLETS, start_ammo_nails);
+ SetResourceAmount(this, RESOURCE_ROCKETS, start_ammo_rockets);
+ SetResourceAmount(this, RESOURCE_CELLS, start_ammo_cells);
+ SetResourceAmount(this, RESOURCE_PLASMA, start_ammo_plasma);
+ SetResourceAmount(this, RESOURCE_FUEL, start_ammo_fuel);
this.health = start_health;
this.armorvalue = start_armorvalue;
- this.weapons = start_weapons;
+ STAT(WEAPONS, this) = start_weapons;
if (MUTATOR_CALLHOOK(ForbidRandomStartWeapons, this) == false)
{
GiveRandomWeapons(this, random_start_weapons_count,
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;
}
}
-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)
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!
- if (CS(this).weaponorder_byimpulse) strunzone(CS(this).weaponorder_byimpulse);
+ strfree(CS(this).netname_previous); // needs to be before the CS entity is removed!
+ strfree(CS(this).weaponorder_byimpulse);
ClientState_detach(this);
Portal_ClearAll(this);
bot_relinkplayerlist();
- if (this.clientstatus) strunzone(this.clientstatus);
+ 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
PS(this) = PS(spectatee);
this.armortype = spectatee.armortype;
this.armorvalue = spectatee.armorvalue;
- this.ammo_cells = spectatee.ammo_cells;
+ this.ammo_cells = spectatee.ammo_cells; // TODO: these will be a part of inventory, so no need to worry about setting them later!
this.ammo_plasma = spectatee.ammo_plasma;
this.ammo_shells = spectatee.ammo_shells;
this.ammo_nails = spectatee.ammo_nails;
this.invincible_finished = spectatee.invincible_finished;
this.superweapons_finished = spectatee.superweapons_finished;
STAT(PRESSED_KEYS, this) = STAT(PRESSED_KEYS, spectatee);
- this.weapons = spectatee.weapons;
+ STAT(WEAPONS, this) = STAT(WEAPONS, spectatee);
this.punchangle = spectatee.punchangle;
this.view_ofs = spectatee.view_ofs;
this.velocity = spectatee.velocity;
}
}
+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;
}
return false;
}
- bool have_hook = false;
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
- if(this.(weaponentity).hook.state)
- {
- have_hook = true;
- break;
- }
- }
- bool do_crouch = PHYS_INPUT_BUTTON_CROUCH(this);
- if (have_hook) {
- do_crouch = false;
- } else if (this.waterlevel >= WATERLEVEL_SWIMMING) {
- do_crouch = false;
- } else if (this.vehicle) {
- do_crouch = false;
- } else if (STAT(FROZEN, this)) {
- do_crouch = false;
- }
-
- if (do_crouch) {
- if (!this.crouch) {
- this.crouch = true;
- this.view_ofs = STAT(PL_CROUCH_VIEW_OFS, this);
- setsize(this, STAT(PL_CROUCH_MIN, this), STAT(PL_CROUCH_MAX, this));
- // setanim(this, this.anim_duck, false, true, true); // this anim is BROKEN anyway
- }
- } else if (this.crouch) {
- tracebox(this.origin, STAT(PL_MIN, this), STAT(PL_MAX, this), this.origin, false, this);
- if (!trace_startsolid) {
- this.crouch = false;
- this.view_ofs = STAT(PL_VIEW_OFS, this);
- setsize(this, STAT(PL_MIN, this), STAT(PL_MAX, this));
- }
- }
-
FixPlayermodel(this);
if (this.shootfromfixedorigin != autocvar_g_shootfromfixedorigin) {
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
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);
}
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_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 (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);
#include <common/command/_mod.qh>
#include "../g_world.qh"
-#include "../g_subs.qh"
#include <common/util.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)
{
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;
}
}
#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;
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":
void ReadyCount();
void ReadyRestart_force();
void VoteCount(float first_count);
+void Nagger_Init();
#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
//***********************
SetResourceAmount(actor, RESOURCE_PLASMA, start_ammo_plasma);
SetResourceAmount(actor, RESOURCE_FUEL, start_ammo_fuel);
- actor.weapons = start_weapons;
+ STAT(WEAPONS, actor) = start_weapons;
if (this.spawnflags & 32)
{
// TODO
#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;
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;
// 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 vortex_charge;
.float vortex_charge_rottime;
.float vortex_chargepool_ammo;
+.float oknex_charge;
+.float oknex_charge_rottime;
+.float oknex_chargepool_ammo;
.int hagar_load;
.int grab; // 0 = can't grab, 1 = owner can grab, 2 = owner and team mates can grab, 3 = anyone can grab
.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(targ, DEATHS, 1);
- if(targ != attacker) // not for suicides
- if(g_weaponarena_random)
- {
- // after a frag, exchange the current weapon (or the culprit, if detectable) by a new random weapon
- Weapon culprit = DEATH_WEAPONOF(deathtype);
- if(!culprit) culprit = attacker.(weaponentity).m_weapon;
- else if(!(attacker.weapons & (culprit.m_wepset))) culprit = attacker.(weaponentity).m_weapon;
-
- if(g_weaponarena_random_with_blaster && culprit == WEP_BLASTER) // WEAPONTODO: Shouldn't this be in a mutator?
- {
- // no exchange
- }
- else
- {
- if(!GiveFrags_randomweapons)
- {
- GiveFrags_randomweapons = new(GiveFrags_randomweapons);
- }
-
- if(warmup_stage)
- GiveFrags_randomweapons.weapons = WARMUP_START_WEAPONS;
- else
- GiveFrags_randomweapons.weapons = start_weapons;
-
- // all others (including the culprit): remove
- GiveFrags_randomweapons.weapons &= ~attacker.weapons;
- GiveFrags_randomweapons.weapons &= ~(culprit.m_wepset);
-
- // among the remaining ones, choose one by random
- W_RandomWeapons(GiveFrags_randomweapons, 1);
-
- if(GiveFrags_randomweapons.weapons)
- {
- attacker.weapons |= GiveFrags_randomweapons.weapons;
- attacker.weapons &= ~(culprit.m_wepset);
- }
- }
-
- // after a frag, choose another random weapon set
- if (!(attacker.weapons & WepSet_FromWeapon(attacker.(weaponentity).m_weapon)))
- W_SwitchWeapon_Force(attacker, w_getbestweapon(attacker, weaponentity), weaponentity);
- }
-
// FIXME fix the mess this is (we have REAL points now!)
- if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f))
+ if(MUTATOR_CALLHOOK(GiveFragsForKill, attacker, targ, f, deathtype, attacker.(weaponentity)))
f = M_ARGV(2, float);
attacker.totalfrags += f;
return MUTATOR_CALLHOOK(FragCenterMessage, attacker, targ, deathtype, kill_count_to_attacker, kill_count_to_target);
}
-entity buff_FirstFromFlags(int _buffs);
void Obituary(entity attacker, entity inflictor, entity targ, int deathtype, .entity weaponentity)
{
// Sanity check
}
// 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);
}
}
- if(!g_instagib)
+ if(!MUTATOR_IS_ENABLED(mutator_instagib))
{
// apply strength multiplier
if (attacker.items & ITEM_Strength.m_itemid)
}
}
-float RadiusDamageForSource(entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe,
float inflictorselfdamage, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
// Returns total damage applies to creatures
{
#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, .entity weaponentity);
string AppendItemcodes(string s, entity player);
RemoveHook(this);
}
-void GrapplingHookThink(entity this);
void GrapplingHook_Stop(entity this)
{
Send_Effect(EFFECT_HOOK_IMPACT, this.origin, '0 0 0', 1);
// 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))
- {
- 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)
+++ /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");
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 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
}
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]);
}
}
#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 "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(CS(this).weaponorder_byimpulse)
- {
- strunzone(CS(this).weaponorder_byimpulse);
- CS(this).weaponorder_byimpulse = string_null;
- }
- CS(this).weaponorder_byimpulse = strzone(W_FixWeaponOrder_BuildImpulseList(o));
+ string o = W_FixWeaponOrder_ForceComplete(wo);
+ strcpy(CS(this).weaponorder_byimpulse, W_FixWeaponOrder_BuildImpulseList(o));
return o;
}
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
#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");
// 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 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) \
/** 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)
+};
+++ /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;
+++ /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)
-{
- // 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;
-}
+++ /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), {
- STAT(REDALIVE, it) = redalive;
- STAT(BLUEALIVE, it) = bluealive;
- STAT(YELLOWALIVE, it) = yellowalive;
- STAT(PINKALIVE, it) = pinkalive;
- });
-}
-
-float CA_GetWinnerTeam()
-{
- float winner_team = 0;
- if(redalive >= 1)
- winner_team = NUM_TEAM_1;
- if(bluealive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
- }
- if(yellowalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
- }
- if(pinkalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
- return winner_team;
- return -1; // no player left
-}
-
-void nades_Clear(entity player);
-
-#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
-float CA_CheckWinner()
-{
- if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
- FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
-
- allowed_to_spawn = false;
- game_stopped = true;
- round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
- return 1;
- }
-
- CA_count_alive_players();
- if(CA_ALIVE_TEAMS() > 1)
- return 0;
-
- int winner_team = CA_GetWinnerTeam();
- if(winner_team > 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
- TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1);
- }
- else if(winner_team == -1)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
- }
-
- allowed_to_spawn = false;
- game_stopped = true;
- round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-
- FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
-
- return 1;
-}
-
-void CA_RoundStart()
-{
- allowed_to_spawn = boolean(warmup_stage);
-}
-
-bool CA_CheckTeams()
-{
- static int prev_missing_teams_mask;
- allowed_to_spawn = true;
- CA_count_alive_players();
- if(CA_ALIVE_TEAMS_OK())
- {
- if(prev_missing_teams_mask > 0)
- Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
- prev_missing_teams_mask = -1;
- return true;
- }
- if(total_players == 0)
- {
- if(prev_missing_teams_mask > 0)
- Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
- prev_missing_teams_mask = -1;
- return false;
- }
- int missing_teams_mask = 0;
- if(ca_teams & BIT(0))
- missing_teams_mask += (!redalive) * 1;
- if(ca_teams & BIT(1))
- missing_teams_mask += (!bluealive) * 2;
- if(ca_teams & BIT(2))
- missing_teams_mask += (!yellowalive) * 4;
- if(ca_teams & BIT(3))
- missing_teams_mask += (!pinkalive) * 8;
- if(prev_missing_teams_mask != missing_teams_mask)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
- prev_missing_teams_mask = missing_teams_mask;
- }
- return false;
-}
-
-bool ca_isEliminated(entity e)
-{
- if(e.caplayer == 1 && (IS_DEAD(e) || e.frags == FRAGS_LMS_LOSER))
- return true;
- if(e.caplayer == 0.5)
- return true;
- return false;
-}
-
-/** Returns next available player to spectate if g_ca_spectate_enemies == 0 */
-entity CA_SpectateNext(entity player, entity start)
-{
- if (SAME_TEAM(start, player)) return start;
- // continue from current player
- for (entity e = start; (e = find(e, classname, STR_PLAYER)); )
- {
- if (SAME_TEAM(player, e)) return e;
- }
- // restart from begining
- for (entity e = NULL; (e = find(e, classname, STR_PLAYER)); )
- {
- if (SAME_TEAM(player, e)) return e;
- }
- return start;
-}
-
-
-MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- player.caplayer = 1;
- if (!warmup_stage)
- eliminatedPlayers.SendFlags |= 1;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ForbidSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- // spectators / observers that weren't playing can join; they are
- // immediately forced to observe in the PutClientInServer hook
- // this way they are put in a team and can play in the next round
- if (!allowed_to_spawn && player.caplayer)
- return true;
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
-{
- entity player = M_ARGV(0, entity);
-
- if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
- {
- TRANSMUTE(Observer, player);
- if (CS(player).jointime != time && !player.caplayer) // not when connecting
- {
- player.caplayer = 0.5;
- Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ca, reset_map_players)
-{
- FOREACH_CLIENT(true, {
- CS(it).killcount = 0;
- if (!it.caplayer && IS_BOT_CLIENT(it))
- {
- it.team = -1;
- it.caplayer = 1;
- }
- if (it.caplayer)
- {
- TRANSMUTE(Player, it);
- it.caplayer = 1;
- PutClientInServer(it);
- }
- });
- bot_relinkplayerlist();
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientConnect)
-{
- entity player = M_ARGV(0, entity);
-
- TRANSMUTE(Observer, player);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, reset_map_global)
-{
- allowed_to_spawn = true;
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
- M_ARGV(0, float) = ca_teams;
-}
-
-entity ca_LastPlayerForTeam(entity this)
-{
- entity last_pl = NULL;
- FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
- if (!IS_DEAD(it))
- if (SAME_TEAM(this, it))
- if (!last_pl)
- last_pl = it;
- else
- return NULL;
- });
- return last_pl;
-}
-
-void ca_LastPlayerForTeam_Notify(entity this)
-{
- if (round_handler_IsActive())
- if (round_handler_IsRoundStarted())
- {
- entity pl = ca_LastPlayerForTeam(this);
- if (pl)
- Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
- }
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerDies)
-{
- entity frag_target = M_ARGV(2, entity);
-
- ca_LastPlayerForTeam_Notify(frag_target);
- if (!allowed_to_spawn)
- {
- frag_target.respawn_flags = RESPAWN_SILENT;
- // prevent unwanted sudden rejoin as spectator and move of spectator camera
- frag_target.respawn_time = time + 2;
- }
- if (!warmup_stage)
- eliminatedPlayers.SendFlags |= 1;
- if(IS_BOT_CLIENT(frag_target))
- bot_clear(frag_target);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
-{
- entity player = M_ARGV(0, entity);
-
- if (player.caplayer == 1)
- ca_LastPlayerForTeam_Notify(player);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
-{
- entity player = M_ARGV(0, entity);
-
- if (!IS_DEAD(player))
- ca_LastPlayerForTeam_Notify(player);
- if (player.killindicator_teamchange == -2) // player wants to spectate
- player.caplayer = 0;
- if (player.caplayer)
- player.frags = FRAGS_LMS_LOSER;
- if (!warmup_stage)
- eliminatedPlayers.SendFlags |= 1;
- if (!player.caplayer)
- return false; // allow team reset
- return true; // prevent team reset
-}
-
-MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon)
-{
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST)
-{
- M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SetStartItems)
-{
- start_items &= ~IT_UNLIMITED_AMMO;
- start_health = warmup_start_health = cvar("g_lms_start_health");
- start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor");
- start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells");
- start_ammo_nails = warmup_start_ammo_nails = cvar("g_lms_start_ammo_nails");
- start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
- start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells");
- start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma");
- start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
-}
-
-MUTATOR_HOOKFUNCTION(ca, Damage_Calculate)
-{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, entity);
- float frag_deathtype = M_ARGV(3, float);
- float frag_damage = M_ARGV(4, float);
- float frag_mirrordamage = M_ARGV(5, float);
-
- if (IS_PLAYER(frag_target))
- if (!IS_DEAD(frag_target))
- if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
- frag_damage = 0;
-
- frag_mirrordamage = 0;
-
- M_ARGV(4, float) = frag_damage;
- M_ARGV(5, float) = frag_mirrordamage;
-}
-
-MUTATOR_HOOKFUNCTION(ca, FilterItem)
-{
- entity item = M_ARGV(0, entity);
-
- if (autocvar_g_powerups <= 0)
- if (item.flags & FL_POWERUP)
- return true;
-
- if (autocvar_g_pickup_items <= 0)
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
-{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, entity);
- float frag_damage = M_ARGV(7, float);
- float damage_take = M_ARGV(4, float);
- float damage_save = M_ARGV(5, float);
-
- float excess = max(0, frag_damage - damage_take - damage_save);
-
- if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
- GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
-}
-
-MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
-{
- // no respawn calculations needed, player is forced to spectate anyway
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
-{
- // no regeneration in CA
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
-{
- // announce remaining frags
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectateSet)
-{
- entity client = M_ARGV(0, entity);
- entity targ = M_ARGV(1, entity);
-
- if (!autocvar_g_ca_spectate_enemies && client.caplayer)
- if (DIFF_TEAM(targ, client))
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectateNext)
-{
- entity client = M_ARGV(0, entity);
-
- if (!autocvar_g_ca_spectate_enemies && client.caplayer)
- {
- entity targ = M_ARGV(1, entity);
- M_ARGV(1, entity) = CA_SpectateNext(client, targ);
- return true;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
-{
- entity client = M_ARGV(0, entity);
- entity targ = M_ARGV(1, entity);
- entity first = M_ARGV(2, entity);
-
- if (!autocvar_g_ca_spectate_enemies && client.caplayer)
- {
- do { targ = targ.chain; }
- while(targ && DIFF_TEAM(targ, client));
-
- if (!targ)
- {
- for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain);
-
- if (targ == client.enemy)
- return MUT_SPECPREV_RETURN;
- }
- }
-
- M_ARGV(1, entity) = targ;
-
- return MUT_SPECPREV_FOUND;
-}
-
-MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
-{
- FOREACH_CLIENT(IS_REAL_CLIENT(it), {
- if (IS_PLAYER(it) || it.caplayer == 1)
- ++M_ARGV(0, int);
- ++M_ARGV(1, int);
- });
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
-{
- entity player = M_ARGV(0, entity);
-
- if (player.caplayer)
- {
- // they're going to spec, we can do other checks
- if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
- Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
- return MUT_SPECCMD_FORCE;
- }
-
- return MUT_SPECCMD_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(ca, WantWeapon)
-{
- M_ARGV(2, bool) = true; // all weapons
-}
-
-MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
-{
- return true; // doesn't work well with the whole spectator as player thing
-}
-
-MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus)
-{
- entity player = M_ARGV(0, entity);
-
- return player.caplayer == 1;
-}
-
-MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
-{
- // most weapons arena
- if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
-}
+++ /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, DMG_NOWEP, mymid, normalize(theirmid - mymid) * ctf_captureshield_force);
- if(IS_REAL_CLIENT(toucher)) { Send_Notification(NOTIF_ONE, toucher, MSG_CENTER, CENTER_CTF_CAPTURESHIELD_SHIELDED); }
-}
-
-void ctf_CaptureShield_Spawn(entity flag)
-{
- entity shield = new(ctf_captureshield);
-
- shield.enemy = flag;
- shield.team = flag.team;
- settouch(shield, ctf_CaptureShield_Touch);
- setcefc(shield, ctf_CaptureShield_Customize);
- shield.effects = EF_ADDITIVE;
- set_movetype(shield, MOVETYPE_NOCLIP);
- shield.solid = SOLID_TRIGGER;
- shield.avelocity = '7 0 11';
- shield.scale = 0.5;
-
- setorigin(shield, flag.origin);
- setmodel(shield, MDL_CTF_SHIELD);
- setsize(shield, shield.scale * shield.mins, shield.scale * shield.maxs);
-}
-
-
-// ====================
-// Drop/Pass/Throw Code
-// ====================
-
-void ctf_Handle_Drop(entity flag, entity player, int droptype)
-{
- // declarations
- player = (player ? player : flag.pass_sender);
-
- // main
- set_movetype(flag, MOVETYPE_TOSS);
- flag.takedamage = DAMAGE_YES;
- flag.angles = '0 0 0';
- flag.health = flag.max_flag_health;
- flag.ctf_droptime = time;
- flag.ctf_dropper = player;
- flag.ctf_status = FLAG_DROPPED;
-
- // messages and sounds
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_LOST), player.netname);
- _sound(flag, CH_TRIGGER, flag.snd_flag_dropped, VOL_BASE, ATTEN_NONE);
- ctf_EventLog("dropped", player.team, player);
-
- // scoring
- GameRules_scoring_add_team(player, SCORE, -((flag.score_drop) ? flag.score_drop : autocvar_g_ctf_score_penalty_drop));
- GameRules_scoring_add(player, CTF_DROPS, 1);
-
- // waypoints
- if(autocvar_g_ctf_flag_dropped_waypoint) {
- entity wp = WaypointSprite_Spawn(WP_FlagDropped, 0, 0, flag, FLAG_WAYPOINT_OFFSET, NULL, ((autocvar_g_ctf_flag_dropped_waypoint == 2) ? 0 : player.team), flag, wps_flagdropped, true, RADARICON_FLAG);
- wp.colormod = WPCOLOR_DROPPEDFLAG(flag.team);
- }
-
- if(autocvar_g_ctf_flag_return_time || (autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health))
- {
- WaypointSprite_UpdateMaxHealth(flag.wps_flagdropped, flag.max_flag_health);
- WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health);
- }
-
- player.throw_antispam = time + autocvar_g_ctf_pass_wait;
-
- if(droptype == DROP_PASS)
- {
- flag.pass_distance = 0;
- flag.pass_sender = NULL;
- flag.pass_target = NULL;
- }
-}
-
-void ctf_Handle_Retrieve(entity flag, entity player)
-{
- entity sender = flag.pass_sender;
-
- // transfer flag to player
- flag.owner = player;
- flag.owner.flagcarried = flag;
- GameRules_scoring_vip(player, true);
-
- // reset flag
- if(player.vehicle)
- {
- setattachment(flag, player.vehicle, "");
- setorigin(flag, VEHICLE_FLAG_OFFSET);
- flag.scale = VEHICLE_FLAG_SCALE;
- }
- else
- {
- setattachment(flag, player, "");
- setorigin(flag, FLAG_CARRY_OFFSET);
- }
- set_movetype(flag, MOVETYPE_NONE);
- flag.takedamage = DAMAGE_NO;
- flag.solid = SOLID_NOT;
- flag.angles = '0 0 0';
- flag.ctf_status = FLAG_CARRY;
-
- // messages and sounds
- _sound(player, CH_TRIGGER, flag.snd_flag_pass, VOL_BASE, ATTEN_NORM);
- ctf_EventLog("receive", flag.team, player);
-
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), {
- if(it == sender)
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_SENT), player.netname);
- else if(it == player)
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_RECEIVED), sender.netname);
- else if(SAME_TEAM(it, sender))
- Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_NUM(flag.team, CENTER_CTF_PASS_OTHER), sender.netname, player.netname);
- });
-
- // create new waypoint
- ctf_FlagcarrierWaypoints(player);
-
- sender.throw_antispam = time + autocvar_g_ctf_pass_wait;
- player.throw_antispam = sender.throw_antispam;
-
- flag.pass_distance = 0;
- flag.pass_sender = NULL;
- flag.pass_target = NULL;
-}
-
-void ctf_Handle_Throw(entity player, entity receiver, int droptype)
-{
- entity flag = player.flagcarried;
- vector targ_origin, flag_velocity;
-
- if(!flag) { return; }
- if((droptype == DROP_PASS) && !receiver) { return; }
-
- if(flag.speedrunning) { ctf_RespawnFlag(flag); return; }
-
- // reset the flag
- setattachment(flag, NULL, "");
- setorigin(flag, player.origin + FLAG_DROP_OFFSET);
- flag.owner.flagcarried = NULL;
- GameRules_scoring_vip(flag.owner, false);
- flag.owner = NULL;
- flag.solid = SOLID_TRIGGER;
- flag.ctf_dropper = player;
- flag.ctf_droptime = time;
- navigation_dynamicgoal_set(flag);
-
- flag.flags = FL_ITEM | FL_NOTARGET; // clear FL_ONGROUND for MOVETYPE_TOSS
-
- switch(droptype)
- {
- case DROP_PASS:
- {
- // warpzone support:
- // for the examples, we assume player -> wz1 -> ... -> wzn -> receiver
- // findradius has already put wzn ... wz1 into receiver's warpzone parameters!
- WarpZone_RefSys_Copy(flag, receiver);
- WarpZone_RefSys_AddInverse(flag, receiver); // wz1^-1 ... wzn^-1 receiver
- targ_origin = WarpZone_RefSys_TransformOrigin(receiver, flag, (0.5 * (receiver.absmin + receiver.absmax))); // this is target origin as seen by the flag
-
- flag.pass_distance = vlen((('1 0 0' * targ_origin.x) + ('0 1 0' * targ_origin.y)) - (('1 0 0' * player.origin.x) + ('0 1 0' * player.origin.y))); // for the sake of this check, exclude Z axis
- ctf_CalculatePassVelocity(flag, targ_origin, player.origin, false);
-
- // main
- set_movetype(flag, MOVETYPE_FLY);
- flag.takedamage = DAMAGE_NO;
- flag.pass_sender = player;
- flag.pass_target = receiver;
- flag.ctf_status = FLAG_PASSING;
-
- // other
- _sound(player, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
- WarpZone_TrailParticles(NULL, _particleeffectnum(flag.passeffect), player.origin, targ_origin);
- ctf_EventLog("pass", flag.team, player);
- break;
- }
-
- case DROP_THROW:
- {
- makevectors((player.v_angle.y * '0 1 0') + (bound(autocvar_g_ctf_throw_angle_min, player.v_angle.x, autocvar_g_ctf_throw_angle_max) * '1 0 0'));
-
- flag_velocity = (('0 0 1' * autocvar_g_ctf_throw_velocity_up) + ((v_forward * autocvar_g_ctf_throw_velocity_forward) * ((player.items & ITEM_Strength.m_itemid) ? autocvar_g_ctf_throw_strengthmultiplier : 1)));
- flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, flag_velocity, false);
- ctf_Handle_Drop(flag, player, droptype);
- break;
- }
-
- case DROP_RESET:
- {
- flag.velocity = '0 0 0'; // do nothing
- break;
- }
-
- default:
- case DROP_NORMAL:
- {
- flag.velocity = W_CalculateProjectileVelocity(player, player.velocity, (('0 0 1' * autocvar_g_ctf_drop_velocity_up) + ((('0 1 0' * crandom()) + ('1 0 0' * crandom())) * autocvar_g_ctf_drop_velocity_side)), false);
- ctf_Handle_Drop(flag, player, droptype);
- break;
- }
- }
-
- // kill old waypointsprite
- WaypointSprite_Ping(player.wps_flagcarrier);
- WaypointSprite_Kill(player.wps_flagcarrier);
-
- if(player.wps_enemyflagcarrier)
- WaypointSprite_Kill(player.wps_enemyflagcarrier);
-
- if(player.wps_flagreturn)
- WaypointSprite_Kill(player.wps_flagreturn);
-
- // captureshield
- ctf_CaptureShield_Update(player, 0); // shield player from picking up flag
-}
-
-void shockwave_spawn(string m, vector org, float sz, float t1, float t2)
-{
- return modeleffect_spawn(m, 0, 0, org, '0 0 0', '0 0 0', '0 0 0', 0, sz, 1, t1, t2);
-}
-
-// ==============
-// Event Handlers
-// ==============
-
-void nades_GiveBonus(entity player, float score);
-
-void ctf_Handle_Capture(entity flag, entity toucher, int capturetype)
-{
- entity enemy_flag = ((capturetype == CAPTURE_NORMAL) ? toucher.flagcarried : toucher);
- entity player = ((capturetype == CAPTURE_NORMAL) ? toucher : enemy_flag.ctf_dropper);
- entity player_team_flag = NULL, tmp_entity;
- float old_time, new_time;
-
- if(!player) { return; } // without someone to give the reward to, we can't possibly cap
- if(CTF_DIFFTEAM(player, flag)) { return; }
- if((flag.cnt || enemy_flag.cnt) && flag.cnt != enemy_flag.cnt) { return; } // this should catch some edge cases (capturing grouped flag at ungrouped flag disallowed etc)
-
- if (toucher.goalentity == flag.bot_basewaypoint)
- toucher.goalentity_lock_timeout = 0;
-
- if(ctf_oneflag)
- for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
- if(SAME_TEAM(tmp_entity, player))
- {
- player_team_flag = tmp_entity;
- break;
- }
-
- nades_GiveBonus(player, autocvar_g_nades_bonus_score_high );
-
- player.throw_prevtime = time;
- player.throw_count = 0;
-
- // messages and sounds
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_NUM(enemy_flag.team, CENTER_CTF_CAPTURE));
- ctf_CaptureRecord(enemy_flag, player);
- _sound(player, CH_TRIGGER, ((ctf_oneflag) ? player_team_flag.snd_flag_capture : ((DIFF_TEAM(player, flag)) ? enemy_flag.snd_flag_capture : flag.snd_flag_capture)), VOL_BASE, ATTEN_NONE);
-
- switch(capturetype)
- {
- case CAPTURE_NORMAL: ctf_EventLog("capture", enemy_flag.team, player); break;
- case CAPTURE_DROPPED: ctf_EventLog("droppedcapture", enemy_flag.team, player); break;
- default: break;
- }
-
- // scoring
- float pscore = 0;
- if(enemy_flag.score_capture || flag.score_capture)
- pscore = floor((max(1, enemy_flag.score_capture) + max(1, flag.score_capture)) * 0.5);
- GameRules_scoring_add_team(player, SCORE, ((pscore) ? pscore : autocvar_g_ctf_score_capture));
- float capscore = 0;
- if(enemy_flag.score_team_capture || flag.score_team_capture)
- capscore = floor((max(1, enemy_flag.score_team_capture) + max(1, flag.score_team_capture)) * 0.5);
- GameRules_scoring_add_team(player, CTF_CAPS, ((capscore) ? capscore : 1));
-
- old_time = GameRules_scoring_add(player, CTF_CAPTIME, 0);
- new_time = TIME_ENCODE(time - enemy_flag.ctf_pickuptime);
- if(!old_time || new_time < old_time)
- GameRules_scoring_add(player, CTF_CAPTIME, new_time - old_time);
-
- // effects
- Send_Effect_(flag.capeffect, flag.origin, '0 0 0', 1);
- //shockwave_spawn("models/ctf/shockwavetransring.md3", flag.origin - '0 0 15', -0.8, 0, 1);
-
- // other
- if(capturetype == CAPTURE_NORMAL)
- {
- WaypointSprite_Kill(player.wps_flagcarrier);
- if(flag.speedrunning) { ctf_FakeTimeLimit(player, -1); }
-
- if((enemy_flag.ctf_dropper) && (player != enemy_flag.ctf_dropper))
- { GameRules_scoring_add_team(enemy_flag.ctf_dropper, SCORE, ((enemy_flag.score_assist) ? enemy_flag.score_assist : autocvar_g_ctf_score_capture_assist)); }
- }
-
- flag.enemy = toucher;
-
- // reset the flag
- player.next_take_time = time + autocvar_g_ctf_flag_collect_delay;
- ctf_RespawnFlag(enemy_flag);
-}
-
-void ctf_Handle_Return(entity flag, entity player)
-{
- // messages and sounds
- if(IS_MONSTER(player))
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN_MONSTER), player.monster_name);
- }
- else if(flag.team)
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_RETURN));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(flag.team, INFO_CTF_RETURN), player.netname);
- }
- _sound(player, CH_TRIGGER, flag.snd_flag_returned, VOL_BASE, ATTEN_NONE);
- ctf_EventLog("return", flag.team, player);
-
- // scoring
- if(IS_PLAYER(player))
- {
- GameRules_scoring_add_team(player, SCORE, ((flag.score_return) ? flag.score_return : autocvar_g_ctf_score_return)); // reward for return
- GameRules_scoring_add(player, CTF_RETURNS, 1); // add to count of returns
-
- nades_GiveBonus(player,autocvar_g_nades_bonus_score_medium);
- }
-
- TeamScore_AddToTeam(flag.team, ST_SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the team who was last carrying it
-
- if(flag.ctf_dropper)
- {
- GameRules_scoring_add(flag.ctf_dropper, SCORE, -autocvar_g_ctf_score_penalty_returned); // punish the player who dropped the flag
- ctf_CaptureShield_Update(flag.ctf_dropper, 0); // shield player from picking up flag
- flag.ctf_dropper.next_take_time = time + autocvar_g_ctf_flag_collect_delay; // set next take time
- }
-
- // other
- if(player.flagcarried == flag)
- WaypointSprite_Kill(player.wps_flagcarrier);
-
- flag.enemy = player;
-
- // reset the flag
- ctf_RespawnFlag(flag);
-}
-
-void ctf_Handle_Pickup(entity flag, entity player, int pickuptype)
-{
- // declarations
- float pickup_dropped_score; // used to calculate dropped pickup score
-
- // attach the flag to the player
- flag.owner = player;
- player.flagcarried = flag;
- GameRules_scoring_vip(player, true);
- if(player.vehicle)
- {
- setattachment(flag, player.vehicle, "");
- setorigin(flag, VEHICLE_FLAG_OFFSET);
- flag.scale = VEHICLE_FLAG_SCALE;
- }
- else
- {
- setattachment(flag, player, "");
- setorigin(flag, FLAG_CARRY_OFFSET);
- }
-
- // flag setup
- set_movetype(flag, MOVETYPE_NONE);
- flag.takedamage = DAMAGE_NO;
- flag.solid = SOLID_NOT;
- flag.angles = '0 0 0';
- flag.ctf_status = FLAG_CARRY;
-
- switch(pickuptype)
- {
- case PICKUP_BASE: flag.ctf_pickuptime = time; break; // used for timing runs
- case PICKUP_DROPPED: flag.health = flag.max_flag_health; break; // reset health/return timelimit
- default: break;
- }
-
- // messages and sounds
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_PICKUP), player.netname);
- if(ctf_stalemate)
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_STALEMATE_CARRIER);
- if(!flag.team)
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PICKUP_NEUTRAL);
- else if(CTF_DIFFTEAM(player, flag))
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, APP_TEAM_NUM(flag.team, CENTER_CTF_PICKUP));
- else
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, ((SAME_TEAM(player, flag)) ? CENTER_CTF_PICKUP_RETURN : CENTER_CTF_PICKUP_RETURN_ENEMY), Team_ColorCode(flag.team));
-
- Send_Notification(NOTIF_TEAM_EXCEPT, player, MSG_CHOICE, APP_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
-
- if(!flag.team)
- FOREACH_CLIENT(IS_PLAYER(it) && it != player && DIFF_TEAM(it, player), { Send_Notification(NOTIF_ONE, it, MSG_CHOICE, CHOICE_CTF_PICKUP_ENEMY_NEUTRAL, Team_ColorCode(player.team), player.netname); });
-
- if(flag.team)
- FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
- if(CTF_SAMETEAM(flag, it))
- if(SAME_TEAM(player, it))
- Send_Notification(NOTIF_ONE, it, MSG_CHOICE, APP_TEAM_NUM(flag.team, CHOICE_CTF_PICKUP_TEAM), Team_ColorCode(player.team), player.netname);
- else
- Send_Notification(NOTIF_ONE, it, MSG_CHOICE, ((SAME_TEAM(flag, player)) ? CHOICE_CTF_PICKUP_ENEMY_TEAM : CHOICE_CTF_PICKUP_ENEMY), Team_ColorCode(player.team), player.netname);
- });
-
- _sound(player, CH_TRIGGER, flag.snd_flag_taken, VOL_BASE, ATTEN_NONE);
-
- // scoring
- GameRules_scoring_add(player, CTF_PICKUPS, 1);
- nades_GiveBonus(player, autocvar_g_nades_bonus_score_minor);
- switch(pickuptype)
- {
- case PICKUP_BASE:
- {
- GameRules_scoring_add_team(player, SCORE, ((flag.score_pickup) ? flag.score_pickup : autocvar_g_ctf_score_pickup_base));
- ctf_EventLog("steal", flag.team, player);
- break;
- }
-
- case PICKUP_DROPPED:
- {
- pickup_dropped_score = (autocvar_g_ctf_flag_return_time ? bound(0, ((flag.ctf_droptime + autocvar_g_ctf_flag_return_time) - time) / autocvar_g_ctf_flag_return_time, 1) : 1);
- pickup_dropped_score = floor((autocvar_g_ctf_score_pickup_dropped_late * (1 - pickup_dropped_score) + autocvar_g_ctf_score_pickup_dropped_early * pickup_dropped_score) + 0.5);
- LOG_TRACE("pickup_dropped_score is ", ftos(pickup_dropped_score));
- GameRules_scoring_add_team(player, SCORE, pickup_dropped_score);
- ctf_EventLog("pickup", flag.team, player);
- break;
- }
-
- default: break;
- }
-
- // speedrunning
- if(pickuptype == PICKUP_BASE)
- {
- flag.speedrunning = player.speedrunning; // if speedrunning, flag will flag-return and teleport the owner back after the record
- if((player.speedrunning) && (ctf_captimerecord))
- ctf_FakeTimeLimit(player, time + ctf_captimerecord);
- }
-
- // effects
- Send_Effect_(flag.toucheffect, player.origin, '0 0 0', 1);
-
- // waypoints
- if(pickuptype == PICKUP_DROPPED) { WaypointSprite_Kill(flag.wps_flagdropped); }
- ctf_FlagcarrierWaypoints(player);
- WaypointSprite_Ping(player.wps_flagcarrier);
-}
-
-
-// ===================
-// Main Flag Functions
-// ===================
-
-void ctf_CheckFlagReturn(entity flag, int returntype)
-{
- if((flag.ctf_status == FLAG_DROPPED) || (flag.ctf_status == FLAG_PASSING))
- {
- if(flag.wps_flagdropped) { WaypointSprite_UpdateHealth(flag.wps_flagdropped, flag.health); }
-
- if((flag.health <= 0) || (time >= flag.ctf_droptime + autocvar_g_ctf_flag_return_time))
- {
- switch(returntype)
- {
- case RETURN_DROPPED:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DROPPED)); break;
- case RETURN_DAMAGE:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_DAMAGED)); break;
- case RETURN_SPEEDRUN:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_SPEEDRUN), TIME_ENCODE(ctf_captimerecord)); break;
- case RETURN_NEEDKILL:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_NEEDKILL)); break;
- default:
- case RETURN_TIMEOUT:
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(flag.team, INFO_CTF_FLAGRETURN_TIMEOUT)); break;
- }
- _sound(flag, CH_TRIGGER, flag.snd_flag_respawn, VOL_BASE, ATTEN_NONE);
- ctf_EventLog("returned", flag.team, NULL);
- flag.enemy = NULL;
- ctf_RespawnFlag(flag);
- }
- }
-}
-
-bool ctf_Stalemate_Customize(entity this, entity client)
-{
- // make spectators see what the player would see
- entity e = WaypointSprite_getviewentity(client);
- entity wp_owner = this.owner;
-
- // team waypoints
- //if(CTF_SAMETEAM(wp_owner.flagcarried, wp_owner)) { return false; }
- if(SAME_TEAM(wp_owner, e)) { return false; }
- if(!IS_PLAYER(e)) { return false; }
-
- return true;
-}
-
-void ctf_CheckStalemate()
-{
- // declarations
- int stale_flags = 0, stale_red_flags = 0, stale_blue_flags = 0, stale_yellow_flags = 0, stale_pink_flags = 0, stale_neutral_flags = 0;
- entity tmp_entity;
-
- entity ctf_staleflaglist = NULL; // reset the list, we need to build the list each time this function runs
-
- // build list of stale flags
- for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
- {
- if(autocvar_g_ctf_stalemate)
- if(tmp_entity.ctf_status != FLAG_BASE)
- if(time >= tmp_entity.ctf_pickuptime + autocvar_g_ctf_stalemate_time || !tmp_entity.team) // instant stalemate in oneflag
- {
- tmp_entity.ctf_staleflagnext = ctf_staleflaglist; // link flag into staleflaglist
- ctf_staleflaglist = tmp_entity;
-
- switch(tmp_entity.team)
- {
- case NUM_TEAM_1: ++stale_red_flags; break;
- case NUM_TEAM_2: ++stale_blue_flags; break;
- case NUM_TEAM_3: ++stale_yellow_flags; break;
- case NUM_TEAM_4: ++stale_pink_flags; break;
- default: ++stale_neutral_flags; break;
- }
- }
- }
-
- if(ctf_oneflag)
- stale_flags = (stale_neutral_flags >= 1);
- else
- stale_flags = (stale_red_flags >= 1) + (stale_blue_flags >= 1) + (stale_yellow_flags >= 1) + (stale_pink_flags >= 1);
-
- if(ctf_oneflag && stale_flags == 1)
- ctf_stalemate = true;
- else if(stale_flags >= 2)
- ctf_stalemate = true;
- else if(stale_flags == 0 && autocvar_g_ctf_stalemate_endcondition == 2)
- { ctf_stalemate = false; wpforenemy_announced = false; }
- else if(stale_flags < 2 && autocvar_g_ctf_stalemate_endcondition == 1)
- { ctf_stalemate = false; wpforenemy_announced = false; }
-
- // if sufficient stalemate, then set up the waypointsprite and announce the stalemate if necessary
- if(ctf_stalemate)
- {
- for(tmp_entity = ctf_staleflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_staleflagnext)
- {
- if((tmp_entity.owner) && (!tmp_entity.owner.wps_enemyflagcarrier))
- {
- entity wp = WaypointSprite_Spawn(((ctf_oneflag) ? WP_FlagCarrier : WP_FlagCarrierEnemy), 0, 0, tmp_entity.owner, FLAG_WAYPOINT_OFFSET, NULL, 0, tmp_entity.owner, wps_enemyflagcarrier, true, RADARICON_FLAG);
- wp.colormod = WPCOLOR_ENEMYFC(tmp_entity.owner.team);
- setcefc(tmp_entity.owner.wps_enemyflagcarrier, ctf_Stalemate_Customize);
- }
- }
-
- if (!wpforenemy_announced)
- {
- FOREACH_CLIENT(IS_PLAYER(it) && IS_REAL_CLIENT(it), { Send_Notification(NOTIF_ONE, it, MSG_CENTER, ((it.flagcarried) ? CENTER_CTF_STALEMATE_CARRIER : CENTER_CTF_STALEMATE_OTHER)); });
-
- wpforenemy_announced = true;
- }
- }
-}
-
-void ctf_FlagDamage(entity this, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force)
-{
- if(ITEM_DAMAGE_NEEDKILL(deathtype))
- {
- if(autocvar_g_ctf_flag_return_damage_delay)
- this.ctf_flagdamaged_byworld = true;
- else
- {
- this.health = 0;
- ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
- }
- return;
- }
- if(autocvar_g_ctf_flag_return_damage)
- {
- // reduce health and check if it should be returned
- this.health = this.health - damage;
- ctf_CheckFlagReturn(this, RETURN_DAMAGE);
- return;
- }
-}
-
-void ctf_FlagThink(entity this)
-{
- // declarations
- entity tmp_entity;
-
- this.nextthink = time + FLAG_THINKRATE; // only 5 fps, more is unnecessary.
-
- // captureshield
- if(this == ctf_worldflaglist) // only for the first flag
- FOREACH_CLIENT(true, { ctf_CaptureShield_Update(it, 1); }); // release shield only
-
- // sanity checks
- if(this.mins != this.m_mins || this.maxs != this.m_maxs) { // reset the flag boundaries in case it got squished
- LOG_TRACE("wtf the flag got squashed?");
- tracebox(this.origin, this.m_mins, this.m_maxs, this.origin, MOVE_NOMONSTERS, this);
- if(!trace_startsolid || this.noalign) // can we resize it without getting stuck?
- setsize(this, this.m_mins, this.m_maxs);
- }
-
- // main think method
- switch(this.ctf_status)
- {
- case FLAG_BASE:
- {
- if(autocvar_g_ctf_dropped_capture_radius)
- {
- for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
- if(tmp_entity.ctf_status == FLAG_DROPPED)
- if(vdist(this.origin - tmp_entity.origin, <, autocvar_g_ctf_dropped_capture_radius))
- if(time > tmp_entity.ctf_droptime + autocvar_g_ctf_dropped_capture_delay)
- ctf_Handle_Capture(this, tmp_entity, CAPTURE_DROPPED);
- }
- return;
- }
-
- case FLAG_DROPPED:
- {
- this.angles = '0 0 0'; // reset flag angles in case warpzones adjust it
-
- if(autocvar_g_ctf_flag_dropped_floatinwater)
- {
- vector midpoint = ((this.absmin + this.absmax) * 0.5);
- if(pointcontents(midpoint) == CONTENT_WATER)
- {
- this.velocity = this.velocity * 0.5;
-
- if(pointcontents(midpoint + FLAG_FLOAT_OFFSET) == CONTENT_WATER)
- { this.velocity_z = autocvar_g_ctf_flag_dropped_floatinwater; }
- else
- { set_movetype(this, MOVETYPE_FLY); }
- }
- else if(this.move_movetype == MOVETYPE_FLY) { set_movetype(this, MOVETYPE_TOSS); }
- }
- if(autocvar_g_ctf_flag_return_dropped)
- {
- if((vdist(this.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_dropped)) || (autocvar_g_ctf_flag_return_dropped == -1))
- {
- this.health = 0;
- ctf_CheckFlagReturn(this, RETURN_DROPPED);
- return;
- }
- }
- if(this.ctf_flagdamaged_byworld)
- {
- this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_damage_delay) * FLAG_THINKRATE);
- ctf_CheckFlagReturn(this, RETURN_NEEDKILL);
- return;
- }
- else if(autocvar_g_ctf_flag_return_time)
- {
- this.health -= ((this.max_flag_health / autocvar_g_ctf_flag_return_time) * FLAG_THINKRATE);
- ctf_CheckFlagReturn(this, RETURN_TIMEOUT);
- return;
- }
- return;
- }
-
- case FLAG_CARRY:
- {
- if(this.speedrunning && ctf_captimerecord && (time >= this.ctf_pickuptime + ctf_captimerecord))
- {
- this.health = 0;
- ctf_CheckFlagReturn(this, RETURN_SPEEDRUN);
-
- CS(this.owner).impulse = CHIMPULSE_SPEEDRUN.impulse; // move the player back to the waypoint they set
- ImpulseCommands(this.owner);
- }
- if(autocvar_g_ctf_stalemate)
- {
- if(time >= wpforenemy_nextthink)
- {
- ctf_CheckStalemate();
- wpforenemy_nextthink = time + WPFE_THINKRATE; // waypoint for enemy think rate (to reduce unnecessary spam of this check)
- }
- }
- if(CTF_SAMETEAM(this, this.owner) && this.team)
- {
- if(autocvar_g_ctf_flag_return) // drop the flag if reverse status has changed
- ctf_Handle_Throw(this.owner, NULL, DROP_THROW);
- else if(vdist(this.owner.origin - this.ctf_spawnorigin, <=, autocvar_g_ctf_flag_return_carried_radius))
- ctf_Handle_Return(this, this.owner);
- }
- return;
- }
-
- case FLAG_PASSING:
- {
- vector targ_origin = ((this.pass_target.absmin + this.pass_target.absmax) * 0.5);
- targ_origin = WarpZone_RefSys_TransformOrigin(this.pass_target, this, targ_origin); // origin of target as seen by the flag (us)
- WarpZone_TraceLine(this.origin, targ_origin, MOVE_NOMONSTERS, this);
-
- if((this.pass_target == NULL)
- || (IS_DEAD(this.pass_target))
- || (this.pass_target.flagcarried)
- || (vdist(this.origin - targ_origin, >, autocvar_g_ctf_pass_radius))
- || ((trace_fraction < 1) && (trace_ent != this.pass_target))
- || (time > this.ctf_droptime + autocvar_g_ctf_pass_timelimit))
- {
- // give up, pass failed
- ctf_Handle_Drop(this, NULL, DROP_PASS);
- }
- else
- {
- // still a viable target, go for it
- ctf_CalculatePassVelocity(this, targ_origin, this.origin, true);
- }
- return;
- }
-
- default: // this should never happen
- {
- LOG_TRACE("ctf_FlagThink(): Flag exists with no status?");
- return;
- }
- }
-}
-
-METHOD(Flag, giveTo, bool(Flag this, entity flag, entity toucher))
-{
- return = false;
- if(game_stopped) return;
- if(trace_dphitcontents & (DPCONTENTS_PLAYERCLIP | DPCONTENTS_MONSTERCLIP)) { return; }
-
- bool is_not_monster = (!IS_MONSTER(toucher));
-
- // automatically kill the flag and return it if it touched lava/slime/nodrop surfaces
- if(ITEM_TOUCH_NEEDKILL())
- {
- if(!autocvar_g_ctf_flag_return_damage_delay)
- {
- flag.health = 0;
- ctf_CheckFlagReturn(flag, RETURN_NEEDKILL);
- }
- if(!flag.ctf_flagdamaged_byworld) { return; }
- }
-
- // special touch behaviors
- if(STAT(FROZEN, toucher)) { return; }
- else if(IS_VEHICLE(toucher))
- {
- if(autocvar_g_ctf_allow_vehicle_touch && toucher.owner)
- toucher = toucher.owner; // the player is actually the vehicle owner, not other
- else
- return; // do nothing
- }
- else if(IS_MONSTER(toucher))
- {
- if(!autocvar_g_ctf_allow_monster_touch)
- return; // do nothing
- }
- else if (!IS_PLAYER(toucher)) // The flag just touched an object, most likely the world
- {
- if(time > flag.wait) // if we haven't in a while, play a sound/effect
- {
- Send_Effect_(flag.toucheffect, flag.origin, '0 0 0', 1);
- _sound(flag, CH_TRIGGER, flag.snd_flag_touch, VOL_BASE, ATTEN_NORM);
- flag.wait = time + FLAG_TOUCHRATE;
- }
- return;
- }
- else if(IS_DEAD(toucher)) { return; }
-
- switch(flag.ctf_status)
- {
- case FLAG_BASE:
- {
- if(ctf_oneflag)
- {
- if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && !toucher.flagcarried.team && is_not_monster)
- ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the neutral flag to enemy base
- else if(!flag.team && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the neutral flag
- }
- else if(CTF_SAMETEAM(toucher, flag) && (toucher.flagcarried) && DIFF_TEAM(toucher.flagcarried, flag) && is_not_monster)
- ctf_Handle_Capture(flag, toucher, CAPTURE_NORMAL); // toucher just captured the enemies flag to his base
- else if(CTF_DIFFTEAM(toucher, flag) && (toucher.flagcarried) && CTF_SAMETEAM(toucher.flagcarried, toucher) && (!toucher.ctf_captureshielded) && autocvar_g_ctf_flag_return_carrying && (time > toucher.next_take_time) && is_not_monster)
- {
- ctf_Handle_Return(toucher.flagcarried, toucher); // return their current flag
- ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // now pickup the flag
- }
- else if(CTF_DIFFTEAM(toucher, flag) && (!toucher.flagcarried) && (!toucher.ctf_captureshielded) && (time > toucher.next_take_time) && is_not_monster)
- ctf_Handle_Pickup(flag, toucher, PICKUP_BASE); // toucher just stole the enemies flag
- break;
- }
-
- case FLAG_DROPPED:
- {
- if(CTF_SAMETEAM(toucher, flag) && ctf_Immediate_Return_Allowed(flag, toucher))
- ctf_Handle_Return(flag, toucher); // toucher just returned his own flag
- else if(is_not_monster && (!toucher.flagcarried) && ((toucher != flag.ctf_dropper) || (time > flag.ctf_droptime + autocvar_g_ctf_flag_collect_delay)))
- ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED); // toucher just picked up a dropped enemy flag
- break;
- }
-
- case FLAG_CARRY:
- {
- LOG_TRACE("Someone touched a flag even though it was being carried?");
- break;
- }
-
- case FLAG_PASSING:
- {
- if((IS_PLAYER(toucher)) && !IS_DEAD(toucher) && (toucher != flag.pass_sender))
- {
- if(DIFF_TEAM(toucher, flag.pass_sender))
- {
- if(ctf_Immediate_Return_Allowed(flag, toucher))
- ctf_Handle_Return(flag, toucher);
- else if(is_not_monster && (!toucher.flagcarried))
- ctf_Handle_Pickup(flag, toucher, PICKUP_DROPPED);
- }
- else if(!toucher.flagcarried)
- ctf_Handle_Retrieve(flag, toucher);
- }
- break;
- }
- }
-}
-
-.float last_respawn;
-void ctf_RespawnFlag(entity flag)
-{
- // check for flag respawn being called twice in a row
- if(flag.last_respawn > time - 0.5)
- { backtrace("flag respawn called twice quickly! please notify Samual about this..."); }
-
- flag.last_respawn = time;
-
- // reset the player (if there is one)
- if((flag.owner) && (flag.owner.flagcarried == flag))
- {
- WaypointSprite_Kill(flag.owner.wps_enemyflagcarrier);
- WaypointSprite_Kill(flag.owner.wps_flagreturn);
- WaypointSprite_Kill(flag.wps_flagcarrier);
-
- flag.owner.flagcarried = NULL;
- GameRules_scoring_vip(flag.owner, false);
-
- if(flag.speedrunning)
- ctf_FakeTimeLimit(flag.owner, -1);
- }
-
- if((flag.owner) && (flag.owner.vehicle))
- flag.scale = FLAG_SCALE;
-
- if(flag.ctf_status == FLAG_DROPPED)
- { WaypointSprite_Kill(flag.wps_flagdropped); }
-
- // reset the flag
- setattachment(flag, NULL, "");
- setorigin(flag, flag.ctf_spawnorigin);
-
- set_movetype(flag, ((flag.noalign) ? MOVETYPE_NONE : MOVETYPE_TOSS));
- flag.takedamage = DAMAGE_NO;
- flag.health = flag.max_flag_health;
- flag.solid = SOLID_TRIGGER;
- flag.velocity = '0 0 0';
- flag.angles = flag.mangle;
- flag.flags = FL_ITEM | FL_NOTARGET;
-
- flag.ctf_status = FLAG_BASE;
- flag.owner = NULL;
- flag.pass_distance = 0;
- flag.pass_sender = NULL;
- flag.pass_target = NULL;
- flag.ctf_dropper = NULL;
- flag.ctf_pickuptime = 0;
- flag.ctf_droptime = 0;
- flag.ctf_flagdamaged_byworld = false;
- navigation_dynamicgoal_unset(flag);
-
- ctf_CheckStalemate();
-}
-
-void ctf_Reset(entity this)
-{
- if(this.owner && IS_PLAYER(this.owner))
- ctf_Handle_Throw(this.owner, NULL, DROP_RESET);
-
- this.enemy = NULL;
- ctf_RespawnFlag(this);
-}
-
-bool ctf_FlagBase_Customize(entity this, entity client)
-{
- entity e = WaypointSprite_getviewentity(client);
- entity wp_owner = this.owner;
- entity flag = e.flagcarried;
- if(flag && CTF_SAMETEAM(e, flag))
- return false;
- if(flag && (flag.cnt || wp_owner.cnt) && wp_owner.cnt != flag.cnt)
- return false;
- return true;
-}
-
-void ctf_DelayedFlagSetup(entity this) // called after a flag is placed on a map by ctf_FlagSetup()
-{
- // bot waypoints
- waypoint_spawnforitem_force(this, this.origin);
- navigation_dynamicgoal_init(this, true);
-
- // waypointsprites
- entity basename;
- switch (this.team)
- {
- case NUM_TEAM_1: basename = WP_FlagBaseRed; break;
- case NUM_TEAM_2: basename = WP_FlagBaseBlue; break;
- case NUM_TEAM_3: basename = WP_FlagBaseYellow; break;
- case NUM_TEAM_4: basename = WP_FlagBasePink; break;
- default: basename = WP_FlagBaseNeutral; break;
- }
-
- entity wp = WaypointSprite_SpawnFixed(basename, this.origin + FLAG_WAYPOINT_OFFSET, this, wps_flagbase, RADARICON_FLAG);
- wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 1 1');
- WaypointSprite_UpdateTeamRadar(this.wps_flagbase, RADARICON_FLAG, ((this.team) ? colormapPaletteColor(this.team - 1, false) : '1 1 1'));
- setcefc(wp, ctf_FlagBase_Customize);
-
- // captureshield setup
- ctf_CaptureShield_Spawn(this);
-}
-
-.bool pushable;
-
-void ctf_FlagSetup(int teamnumber, entity flag) // called when spawning a flag entity on the map as a spawnfunc
-{
- // main setup
- flag.ctf_worldflagnext = ctf_worldflaglist; // link flag into ctf_worldflaglist
- ctf_worldflaglist = flag;
-
- setattachment(flag, NULL, "");
-
- flag.netname = strzone(sprintf("%s%s^7 flag", Team_ColorCode(teamnumber), Team_ColorName_Upper(teamnumber)));
- flag.team = teamnumber;
- flag.classname = "item_flag_team";
- flag.target = "###item###"; // wut?
- flag.flags = FL_ITEM | FL_NOTARGET;
- IL_PUSH(g_items, flag);
- flag.solid = SOLID_TRIGGER;
- flag.takedamage = DAMAGE_NO;
- flag.damageforcescale = autocvar_g_ctf_flag_damageforcescale;
- flag.max_flag_health = ((autocvar_g_ctf_flag_return_damage && autocvar_g_ctf_flag_health) ? autocvar_g_ctf_flag_health : 100);
- flag.health = flag.max_flag_health;
- flag.event_damage = ctf_FlagDamage;
- flag.pushable = true;
- flag.teleportable = TELEPORT_NORMAL;
- flag.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
- flag.damagedbytriggers = autocvar_g_ctf_flag_return_when_unreachable;
- flag.damagedbycontents = autocvar_g_ctf_flag_return_when_unreachable;
- if(flag.damagedbycontents)
- IL_PUSH(g_damagedbycontents, flag);
- flag.velocity = '0 0 0';
- flag.mangle = flag.angles;
- flag.reset = ctf_Reset;
- settouch(flag, ctf_FlagTouch);
- setthink(flag, ctf_FlagThink);
- flag.nextthink = time + FLAG_THINKRATE;
- flag.ctf_status = FLAG_BASE;
-
- // crudely force them all to 0
- if(autocvar_g_ctf_score_ignore_fields)
- flag.cnt = flag.score_assist = flag.score_team_capture = flag.score_capture = flag.score_drop = flag.score_pickup = flag.score_return = 0;
-
- string teamname = Static_Team_ColorName_Lower(teamnumber);
- // appearence
- if(!flag.scale) { flag.scale = FLAG_SCALE; }
- if(flag.skin == 0) { flag.skin = cvar(sprintf("g_ctf_flag_%s_skin", teamname)); }
- if(flag.model == "") { flag.model = cvar_string(sprintf("g_ctf_flag_%s_model", teamname)); }
- if (flag.toucheffect == "") { flag.toucheffect = EFFECT_FLAG_TOUCH(teamnumber).eent_eff_name; }
- if (flag.passeffect == "") { flag.passeffect = EFFECT_PASS(teamnumber).eent_eff_name; }
- if (flag.capeffect == "") { flag.capeffect = EFFECT_CAP(teamnumber).eent_eff_name; }
-
- // sounds
-#define X(s,b) \
- if(flag.s == "") flag.s = b; \
- precache_sound(flag.s);
-
- X(snd_flag_taken, strzone(SND(CTF_TAKEN(teamnumber))))
- X(snd_flag_returned, strzone(SND(CTF_RETURNED(teamnumber))))
- X(snd_flag_capture, strzone(SND(CTF_CAPTURE(teamnumber))))
- X(snd_flag_dropped, strzone(SND(CTF_DROPPED(teamnumber))))
- X(snd_flag_respawn, strzone(SND(CTF_RESPAWN)))
- X(snd_flag_touch, strzone(SND(CTF_TOUCH)))
- X(snd_flag_pass, strzone(SND(CTF_PASS)))
-#undef X
-
- // precache
- precache_model(flag.model);
-
- // appearence
- _setmodel(flag, flag.model); // precision set below
- setsize(flag, CTF_FLAG.m_mins * flag.scale, CTF_FLAG.m_maxs * flag.scale);
- flag.m_mins = flag.mins; // store these for squash checks
- flag.m_maxs = flag.maxs;
- setorigin(flag, (flag.origin + FLAG_SPAWN_OFFSET));
-
- if(autocvar_g_ctf_flag_glowtrails)
- {
- switch(teamnumber)
- {
- case NUM_TEAM_1: flag.glow_color = 251; break;
- case NUM_TEAM_2: flag.glow_color = 210; break;
- case NUM_TEAM_3: flag.glow_color = 110; break;
- case NUM_TEAM_4: flag.glow_color = 145; break;
- default: flag.glow_color = 254; break;
- }
- flag.glow_size = 25;
- flag.glow_trail = 1;
- }
-
- flag.effects |= EF_LOWPRECISION;
- if(autocvar_g_ctf_fullbrightflags) { flag.effects |= EF_FULLBRIGHT; }
- if(autocvar_g_ctf_dynamiclights)
- {
- switch(teamnumber)
- {
- case NUM_TEAM_1: flag.effects |= EF_RED; break;
- case NUM_TEAM_2: flag.effects |= EF_BLUE; break;
- case NUM_TEAM_3: flag.effects |= EF_DIMLIGHT; break;
- case NUM_TEAM_4: flag.effects |= EF_RED; break;
- default: flag.effects |= EF_DIMLIGHT; break;
- }
- }
-
- // flag placement
- if((flag.spawnflags & 1) || flag.noalign) // don't drop to floor, just stay at fixed location
- {
- flag.dropped_origin = flag.origin;
- flag.noalign = true;
- set_movetype(flag, MOVETYPE_NONE);
- }
- else // drop to floor, automatically find a platform and set that as spawn origin
- {
- flag.noalign = false;
- droptofloor(flag);
- set_movetype(flag, MOVETYPE_NONE);
- }
-
- InitializeEntity(flag, ctf_DelayedFlagSetup, INITPRIO_SETLOCATION);
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-// NOTE: LEGACY CODE, needs to be re-written!
-
-void havocbot_ctf_calculate_middlepoint()
-{
- entity f;
- vector s = '0 0 0';
- vector fo = '0 0 0';
- int n = 0;
-
- f = ctf_worldflaglist;
- while (f)
- {
- fo = f.origin;
- s = s + fo;
- f = f.ctf_worldflagnext;
- n++;
- }
- if(!n)
- return;
-
- havocbot_middlepoint = s / n;
- havocbot_middlepoint_radius = vlen(fo - havocbot_middlepoint);
-
- havocbot_symmetryaxis_equation = '0 0 0';
- if(n == 2)
- {
- // for symmetrical editing of waypoints
- entity f1 = ctf_worldflaglist;
- entity f2 = f1.ctf_worldflagnext;
- float m = -(f1.origin.y - f2.origin.y) / (f1.origin.x - f2.origin.x);
- float q = havocbot_middlepoint.y - m * havocbot_middlepoint.x;
- havocbot_symmetryaxis_equation.x = m;
- havocbot_symmetryaxis_equation.y = q;
- }
- // store number of flags in this otherwise unused vector component
- havocbot_symmetryaxis_equation.z = n;
-}
-
-
-entity havocbot_ctf_find_flag(entity bot)
-{
- entity f;
- f = ctf_worldflaglist;
- while (f)
- {
- if (CTF_SAMETEAM(bot, f))
- return f;
- f = f.ctf_worldflagnext;
- }
- return NULL;
-}
-
-entity havocbot_ctf_find_enemy_flag(entity bot)
-{
- entity f;
- f = ctf_worldflaglist;
- while (f)
- {
- if(ctf_oneflag)
- {
- if(CTF_DIFFTEAM(bot, f))
- {
- if(f.team)
- {
- if(bot.flagcarried)
- return f;
- }
- else if(!bot.flagcarried)
- return f;
- }
- }
- else if (CTF_DIFFTEAM(bot, f))
- return f;
- f = f.ctf_worldflagnext;
- }
- return NULL;
-}
-
-int havocbot_ctf_teamcount(entity bot, vector org, float tc_radius)
-{
- if (!teamplay)
- return 0;
-
- int c = 0;
-
- FOREACH_CLIENT(IS_PLAYER(it), {
- if(DIFF_TEAM(it, bot) || IS_DEAD(it) || it == bot)
- continue;
-
- if(vdist(it.origin - org, <, tc_radius))
- ++c;
- });
-
- return c;
-}
-
-// unused
-#if 0
-void havocbot_goalrating_ctf_ourflag(entity this, float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if (CTF_SAMETEAM(this, head))
- break;
- head = head.ctf_worldflagnext;
- }
- if (head)
- navigation_routerating(this, head, ratingscale, 10000);
-}
-#endif
-
-void havocbot_goalrating_ctf_ourbase(entity this, float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if (CTF_SAMETEAM(this, head))
- {
- if (this.flagcarried)
- if ((this.flagcarried.cnt || head.cnt) && this.flagcarried.cnt != head.cnt)
- {
- head = head.ctf_worldflagnext; // skip base if it has a different group
- continue;
- }
- break;
- }
- head = head.ctf_worldflagnext;
- }
- if (!head)
- return;
-
- navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemyflag(entity this, float ratingscale)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- if(ctf_oneflag)
- {
- if(CTF_DIFFTEAM(this, head))
- {
- if(head.team)
- {
- if(this.flagcarried)
- break;
- }
- else if(!this.flagcarried)
- break;
- }
- }
- else if(CTF_DIFFTEAM(this, head))
- break;
- head = head.ctf_worldflagnext;
- }
- if (head)
- navigation_routerating(this, head, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_enemybase(entity this, float ratingscale)
-{
- if (!bot_waypoints_for_items)
- {
- havocbot_goalrating_ctf_enemyflag(this, ratingscale);
- return;
- }
-
- entity head;
-
- head = havocbot_ctf_find_enemy_flag(this);
-
- if (!head)
- return;
-
- navigation_routerating(this, head.bot_basewaypoint, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_ourstolenflag(entity this, float ratingscale)
-{
- entity mf;
-
- mf = havocbot_ctf_find_flag(this);
-
- if(mf.ctf_status == FLAG_BASE)
- return;
-
- if(mf.tag_entity)
- navigation_routerating(this, mf.tag_entity, ratingscale, 10000);
-}
-
-void havocbot_goalrating_ctf_droppedflags(entity this, float ratingscale, vector org, float df_radius)
-{
- entity head;
- head = ctf_worldflaglist;
- while (head)
- {
- // flag is out in the field
- if(head.ctf_status != FLAG_BASE)
- if(head.tag_entity==NULL) // dropped
- {
- if(df_radius)
- {
- if(vdist(org - head.origin, <, df_radius))
- navigation_routerating(this, head, ratingscale, 10000);
- }
- else
- navigation_routerating(this, head, ratingscale, 10000);
- }
-
- head = head.ctf_worldflagnext;
- }
-}
-
-void havocbot_goalrating_ctf_carrieritems(entity this, float ratingscale, vector org, float sradius)
-{
- IL_EACH(g_items, it.bot_pickup,
- {
- // gather health and armor only
- if (it.solid)
- if (it.health || it.armorvalue)
- if (vdist(it.origin - org, <, sradius))
- {
- // get the value of the item
- float t = it.bot_pickupevalfunc(this, it) * 0.0001;
- if (t > 0)
- navigation_routerating(this, it, t * ratingscale, 500);
- }
- });
-}
-
-void havocbot_ctf_reset_role(entity this)
-{
- float cdefense, cmiddle, coffense;
- entity mf, ef;
- float c;
-
- if(IS_DEAD(this))
- return;
-
- // Check ctf flags
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- mf = havocbot_ctf_find_flag(this);
- ef = havocbot_ctf_find_enemy_flag(this);
-
- // Retrieve stolen flag
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- // If enemy flag is taken go to the middle to intercept pursuers
- if(ef.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
- return;
- }
-
- // if there is only me on the team switch to offense
- c = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this), { ++c; });
-
- if(c==1)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
- return;
- }
-
- // Evaluate best position to take
- // Count mates on middle position
- cmiddle = havocbot_ctf_teamcount(this, havocbot_middlepoint, havocbot_middlepoint_radius * 0.5);
-
- // Count mates on defense position
- cdefense = havocbot_ctf_teamcount(this, mf.dropped_origin, havocbot_middlepoint_radius * 0.5);
-
- // Count mates on offense position
- coffense = havocbot_ctf_teamcount(this, ef.dropped_origin, havocbot_middlepoint_radius);
-
- if(cdefense<=coffense)
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
- else if(coffense<=cmiddle)
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_OFFENSE);
- else
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
-}
-
-void havocbot_role_ctf_carrier(entity this)
-{
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried == NULL)
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
-
- if(ctf_oneflag)
- havocbot_goalrating_ctf_enemybase(this, 50000);
- else
- havocbot_goalrating_ctf_ourbase(this, 50000);
-
- if(this.health<100)
- havocbot_goalrating_ctf_carrieritems(this, 1000, this.origin, 1000);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
-
- entity head = ctf_worldflaglist;
- while (head)
- {
- if (this.goalentity == head.bot_basewaypoint)
- {
- this.goalentity_lock_timeout = time + 5;
- break;
- }
- head = head.ctf_worldflagnext;
- }
-
- if (this.goalentity)
- this.havocbot_cantfindflag = time + 10;
- else if (time > this.havocbot_cantfindflag)
- {
- // Can't navigate to my own base, suicide!
- // TODO: drop it and wander around
- Damage(this, this, this, 100000, DEATH_KILL.m_id, DMG_NOWEP, this.origin, '0 0 0');
- return;
- }
- }
-}
-
-void havocbot_role_ctf_escort(entity this)
-{
- entity mf, ef;
-
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If enemy flag is back on the base switch to previous role
- ef = havocbot_ctf_find_enemy_flag(this);
- if(ef.ctf_status==FLAG_BASE)
- {
- this.havocbot_role = this.havocbot_previous_role;
- this.havocbot_role_timeout = 0;
- return;
- }
-
- // If the flag carrier reached the base switch to defense
- mf = havocbot_ctf_find_flag(this);
- if(mf.ctf_status!=FLAG_BASE)
- if(vdist(ef.origin - mf.dropped_origin, <, 300))
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_DEFENSE);
- return;
- }
-
- // Set the role timeout if necessary
- if (!this.havocbot_role_timeout)
- {
- this.havocbot_role_timeout = time + random() * 30 + 60;
- }
-
- // If nothing happened just switch to previous role
- if (time > this.havocbot_role_timeout)
- {
- this.havocbot_role = this.havocbot_previous_role;
- this.havocbot_role_timeout = 0;
- return;
- }
-
- // Chase the flag carrier
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
-
- havocbot_goalrating_ctf_enemyflag(this, 30000);
- havocbot_goalrating_ctf_ourstolenflag(this, 40000);
- havocbot_goalrating_items(this, 10000, this.origin, 10000);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-void havocbot_role_ctf_offense(entity this)
-{
- entity mf, ef;
- vector pos;
-
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // Check flags
- mf = havocbot_ctf_find_flag(this);
- ef = havocbot_ctf_find_enemy_flag(this);
-
- // Own flag stolen
- if(mf.ctf_status!=FLAG_BASE)
- {
- if(mf.tag_entity)
- pos = mf.tag_entity.origin;
- else
- pos = mf.origin;
-
- // Try to get it if closer than the enemy base
- if(vlen2(this.origin-ef.dropped_origin)>vlen2(this.origin-pos))
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
- }
-
- // Escort flag carrier
- if(ef.ctf_status!=FLAG_BASE)
- {
- if(ef.tag_entity)
- pos = ef.tag_entity.origin;
- else
- pos = ef.origin;
-
- if(vdist(pos - mf.dropped_origin, >, 700))
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_ESCORT);
- return;
- }
- }
-
- // About to fail, switch to middlefield
- if(this.health<50)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_MIDDLE);
- return;
- }
-
- // Set the role timeout if necessary
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + 120;
-
- if (time > this.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
-
- havocbot_goalrating_ctf_ourstolenflag(this, 50000);
- havocbot_goalrating_ctf_enemybase(this, 20000);
- havocbot_goalrating_items(this, 5000, this.origin, 1000);
- havocbot_goalrating_items(this, 1000, this.origin, 10000);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-// Retriever (temporary role):
-void havocbot_role_ctf_retriever(entity this)
-{
- entity mf;
-
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If flag is back on the base switch to previous role
- mf = havocbot_ctf_find_flag(this);
- if(mf.ctf_status==FLAG_BASE)
- {
- if (mf.enemy == this) // did this bot return the flag?
- navigation_goalrating_timeout_force(this);
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + 20;
-
- if (time > this.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- float rt_radius;
- rt_radius = 10000;
-
- navigation_goalrating_start(this);
-
- havocbot_goalrating_ctf_ourstolenflag(this, 50000);
- havocbot_goalrating_ctf_droppedflags(this, 40000, this.origin, rt_radius);
- havocbot_goalrating_ctf_enemybase(this, 30000);
- havocbot_goalrating_items(this, 500, this.origin, rt_radius);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-void havocbot_role_ctf_middle(entity this)
-{
- entity mf;
-
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- mf = havocbot_ctf_find_flag(this);
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + 10;
-
- if (time > this.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- vector org;
-
- org = havocbot_middlepoint;
- org.z = this.origin.z;
-
- navigation_goalrating_start(this);
-
- havocbot_goalrating_ctf_ourstolenflag(this, 50000);
- havocbot_goalrating_ctf_droppedflags(this, 30000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 10000, org, havocbot_middlepoint_radius * 0.5);
- havocbot_goalrating_items(this, 5000, org, havocbot_middlepoint_radius * 0.5);
- havocbot_goalrating_items(this, 2500, this.origin, 10000);
- havocbot_goalrating_ctf_enemybase(this, 2500);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-void havocbot_role_ctf_defense(entity this)
-{
- entity mf;
-
- if(IS_DEAD(this))
- {
- havocbot_ctf_reset_role(this);
- return;
- }
-
- if (this.flagcarried)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_CARRIER);
- return;
- }
-
- // If own flag was captured
- mf = havocbot_ctf_find_flag(this);
- if(mf.ctf_status!=FLAG_BASE)
- {
- havocbot_role_ctf_setrole(this, HAVOCBOT_CTF_ROLE_RETRIEVER);
- return;
- }
-
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + 30;
-
- if (time > this.havocbot_role_timeout)
- {
- havocbot_ctf_reset_role(this);
- return;
- }
- if (navigation_goalrating_timeout(this))
- {
- vector org = mf.dropped_origin;
-
- navigation_goalrating_start(this);
-
- // if enemies are closer to our base, go there
- entity closestplayer = NULL;
- float distance, bestdistance = 10000;
- FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it), {
- distance = vlen(org - it.origin);
- if(distance<bestdistance)
- {
- closestplayer = it;
- bestdistance = distance;
- }
- });
-
- if(closestplayer)
- if(DIFF_TEAM(closestplayer, this))
- if(vdist(org - this.origin, >, 1000))
- if(checkpvs(this.origin,closestplayer)||random()<0.5)
- havocbot_goalrating_ctf_ourbase(this, 30000);
-
- havocbot_goalrating_ctf_ourstolenflag(this, 20000);
- havocbot_goalrating_ctf_droppedflags(this, 20000, org, havocbot_middlepoint_radius);
- havocbot_goalrating_enemyplayers(this, 15000, org, havocbot_middlepoint_radius);
- havocbot_goalrating_items(this, 10000, org, havocbot_middlepoint_radius);
- havocbot_goalrating_items(this, 5000, this.origin, 10000);
-
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-void havocbot_role_ctf_setrole(entity bot, int role)
-{
- string s = "(null)";
- switch(role)
- {
- case HAVOCBOT_CTF_ROLE_CARRIER:
- s = "carrier";
- bot.havocbot_role = havocbot_role_ctf_carrier;
- bot.havocbot_role_timeout = 0;
- bot.havocbot_cantfindflag = time + 10;
- if (bot.havocbot_previous_role != bot.havocbot_role)
- navigation_goalrating_timeout_force(bot);
- break;
- case HAVOCBOT_CTF_ROLE_DEFENSE:
- s = "defense";
- bot.havocbot_role = havocbot_role_ctf_defense;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_MIDDLE:
- s = "middle";
- bot.havocbot_role = havocbot_role_ctf_middle;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_OFFENSE:
- s = "offense";
- bot.havocbot_role = havocbot_role_ctf_offense;
- bot.havocbot_role_timeout = 0;
- break;
- case HAVOCBOT_CTF_ROLE_RETRIEVER:
- s = "retriever";
- bot.havocbot_previous_role = bot.havocbot_role;
- bot.havocbot_role = havocbot_role_ctf_retriever;
- bot.havocbot_role_timeout = time + 10;
- if (bot.havocbot_previous_role != bot.havocbot_role)
- navigation_goalrating_timeout_expire(bot, 2);
- break;
- case HAVOCBOT_CTF_ROLE_ESCORT:
- s = "escort";
- bot.havocbot_previous_role = bot.havocbot_role;
- bot.havocbot_role = havocbot_role_ctf_escort;
- bot.havocbot_role_timeout = time + 30;
- if (bot.havocbot_previous_role != bot.havocbot_role)
- navigation_goalrating_timeout_expire(bot, 2);
- break;
- }
- LOG_TRACE(bot.netname, " switched to ", s);
-}
-
-
-// ==============
-// Hook Functions
-// ==============
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerPreThink)
-{
- entity player = M_ARGV(0, entity);
-
- int t = 0, t2 = 0, t3 = 0;
- bool b1 = false, b2 = false, b3 = false, b4 = false, b5 = false; // TODO: kill this, we WANT to show the other flags, somehow! (note: also means you don't see if you're FC)
-
- // initially clear items so they can be set as necessary later.
- STAT(CTF_FLAGSTATUS, player) &= ~(CTF_RED_FLAG_CARRYING | CTF_RED_FLAG_TAKEN | CTF_RED_FLAG_LOST
- | CTF_BLUE_FLAG_CARRYING | CTF_BLUE_FLAG_TAKEN | CTF_BLUE_FLAG_LOST
- | CTF_YELLOW_FLAG_CARRYING | CTF_YELLOW_FLAG_TAKEN | CTF_YELLOW_FLAG_LOST
- | CTF_PINK_FLAG_CARRYING | CTF_PINK_FLAG_TAKEN | CTF_PINK_FLAG_LOST
- | CTF_NEUTRAL_FLAG_CARRYING | CTF_NEUTRAL_FLAG_TAKEN | CTF_NEUTRAL_FLAG_LOST
- | CTF_FLAG_NEUTRAL | CTF_SHIELDED | CTF_STALEMATE);
-
- // scan through all the flags and notify the client about them
- for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
- {
- if(flag.team == NUM_TEAM_1 && !b1) { b1 = true; t = CTF_RED_FLAG_CARRYING; t2 = CTF_RED_FLAG_TAKEN; t3 = CTF_RED_FLAG_LOST; }
- if(flag.team == NUM_TEAM_2 && !b2) { b2 = true; t = CTF_BLUE_FLAG_CARRYING; t2 = CTF_BLUE_FLAG_TAKEN; t3 = CTF_BLUE_FLAG_LOST; }
- if(flag.team == NUM_TEAM_3 && !b3) { b3 = true; t = CTF_YELLOW_FLAG_CARRYING; t2 = CTF_YELLOW_FLAG_TAKEN; t3 = CTF_YELLOW_FLAG_LOST; }
- if(flag.team == NUM_TEAM_4 && !b4) { b4 = true; t = CTF_PINK_FLAG_CARRYING; t2 = CTF_PINK_FLAG_TAKEN; t3 = CTF_PINK_FLAG_LOST; }
- if(flag.team == 0 && !b5) { b5 = true; t = CTF_NEUTRAL_FLAG_CARRYING; t2 = CTF_NEUTRAL_FLAG_TAKEN; t3 = CTF_NEUTRAL_FLAG_LOST; STAT(CTF_FLAGSTATUS, player) |= CTF_FLAG_NEUTRAL; }
-
- switch(flag.ctf_status)
- {
- case FLAG_PASSING:
- case FLAG_CARRY:
- {
- if((flag.owner == player) || (flag.pass_sender == player))
- STAT(CTF_FLAGSTATUS, player) |= t; // carrying: player is currently carrying the flag
- else
- STAT(CTF_FLAGSTATUS, player) |= t2; // taken: someone else is carrying the flag
- break;
- }
- case FLAG_DROPPED:
- {
- STAT(CTF_FLAGSTATUS, player) |= t3; // lost: the flag is dropped somewhere on the map
- break;
- }
- }
- }
-
- // item for stopping players from capturing the flag too often
- if(player.ctf_captureshielded)
- STAT(CTF_FLAGSTATUS, player) |= CTF_SHIELDED;
-
- if(ctf_stalemate)
- STAT(CTF_FLAGSTATUS, player) |= CTF_STALEMATE;
-
- // update the health of the flag carrier waypointsprite
- if(player.wps_flagcarrier)
- WaypointSprite_UpdateHealth(player.wps_flagcarrier, '1 0 0' * healtharmor_maxdamage(player.health, player.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id));
-}
-
-MUTATOR_HOOKFUNCTION(ctf, Damage_Calculate) // for changing damage and force values that are applied to players in g_damage.qc
-{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, entity);
- float frag_damage = M_ARGV(4, float);
- vector frag_force = M_ARGV(6, vector);
-
- if(frag_attacker.flagcarried) // if the attacker is a flagcarrier
- {
- if(frag_target == frag_attacker) // damage done to yourself
- {
- frag_damage *= autocvar_g_ctf_flagcarrier_selfdamagefactor;
- frag_force *= autocvar_g_ctf_flagcarrier_selfforcefactor;
- }
- else // damage done to everyone else
- {
- frag_damage *= autocvar_g_ctf_flagcarrier_damagefactor;
- frag_force *= autocvar_g_ctf_flagcarrier_forcefactor;
- }
-
- M_ARGV(4, float) = frag_damage;
- M_ARGV(6, vector) = frag_force;
- }
- else if(frag_target.flagcarried && !IS_DEAD(frag_target) && CTF_DIFFTEAM(frag_target, frag_attacker)) // if the target is a flagcarrier
- {
- if(autocvar_g_ctf_flagcarrier_auto_helpme_damage > ('1 0 0' * healtharmor_maxdamage(frag_target.health, frag_target.armorvalue, autocvar_g_balance_armor_blockpercent, DEATH_WEAPON.m_id)))
- if(time > frag_target.wps_helpme_time + autocvar_g_ctf_flagcarrier_auto_helpme_time)
- {
- frag_target.wps_helpme_time = time;
- WaypointSprite_HelpMePing(frag_target.wps_flagcarrier);
- }
- // todo: add notification for when flag carrier needs help?
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerDies)
-{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, entity);
-
- if((frag_attacker != frag_target) && (IS_PLAYER(frag_attacker)) && (frag_target.flagcarried))
- {
- GameRules_scoring_add_team(frag_attacker, SCORE, ((SAME_TEAM(frag_attacker, frag_target)) ? -autocvar_g_ctf_score_kill : autocvar_g_ctf_score_kill));
- GameRules_scoring_add(frag_attacker, CTF_FCKILLS, 1);
- }
-
- if(frag_target.flagcarried)
- {
- entity tmp_entity = frag_target.flagcarried;
- ctf_Handle_Throw(frag_target, NULL, DROP_NORMAL);
- tmp_entity.ctf_dropper = NULL;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GiveFragsForKill)
-{
- M_ARGV(2, float) = 0; // frag score
- return (autocvar_g_ctf_ignore_frags); // no frags counted in ctf if this is true
-}
-
-void ctf_RemovePlayer(entity player)
-{
- if(player.flagcarried)
- { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
-
- for(entity flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
- {
- if(flag.pass_sender == player) { flag.pass_sender = NULL; }
- if(flag.pass_target == player) { flag.pass_target = NULL; }
- if(flag.ctf_dropper == player) { flag.ctf_dropper = NULL; }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, MakePlayerObserver)
-{
- entity player = M_ARGV(0, entity);
-
- ctf_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, ClientDisconnect)
-{
- entity player = M_ARGV(0, entity);
-
- ctf_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, ClientConnect)
-{
- if(!autocvar_g_ctf_leaderboard)
- return;
-
- entity player = M_ARGV(0, entity);
-
- if(IS_REAL_CLIENT(player))
- {
- for(int i = 1; i <= RANKINGS_CNT; ++i)
- {
- race_SendRankings(i, 0, 0, MSG_ONE);
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GetPressedKeys)
-{
- if(!autocvar_g_ctf_leaderboard)
- return;
-
- entity player = M_ARGV(0, entity);
-
- if(CS(player).cvar_cl_allow_uidtracking == 1 && CS(player).cvar_cl_allow_uid2name == 1)
- {
- if (!player.stored_netname)
- player.stored_netname = strzone(uid2name(player.crypto_idfp));
- if(player.stored_netname != player.netname)
- {
- db_put(ServerProgsDB, strcat("/uid2name/", player.crypto_idfp), player.netname);
- strunzone(player.stored_netname);
- player.stored_netname = strzone(player.netname);
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PortalTeleport)
-{
- entity player = M_ARGV(0, entity);
-
- if(player.flagcarried)
- if(!autocvar_g_ctf_portalteleport)
- { ctf_Handle_Throw(player, NULL, DROP_NORMAL); }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, PlayerUseKey)
-{
- if(MUTATOR_RETURNVALUE || game_stopped) return;
-
- entity player = M_ARGV(0, entity);
-
- if((time > player.throw_antispam) && !IS_DEAD(player) && !player.speedrunning && (!player.vehicle || autocvar_g_ctf_allow_vehicle_touch))
- {
- // pass the flag to a team mate
- if(autocvar_g_ctf_pass)
- {
- entity head, closest_target = NULL;
- head = WarpZone_FindRadius(player.origin, autocvar_g_ctf_pass_radius, true);
-
- while(head) // find the closest acceptable target to pass to
- {
- if(IS_PLAYER(head) && !IS_DEAD(head))
- if(head != player && SAME_TEAM(head, player))
- if(!head.speedrunning && !head.vehicle)
- {
- // if it's a player, use the view origin as reference (stolen from RadiusDamage functions in g_damage.qc)
- vector head_center = WarpZone_UnTransformOrigin(head, CENTER_OR_VIEWOFS(head));
- vector passer_center = CENTER_OR_VIEWOFS(player);
-
- if(ctf_CheckPassDirection(head_center, passer_center, player.v_angle, head.WarpZone_findradius_nearest))
- {
- if(autocvar_g_ctf_pass_request && !player.flagcarried && head.flagcarried)
- {
- if(IS_BOT_CLIENT(head))
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
- ctf_Handle_Throw(head, player, DROP_PASS);
- }
- else
- {
- Send_Notification(NOTIF_ONE, head, MSG_CENTER, CENTER_CTF_PASS_REQUESTED, player.netname);
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_PASS_REQUESTING, head.netname);
- }
- player.throw_antispam = time + autocvar_g_ctf_pass_wait;
- return true;
- }
- else if(player.flagcarried && !head.flagcarried)
- {
- if(closest_target)
- {
- vector closest_target_center = WarpZone_UnTransformOrigin(closest_target, CENTER_OR_VIEWOFS(closest_target));
- if(vlen2(passer_center - head_center) < vlen2(passer_center - closest_target_center))
- { closest_target = head; }
- }
- else { closest_target = head; }
- }
- }
- }
- head = head.chain;
- }
-
- if(closest_target) { ctf_Handle_Throw(player, closest_target, DROP_PASS); return true; }
- }
-
- // throw the flag in front of you
- if(autocvar_g_ctf_throw && player.flagcarried)
- {
- if(player.throw_count == -1)
- {
- if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_delay)
- {
- player.throw_prevtime = time;
- player.throw_count = 1;
- ctf_Handle_Throw(player, NULL, DROP_THROW);
- return true;
- }
- else
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_CTF_FLAG_THROW_PUNISH, rint((player.throw_prevtime + autocvar_g_ctf_throw_punish_delay) - time));
- return false;
- }
- }
- else
- {
- if(time > player.throw_prevtime + autocvar_g_ctf_throw_punish_time) { player.throw_count = 1; }
- else { player.throw_count += 1; }
- if(player.throw_count >= autocvar_g_ctf_throw_punish_count) { player.throw_count = -1; }
-
- player.throw_prevtime = time;
- ctf_Handle_Throw(player, NULL, DROP_THROW);
- return true;
- }
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, HelpMePing)
-{
- entity player = M_ARGV(0, entity);
-
- if(player.wps_flagcarrier) // update the flagcarrier waypointsprite with "NEEDING HELP" notification
- {
- player.wps_helpme_time = time;
- WaypointSprite_HelpMePing(player.wps_flagcarrier);
- }
- else // create a normal help me waypointsprite
- {
- WaypointSprite_Spawn(WP_Helpme, waypointsprite_deployed_lifetime, waypointsprite_limitedrange, player, FLAG_WAYPOINT_OFFSET, NULL, player.team, player, wps_helpme, false, RADARICON_HELPME);
- WaypointSprite_Ping(player.wps_helpme);
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, VehicleEnter)
-{
- entity player = M_ARGV(0, entity);
- entity veh = M_ARGV(1, entity);
-
- if(player.flagcarried)
- {
- if(!autocvar_g_ctf_allow_vehicle_carry && !autocvar_g_ctf_allow_vehicle_touch)
- {
- ctf_Handle_Throw(player, NULL, DROP_NORMAL);
- }
- else
- {
- player.flagcarried.nodrawtoclient = player; // hide the flag from the driver
- setattachment(player.flagcarried, veh, "");
- setorigin(player.flagcarried, VEHICLE_FLAG_OFFSET);
- player.flagcarried.scale = VEHICLE_FLAG_SCALE;
- //player.flagcarried.angles = '0 0 0';
- }
- return true;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, VehicleExit)
-{
- entity player = M_ARGV(0, entity);
-
- if(player.flagcarried)
- {
- setattachment(player.flagcarried, player, "");
- setorigin(player.flagcarried, FLAG_CARRY_OFFSET);
- player.flagcarried.scale = FLAG_SCALE;
- player.flagcarried.angles = '0 0 0';
- player.flagcarried.nodrawtoclient = NULL;
- return true;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, AbortSpeedrun)
-{
- entity player = M_ARGV(0, entity);
-
- if(player.flagcarried)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_NUM(player.flagcarried.team, INFO_CTF_FLAGRETURN_ABORTRUN));
- ctf_RespawnFlag(player.flagcarried);
- return true;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, MatchEnd)
-{
- entity flag; // temporary entity for the search method
-
- for(flag = ctf_worldflaglist; flag; flag = flag.ctf_worldflagnext)
- {
- switch(flag.ctf_status)
- {
- case FLAG_DROPPED:
- case FLAG_PASSING:
- {
- // lock the flag, game is over
- set_movetype(flag, MOVETYPE_NONE);
- flag.takedamage = DAMAGE_NO;
- flag.solid = SOLID_NOT;
- flag.nextthink = false; // stop thinking
-
- //dprint("stopping the ", flag.netname, " from moving.\n");
- break;
- }
-
- default:
- case FLAG_BASE:
- case FLAG_CARRY:
- {
- // do nothing for these flags
- break;
- }
- }
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, HavocBot_ChooseRole)
-{
- entity bot = M_ARGV(0, entity);
-
- havocbot_ctf_reset_role(bot);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, CheckAllowedTeams)
-{
- //M_ARGV(0, float) = ctf_teams;
- M_ARGV(1, string) = "ctf_team";
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ctf, SpectateCopy)
-{
- entity spectatee = M_ARGV(0, entity);
- entity client = M_ARGV(1, entity);
-
- STAT(CTF_FLAGSTATUS, client) = STAT(CTF_FLAGSTATUS, spectatee);
-}
-
-MUTATOR_HOOKFUNCTION(ctf, GetRecords)
-{
- int record_page = M_ARGV(0, int);
- string ret_string = M_ARGV(1, string);
-
- for(int i = record_page * 200; i < MapInfo_count && i < record_page * 200 + 200; ++i)
- {
- if (MapInfo_Get_ByID(i))
- {
- float r = stof(db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/time")));
-
- if(!r)
- continue;
-
- // TODO: uid2name
- string h = db_get(ServerProgsDB, strcat(MapInfo_Map_bspname, "/captimerecord/netname"));
- ret_string = strcat(ret_string, strpad(32, MapInfo_Map_bspname), " ", strpad(-6, ftos_decimals(r, 2)), " ", h, "\n");
- }
- }
-
- M_ARGV(1, string) = ret_string;
-}
-
-bool superspec_Spectate(entity this, entity targ); // TODO
-void superspec_msg(string _center_title, string _con_title, entity _to, string _msg, float _spamlevel); // TODO
-MUTATOR_HOOKFUNCTION(ctf, SV_ParseClientCommand)
-{
- entity player = M_ARGV(0, entity);
- string cmd_name = M_ARGV(1, string);
- int cmd_argc = M_ARGV(2, int);
-
- if(IS_PLAYER(player) || MUTATOR_RETURNVALUE || !cvar("g_superspectate")) { return false; }
-
- if(cmd_name == "followfc")
- {
- if(!g_ctf)
- return true;
-
- int _team = 0;
- bool found = false;
-
- if(cmd_argc == 2)
- {
- switch(argv(1))
- {
- case "red": if(ctf_teams & BIT(0)) _team = NUM_TEAM_1; break;
- case "blue": if(ctf_teams & BIT(1)) _team = NUM_TEAM_2; break;
- case "yellow": if(ctf_teams & BIT(2)) _team = NUM_TEAM_3; break;
- case "pink": if(ctf_teams & BIT(3)) _team = NUM_TEAM_4; break;
- }
- }
-
- FOREACH_CLIENT(IS_PLAYER(it), {
- if(it.flagcarried && (it.team == _team || _team == 0))
- {
- found = true;
- if(_team == 0 && IS_SPEC(player) && player.enemy == it)
- continue; // already spectating this fc, try another
- return superspec_Spectate(player, it);
- }
- });
-
- if(!found)
- superspec_msg("", "", player, "No active flag carrier\n", 1);
- return true;
- }
-}
-
-MUTATOR_HOOKFUNCTION(ctf, DropSpecialItems)
-{
- entity frag_target = M_ARGV(0, entity);
-
- if(frag_target.flagcarried)
- ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
-}
-
-
-// ==========
-// Spawnfuncs
-// ==========
-
-/*QUAKED spawnfunc_item_flag_team1 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team one (Red).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red and blue as skins 0 and 1...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team1)
-{
- if(!g_ctf) { delete(this); return; }
-
- ctf_FlagSetup(NUM_TEAM_1, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team2 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team two (Blue).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red and blue as skins 0 and 1...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team2)
-{
- if(!g_ctf) { delete(this); return; }
-
- ctf_FlagSetup(NUM_TEAM_2, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team3 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team three (Yellow).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team3)
-{
- if(!g_ctf) { delete(this); return; }
-
- ctf_FlagSetup(NUM_TEAM_3, this);
-}
-
-/*QUAKED spawnfunc_item_flag_team4 (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag for team four (Pink).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_team4)
-{
- if(!g_ctf) { delete(this); return; }
-
- ctf_FlagSetup(NUM_TEAM_4, this);
-}
-
-/*QUAKED spawnfunc_item_flag_neutral (0 0.5 0.8) (-48 -48 -37) (48 48 37)
-CTF flag (Neutral).
-Keys:
-"angle" Angle the flag will point (minus 90 degrees)...
-"model" model to use, note this needs red, blue yellow and pink as skins 0, 1, 2 and 3...
-"noise" sound played when flag is picked up...
-"noise1" sound played when flag is returned by a teammate...
-"noise2" sound played when flag is captured...
-"noise3" sound played when flag is lost in the field and respawns itself...
-"noise4" sound played when flag is dropped by a player...
-"noise5" sound played when flag touches the ground... */
-spawnfunc(item_flag_neutral)
-{
- if(!g_ctf) { delete(this); return; }
- if(!cvar("g_ctf_oneflag")) { delete(this); return; }
-
- ctf_FlagSetup(0, this);
-}
-
-/*QUAKED spawnfunc_ctf_team (0 .5 .8) (-16 -16 -24) (16 16 32)
-Team declaration for CTF gameplay, this allows you to decide what team names and control point models are used in your map.
-Note: If you use spawnfunc_ctf_team entities you must define at least 2! However, unlike domination, you don't need to make a blank one too.
-Keys:
-"netname" Name of the team (for example Red, Blue, Green, Yellow, Life, Death, Offense, Defense, etc)...
-"cnt" Scoreboard color of the team (for example 4 is red and 13 is blue)... */
-spawnfunc(ctf_team)
-{
- if(!g_ctf) { delete(this); return; }
-
- this.classname = "ctf_team";
- this.team = this.cnt + 1;
-}
-
-// compatibility for quake maps
-spawnfunc(team_CTF_redflag) { spawnfunc_item_flag_team1(this); }
-spawnfunc(team_CTF_blueflag) { spawnfunc_item_flag_team2(this); }
-spawnfunc(info_player_team1);
-spawnfunc(team_CTF_redplayer) { spawnfunc_info_player_team1(this); }
-spawnfunc(team_CTF_redspawn) { spawnfunc_info_player_team1(this); }
-spawnfunc(info_player_team2);
-spawnfunc(team_CTF_blueplayer) { spawnfunc_info_player_team2(this); }
-spawnfunc(team_CTF_bluespawn) { spawnfunc_info_player_team2(this); }
-
-spawnfunc(team_CTF_neutralflag) { spawnfunc_item_flag_neutral(this); }
-spawnfunc(team_neutralobelisk) { spawnfunc_item_flag_neutral(this); }
-
-// compatibility for wop maps
-spawnfunc(team_redplayer) { spawnfunc_info_player_team1(this); }
-spawnfunc(team_blueplayer) { spawnfunc_info_player_team2(this); }
-spawnfunc(team_ctl_redlolly) { spawnfunc_item_flag_team1(this); }
-spawnfunc(team_CTL_redlolly) { spawnfunc_item_flag_team1(this); }
-spawnfunc(team_ctl_bluelolly) { spawnfunc_item_flag_team2(this); }
-spawnfunc(team_CTL_bluelolly) { spawnfunc_item_flag_team2(this); }
-
-
-// ==============
-// Initialization
-// ==============
-
-// scoreboard setup
-void ctf_ScoreRules(int teams)
-{
- CheckAllowedTeams(NULL);
- GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
- field_team(ST_CTF_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
- field(SP_CTF_CAPS, "caps", SFL_SORT_PRIO_SECONDARY);
- field(SP_CTF_CAPTIME, "captime", SFL_LOWER_IS_BETTER | SFL_TIME);
- field(SP_CTF_PICKUPS, "pickups", 0);
- field(SP_CTF_FCKILLS, "fckills", 0);
- field(SP_CTF_RETURNS, "returns", 0);
- field(SP_CTF_DROPS, "drops", SFL_LOWER_IS_BETTER);
- });
-}
-
-// code from here on is just to support maps that don't have flag and team entities
-void ctf_SpawnTeam (string teamname, int teamcolor)
-{
- entity this = new_pure(ctf_team);
- this.netname = teamname;
- this.cnt = teamcolor - 1;
- this.spawnfunc_checked = true;
- this.team = teamcolor;
-}
-
-void ctf_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
-{
- ctf_teams = 0;
-
- entity tmp_entity;
- for(tmp_entity = ctf_worldflaglist; tmp_entity; tmp_entity = tmp_entity.ctf_worldflagnext)
- {
- //if(tmp_entity.team == NUM_TEAM_3) { ctf_teams = max(3, ctf_teams); }
- //if(tmp_entity.team == NUM_TEAM_4) { ctf_teams = max(4, ctf_teams); }
-
- switch(tmp_entity.team)
- {
- case NUM_TEAM_1: BITSET_ASSIGN(ctf_teams, BIT(0)); break;
- case NUM_TEAM_2: BITSET_ASSIGN(ctf_teams, BIT(1)); break;
- case NUM_TEAM_3: BITSET_ASSIGN(ctf_teams, BIT(2)); break;
- case NUM_TEAM_4: BITSET_ASSIGN(ctf_teams, BIT(3)); break;
- }
- if(tmp_entity.team == 0) { ctf_oneflag = true; }
- }
-
- havocbot_ctf_calculate_middlepoint();
-
- if(NumTeams(ctf_teams) < 2) // somehow, there's not enough flags!
- {
- ctf_teams = 0; // so set the default red and blue teams
- BITSET_ASSIGN(ctf_teams, BIT(0));
- BITSET_ASSIGN(ctf_teams, BIT(1));
- }
-
- //ctf_teams = bound(2, ctf_teams, 4);
-
- // if no teams are found, spawn defaults
- if(find(NULL, classname, "ctf_team") == NULL)
- {
- LOG_TRACE("No \"ctf_team\" entities found on this map, creating them anyway.");
- if(ctf_teams & BIT(0))
- ctf_SpawnTeam("Red", NUM_TEAM_1);
- if(ctf_teams & BIT(1))
- ctf_SpawnTeam("Blue", NUM_TEAM_2);
- if(ctf_teams & BIT(2))
- ctf_SpawnTeam("Yellow", NUM_TEAM_3);
- if(ctf_teams & BIT(3))
- ctf_SpawnTeam("Pink", NUM_TEAM_4);
- }
-
- ctf_ScoreRules(ctf_teams);
-}
-
-void ctf_Initialize()
-{
- ctf_captimerecord = stof(db_get(ServerProgsDB, strcat(GetMapname(), "/captimerecord/time")));
-
- ctf_captureshield_min_negscore = autocvar_g_ctf_shield_min_negscore;
- ctf_captureshield_max_ratio = autocvar_g_ctf_shield_max_ratio;
- ctf_captureshield_force = autocvar_g_ctf_shield_force;
-
- InitializeEntity(NULL, ctf_DelayedInit, INITPRIO_GAMETYPE);
-}
+++ /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))
-#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)
-{
- STAT(DOM_TOTAL_PPS, e) = total_pps;
- STAT(DOM_PPS_RED, e) = pps_red;
- STAT(DOM_PPS_BLUE, e) = pps_blue;
- if(domination_teams >= 3)
- STAT(DOM_PPS_YELLOW, e) = pps_yellow;
- if(domination_teams >= 4)
- STAT(DOM_PPS_PINK, e) = pps_pink;
-}
-
-void dompoint_captured(entity this)
-{
- float old_delay, old_team, real_team;
-
- // now that the delay has expired, switch to the latest team to lay claim to this point
- entity head = this.owner;
-
- real_team = this.cnt;
- this.cnt = -1;
-
- dom_EventLog("taken", this.team, this.dmg_inflictor);
- this.dmg_inflictor = NULL;
-
- this.goalentity = head;
- this.model = head.mdl;
- this.modelindex = head.dmg;
- this.skin = head.skin;
-
- float points, wait_time;
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = this.frags;
- if (autocvar_g_domination_point_rate)
- wait_time = autocvar_g_domination_point_rate;
- else
- wait_time = this.wait;
-
- if(domination_roundbased)
- bprint(sprintf("^3%s^3%s\n", head.netname, this.message));
- else
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_DOMINATION_CAPTURE_TIME, head.netname, this.message, points, wait_time);
-
- if(this.enemy.playerid == this.enemy_playerid)
- GameRules_scoring_add(this.enemy, DOM_TAKES, 1);
- else
- this.enemy = NULL;
-
- if (head.noise != "")
- if(this.enemy)
- _sound(this.enemy, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
- else
- _sound(this, CH_TRIGGER, head.noise, VOL_BASE, ATTEN_NORM);
- if (head.noise1 != "")
- play2all(head.noise1);
-
- this.delay = time + wait_time;
-
- // do trigger work
- old_delay = this.delay;
- old_team = this.team;
- this.team = real_team;
- this.delay = 0;
- SUB_UseTargets (this, this, NULL);
- this.delay = old_delay;
- this.team = old_team;
-
- entity msg = WP_DomNeut;
- switch(real_team)
- {
- case NUM_TEAM_1: msg = WP_DomRed; break;
- case NUM_TEAM_2: msg = WP_DomBlue; break;
- case NUM_TEAM_3: msg = WP_DomYellow; break;
- case NUM_TEAM_4: msg = WP_DomPink; break;
- }
-
- WaypointSprite_UpdateSprites(this.sprite, msg, WP_Null, WP_Null);
-
- total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
- IL_EACH(g_dompoints, true,
- {
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = it.frags;
- if (autocvar_g_domination_point_rate)
- wait_time = autocvar_g_domination_point_rate;
- else
- wait_time = it.wait;
- switch(it.goalentity.team)
- {
- case NUM_TEAM_1: pps_red += points/wait_time; break;
- case NUM_TEAM_2: pps_blue += points/wait_time; break;
- case NUM_TEAM_3: pps_yellow += points/wait_time; break;
- case NUM_TEAM_4: pps_pink += points/wait_time; break;
- }
- total_pps += points/wait_time;
- });
-
- WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, colormapPaletteColor(this.goalentity.team - 1, 0));
- WaypointSprite_Ping(this.sprite);
-
- this.captime = time;
-
- FOREACH_CLIENT(IS_REAL_CLIENT(it), { set_dom_state(it); });
-}
-
-void AnimateDomPoint(entity this)
-{
- if(this.pain_finished > time)
- return;
- this.pain_finished = time + this.t_width;
- if(this.nextthink > this.pain_finished)
- this.nextthink = this.pain_finished;
-
- this.frame = this.frame + 1;
- if(this.frame > this.t_length)
- this.frame = 0;
-}
-
-void dompointthink(entity this)
-{
- float fragamt;
-
- this.nextthink = time + 0.1;
-
- //this.frame = this.frame + 1;
- //if(this.frame > 119)
- // this.frame = 0;
- AnimateDomPoint(this);
-
- // give points
-
- if (game_stopped || this.delay > time || time < game_starttime) // game has ended, don't keep giving points
- return;
-
- if(autocvar_g_domination_point_rate)
- this.delay = time + autocvar_g_domination_point_rate;
- else
- this.delay = time + this.wait;
-
- // give credit to the team
- // NOTE: this defaults to 0
- if (!domination_roundbased)
- if (this.goalentity.netname != "")
- {
- if(autocvar_g_domination_point_amt)
- fragamt = autocvar_g_domination_point_amt;
- else
- fragamt = this.frags;
- TeamScore_AddToTeam(this.goalentity.team, ST_SCORE, fragamt);
- TeamScore_AddToTeam(this.goalentity.team, ST_DOM_TICKS, fragamt);
-
- // give credit to the individual player, if he is still there
- if (this.enemy.playerid == this.enemy_playerid)
- {
- GameRules_scoring_add(this.enemy, SCORE, fragamt);
- GameRules_scoring_add(this.enemy, DOM_TICKS, fragamt);
- }
- else
- this.enemy = NULL;
- }
-}
-
-void dompointtouch(entity this, entity toucher)
-{
- if (!IS_PLAYER(toucher))
- return;
- if (toucher.health < 1)
- return;
-
- if(round_handler_IsActive() && !round_handler_IsRoundStarted())
- return;
-
- if(time < this.captime + 0.3)
- return;
-
- // only valid teams can claim it
- entity head = find(NULL, classname, "dom_team");
- while (head && head.team != toucher.team)
- head = find(head, classname, "dom_team");
- if (!head || head.netname == "" || head == this.goalentity)
- return;
-
- // delay capture
-
- this.team = this.goalentity.team; // this stores the PREVIOUS team!
-
- this.cnt = toucher.team;
- this.owner = head; // team to switch to after the delay
- this.dmg_inflictor = toucher;
-
- // this.state = 1;
- // this.delay = time + cvar("g_domination_point_capturetime");
- //this.nextthink = time + cvar("g_domination_point_capturetime");
- //this.think = dompoint_captured;
-
- // go to neutral team in the mean time
- head = find(NULL, classname, "dom_team");
- while (head && head.netname != "")
- head = find(head, classname, "dom_team");
- if(head == NULL)
- return;
-
- WaypointSprite_UpdateSprites(this.sprite, WP_DomNeut, WP_Null, WP_Null);
- WaypointSprite_UpdateTeamRadar(this.sprite, RADARICON_DOMPOINT, '0 1 1');
- WaypointSprite_Ping(this.sprite);
-
- this.goalentity = head;
- this.model = head.mdl;
- this.modelindex = head.dmg;
- this.skin = head.skin;
-
- this.enemy = toucher; // individual player scoring
- this.enemy_playerid = toucher.playerid;
- dompoint_captured(this);
-}
-
-void dom_controlpoint_setup(entity this)
-{
- entity head;
- // find the spawnfunc_dom_team representing unclaimed points
- head = find(NULL, classname, "dom_team");
- while(head && head.netname != "")
- head = find(head, classname, "dom_team");
- if (!head)
- objerror(this, "no spawnfunc_dom_team with netname \"\" found\n");
-
- // copy important properties from spawnfunc_dom_team entity
- this.goalentity = head;
- _setmodel(this, head.mdl); // precision already set
- this.skin = head.skin;
-
- this.cnt = -1;
-
- if(this.message == "")
- this.message = " has captured a control point";
-
- if(this.frags <= 0)
- this.frags = 1;
- if(this.wait <= 0)
- this.wait = 5;
-
- float points, waittime;
- if (autocvar_g_domination_point_amt)
- points = autocvar_g_domination_point_amt;
- else
- points = this.frags;
- if (autocvar_g_domination_point_rate)
- waittime = autocvar_g_domination_point_rate;
- else
- waittime = this.wait;
-
- total_pps += points/waittime;
-
- if(!this.t_width)
- this.t_width = 0.02; // frame animation rate
- if(!this.t_length)
- this.t_length = 239; // maximum frame
-
- setthink(this, dompointthink);
- this.nextthink = time;
- settouch(this, dompointtouch);
- this.solid = SOLID_TRIGGER;
- if(!this.flags & FL_ITEM)
- IL_PUSH(g_items, this);
- this.flags = FL_ITEM;
- setsize(this, '-32 -32 -32', '32 32 32');
- setorigin(this, this.origin + '0 0 20');
- droptofloor(this);
-
- waypoint_spawnforitem(this);
- WaypointSprite_SpawnFixed(WP_DomNeut, this.origin + '0 0 32', this, sprite, RADARICON_DOMPOINT);
-}
-
-float total_controlpoints;
-void Domination_count_controlpoints()
-{
- total_controlpoints = redowned = blueowned = yellowowned = pinkowned = 0;
- IL_EACH(g_dompoints, true,
- {
- ++total_controlpoints;
- redowned += (it.goalentity.team == NUM_TEAM_1);
- blueowned += (it.goalentity.team == NUM_TEAM_2);
- yellowowned += (it.goalentity.team == NUM_TEAM_3);
- pinkowned += (it.goalentity.team == NUM_TEAM_4);
- });
-}
-
-float Domination_GetWinnerTeam()
-{
- float winner_team = 0;
- if(redowned == total_controlpoints)
- winner_team = NUM_TEAM_1;
- if(blueowned == total_controlpoints)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
- }
- if(yellowowned == total_controlpoints)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
- }
- if(pinkowned == total_controlpoints)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
- return winner_team;
- return -1; // no control points left?
-}
-
-#define DOM_OWNED_CONTROLPOINTS() ((redowned > 0) + (blueowned > 0) + (yellowowned > 0) + (pinkowned > 0))
-#define DOM_OWNED_CONTROLPOINTS_OK() (DOM_OWNED_CONTROLPOINTS() < total_controlpoints)
-float Domination_CheckWinner()
-{
- if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
-
- game_stopped = true;
- round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
- return 1;
- }
-
- Domination_count_controlpoints();
-
- float winner_team = Domination_GetWinnerTeam();
-
- if(winner_team == -1)
- return 0;
-
- if(winner_team > 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
- TeamScore_AddToTeam(winner_team, ST_DOM_CAPS, +1);
- }
- else if(winner_team == -1)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
- }
-
- game_stopped = true;
- round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
-
- return 1;
-}
-
-float Domination_CheckPlayers()
-{
- return 1;
-}
-
-void Domination_RoundStart()
-{
- FOREACH_CLIENT(IS_PLAYER(it), { it.player_blocked = false; });
-}
-
-//go to best items, or control points you don't own
-void havocbot_goalrating_controlpoints(entity this, float ratingscale, vector org, float sradius)
-{
- IL_EACH(g_dompoints, vdist((((it.absmin + it.absmax) * 0.5) - org), <, sradius),
- {
- if(it.cnt > -1) // this is just being fought
- navigation_routerating(this, it, ratingscale, 5000);
- else if(it.goalentity.cnt == 0) // unclaimed
- navigation_routerating(this, it, ratingscale * 0.5, 5000);
- else if(it.goalentity.team != this.team) // other team's point
- navigation_routerating(this, it, ratingscale * 0.2, 5000);
- });
-}
-
-void havocbot_role_dom(entity this)
-{
- if(IS_DEAD(this))
- return;
-
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
- havocbot_goalrating_controlpoints(this, 10000, this.origin, 15000);
- havocbot_goalrating_items(this, 8000, this.origin, 8000);
- //havocbot_goalrating_enemyplayers(this, 3000, this.origin, 2000);
- havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-MUTATOR_HOOKFUNCTION(dom, CheckAllowedTeams)
-{
- // fallback?
- M_ARGV(0, float) = domination_teams;
- string ret_string = "dom_team";
-
- entity head = find(NULL, classname, ret_string);
- while(head)
- {
- if(head.netname != "")
- {
- switch(head.team)
- {
- case NUM_TEAM_1: c1 = 0; break;
- case NUM_TEAM_2: c2 = 0; break;
- case NUM_TEAM_3: c3 = 0; break;
- case NUM_TEAM_4: c4 = 0; break;
- }
- }
-
- head = find(head, classname, ret_string);
- }
-
- M_ARGV(1, string) = string_null;
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(dom, reset_map_players)
-{
- total_pps = 0, pps_red = 0, pps_blue = 0, pps_yellow = 0, pps_pink = 0;
- FOREACH_CLIENT(IS_PLAYER(it), {
- PutClientInServer(it);
- if(domination_roundbased)
- it.player_blocked = 1;
- if(IS_REAL_CLIENT(it))
- set_dom_state(it);
- });
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(dom, PlayerSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- if(domination_roundbased)
- if(!round_handler_IsRoundStarted())
- player.player_blocked = 1;
- else
- player.player_blocked = 0;
-}
-
-MUTATOR_HOOKFUNCTION(dom, ClientConnect)
-{
- entity player = M_ARGV(0, entity);
-
- set_dom_state(player);
-}
-
-MUTATOR_HOOKFUNCTION(dom, HavocBot_ChooseRole)
-{
- entity bot = M_ARGV(0, entity);
-
- bot.havocbot_role = havocbot_role_dom;
- return true;
-}
-
-/*QUAKED spawnfunc_dom_controlpoint (0 .5 .8) (-16 -16 -24) (16 16 32)
-Control point for Domination gameplay.
-*/
-spawnfunc(dom_controlpoint)
-{
- if(!g_domination)
- {
- delete(this);
- return;
- }
- setthink(this, dom_controlpoint_setup);
- this.nextthink = time + 0.1;
- this.reset = dom_controlpoint_setup;
-
- if(!this.scale)
- this.scale = 0.6;
-
- this.effects = this.effects | EF_LOWPRECISION;
- if (autocvar_g_domination_point_fullbright)
- this.effects |= EF_FULLBRIGHT;
-
- IL_PUSH(g_dompoints, this);
-}
-
-/*QUAKED spawnfunc_dom_team (0 .5 .8) (-32 -32 -24) (32 32 32)
-Team declaration for Domination gameplay, this allows you to decide what team
-names and control point models are used in your map.
-
-Note: If you use spawnfunc_dom_team entities you must define at least 3 and only two
-can have netname set! The nameless team owns all control points at start.
-
-Keys:
-"netname"
- Name of the team (for example Red Team, Blue Team, Green Team, Yellow Team, Life, Death, etc)
-"cnt"
- Scoreboard color of the team (for example 4 is red and 13 is blue)
-"model"
- Model to use for control points owned by this team (for example
- "progs/b_g_key.mdl" is a gold keycard, and "progs/b_s_key.mdl" is a silver
- keycard)
-"skin"
- Skin of the model to use (for team skins on a single model)
-"noise"
- Sound to play when this team captures a point.
- (this is a localized sound, like a small alarm or other effect)
-"noise1"
- Narrator speech to play when this team captures a point.
- (this is a global sound, like "Red team has captured a control point")
-*/
-
-spawnfunc(dom_team)
-{
- if(!g_domination || autocvar_g_domination_teams_override >= 2)
- {
- delete(this);
- return;
- }
- precache_model(this.model);
- if (this.noise != "")
- precache_sound(this.noise);
- if (this.noise1 != "")
- precache_sound(this.noise1);
- this.classname = "dom_team";
- _setmodel(this, this.model); // precision not needed
- this.mdl = this.model;
- this.dmg = this.modelindex;
- this.model = "";
- this.modelindex = 0;
- // this would have to be changed if used in quakeworld
- if(this.cnt)
- this.team = this.cnt + 1; // WHY are these different anyway?
-}
-
-// scoreboard setup
-void ScoreRules_dom(int teams)
-{
- if(domination_roundbased)
- {
- GameRules_scoring(teams, SFL_SORT_PRIO_PRIMARY, 0, {
- field_team(ST_DOM_CAPS, "caps", SFL_SORT_PRIO_PRIMARY);
- field(SP_DOM_TAKES, "takes", 0);
- });
- }
- else
- {
- float sp_domticks, sp_score;
- sp_score = sp_domticks = 0;
- if(autocvar_g_domination_disable_frags)
- sp_domticks = SFL_SORT_PRIO_PRIMARY;
- else
- sp_score = SFL_SORT_PRIO_PRIMARY;
- GameRules_scoring(teams, sp_score, sp_score, {
- field_team(ST_DOM_TICKS, "ticks", sp_domticks);
- field(SP_DOM_TICKS, "ticks", sp_domticks);
- field(SP_DOM_TAKES, "takes", 0);
- });
- }
-}
-
-// code from here on is just to support maps that don't have control point and team entities
-void dom_spawnteam (string teamname, float teamcolor, string pointmodel, float pointskin, Sound capsound, string capnarration, string capmessage)
-{
- TC(Sound, capsound);
- entity e = new_pure(dom_team);
- e.netname = strzone(teamname);
- e.cnt = teamcolor;
- e.model = pointmodel;
- e.skin = pointskin;
- e.noise = strzone(Sound_fixpath(capsound));
- e.noise1 = strzone(capnarration);
- e.message = strzone(capmessage);
-
- // this code is identical to spawnfunc_dom_team
- _setmodel(e, e.model); // precision not needed
- e.mdl = e.model;
- e.dmg = e.modelindex;
- e.model = "";
- e.modelindex = 0;
- // this would have to be changed if used in quakeworld
- e.team = e.cnt + 1;
-
- //eprint(e);
-}
-
-void dom_spawnpoint(vector org)
-{
- entity e = spawn();
- e.classname = "dom_controlpoint";
- setthink(e, spawnfunc_dom_controlpoint);
- e.nextthink = time;
- setorigin(e, org);
- spawnfunc_dom_controlpoint(e);
-}
-
-// spawn some default teams if the map is not set up for domination
-void dom_spawnteams(int teams)
-{
- TC(int, teams);
- dom_spawnteam(Team_ColoredFullName(NUM_TEAM_1), NUM_TEAM_1-1, "models/domination/dom_red.md3", 0, SND_DOM_CLAIM, "", "Red team has captured a control point");
- dom_spawnteam(Team_ColoredFullName(NUM_TEAM_2), NUM_TEAM_2-1, "models/domination/dom_blue.md3", 0, SND_DOM_CLAIM, "", "Blue team has captured a control point");
- if(teams >= 3)
- dom_spawnteam(Team_ColoredFullName(NUM_TEAM_3), NUM_TEAM_3-1, "models/domination/dom_yellow.md3", 0, SND_DOM_CLAIM, "", "Yellow team has captured a control point");
- if(teams >= 4)
- dom_spawnteam(Team_ColoredFullName(NUM_TEAM_4), NUM_TEAM_4-1, "models/domination/dom_pink.md3", 0, SND_DOM_CLAIM, "", "Pink team has captured a control point");
- dom_spawnteam("", 0, "models/domination/dom_unclaimed.md3", 0, SND_Null, "", "");
-}
-
-void dom_DelayedInit(entity this) // Do this check with a delay so we can wait for teams to be set up.
-{
- // if no teams are found, spawn defaults
- if(find(NULL, classname, "dom_team") == NULL || autocvar_g_domination_teams_override >= 2)
- {
- LOG_TRACE("No \"dom_team\" entities found on this map, creating them anyway.");
- domination_teams = autocvar_g_domination_teams_override;
- if (domination_teams < 2)
- domination_teams = autocvar_g_domination_default_teams;
- domination_teams = bound(2, domination_teams, 4);
- dom_spawnteams(domination_teams);
- }
-
- CheckAllowedTeams(NULL);
- //domination_teams = ((c4>=0) ? 4 : (c3>=0) ? 3 : 2);
-
- int teams = 0;
- if(c1 >= 0) teams |= BIT(0);
- if(c2 >= 0) teams |= BIT(1);
- if(c3 >= 0) teams |= BIT(2);
- if(c4 >= 0) teams |= BIT(3);
- domination_teams = teams;
-
- domination_roundbased = autocvar_g_domination_roundbased;
-
- ScoreRules_dom(domination_teams);
-
- if(domination_roundbased)
- {
- round_handler_Spawn(Domination_CheckPlayers, Domination_CheckWinner, Domination_RoundStart);
- round_handler_Init(5, autocvar_g_domination_warmup, autocvar_g_domination_round_timelimit);
- }
-}
-
-void dom_Initialize()
-{
- g_domination = true;
- InitializeEntity(NULL, dom_DelayedInit, INITPRIO_GAMETYPE);
-}
+++ /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 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), {
- STAT(REDALIVE, it) = redalive;
- STAT(BLUEALIVE, it) = bluealive;
- STAT(YELLOWALIVE, it) = yellowalive;
- STAT(PINKALIVE, it) = pinkalive;
- });
-
- eliminatedPlayers.SendFlags |= 1;
-}
-#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
-
-float freezetag_CheckTeams()
-{
- static float prev_missing_teams_mask;
- if(FREEZETAG_ALIVE_TEAMS_OK())
- {
- if(prev_missing_teams_mask > 0)
- Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
- prev_missing_teams_mask = -1;
- return 1;
- }
- if(total_players == 0)
- {
- if(prev_missing_teams_mask > 0)
- Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
- prev_missing_teams_mask = -1;
- return 0;
- }
- int missing_teams_mask = 0;
- if(freezetag_teams & BIT(0))
- missing_teams_mask += (!redalive) * 1;
- if(freezetag_teams & BIT(1))
- missing_teams_mask += (!bluealive) * 2;
- if(freezetag_teams & BIT(2))
- missing_teams_mask += (!yellowalive) * 4;
- if(freezetag_teams & BIT(3))
- missing_teams_mask += (!pinkalive) * 8;
- if(prev_missing_teams_mask != missing_teams_mask)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
- prev_missing_teams_mask = missing_teams_mask;
- }
- return 0;
-}
-
-float freezetag_getWinnerTeam()
-{
- float winner_team = 0;
- if(redalive >= 1)
- winner_team = NUM_TEAM_1;
- if(bluealive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_2;
- }
- if(yellowalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_3;
- }
- if(pinkalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = NUM_TEAM_4;
- }
- if(winner_team)
- return winner_team;
- return -1; // no player left
-}
-
-void nades_Clear(entity);
-void nades_GiveBonus(entity player, float score);
-
-float freezetag_CheckWinner()
-{
- if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
- FOREACH_CLIENT(IS_PLAYER(it), {
- it.freezetag_frozen_timeout = 0;
- nades_Clear(it);
- });
- game_stopped = true;
- round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
- return 1;
- }
-
- if(FREEZETAG_ALIVE_TEAMS() > 1)
- return 0;
-
- int winner_team = freezetag_getWinnerTeam();
- if(winner_team > 0)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
- TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
- }
- else if(winner_team == -1)
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
- }
-
- FOREACH_CLIENT(IS_PLAYER(it), {
- it.freezetag_frozen_timeout = 0;
- nades_Clear(it);
- });
-
- game_stopped = true;
- round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
- return 1;
-}
-
-entity freezetag_LastPlayerForTeam(entity this)
-{
- entity last_pl = NULL;
- FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
- if(it.health >= 1)
- if(!STAT(FROZEN, it))
- if(SAME_TEAM(it, this))
- if(!last_pl)
- last_pl = it;
- else
- return NULL;
- });
- return last_pl;
-}
-
-void freezetag_LastPlayerForTeam_Notify(entity this)
-{
- if(round_handler_IsActive())
- if(round_handler_IsRoundStarted())
- {
- entity pl = freezetag_LastPlayerForTeam(this);
- if(pl)
- Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
- }
-}
-
-void freezetag_Add_Score(entity targ, entity attacker)
-{
- if(attacker == targ)
- {
- // you froze your own dumb targ
- // counted as "suicide" already
- GameRules_scoring_add(targ, SCORE, -1);
- }
- else if(IS_PLAYER(attacker))
- {
- // got frozen by an enemy
- // counted as "kill" and "death" already
- GameRules_scoring_add(targ, SCORE, -1);
- GameRules_scoring_add(attacker, SCORE, +1);
- }
- // else nothing - got frozen by the game type rules themselves
-}
-
-void freezetag_Freeze(entity targ, entity attacker)
-{
- if(STAT(FROZEN, targ))
- return;
-
- if(autocvar_g_freezetag_frozen_maxtime > 0)
- targ.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
-
- Freeze(targ, 0, 1, true);
-
- freezetag_count_alive_players();
-
- freezetag_Add_Score(targ, attacker);
-}
-
-void freezetag_Unfreeze(entity this)
-{
- this.freezetag_frozen_time = 0;
- this.freezetag_frozen_timeout = 0;
-
- Unfreeze(this);
-}
-
-float freezetag_isEliminated(entity e)
-{
- if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
- return true;
- return false;
-}
-
-
-// ================
-// Bot player logic
-// ================
-
-void(entity this) havocbot_role_ft_freeing;
-void(entity this) havocbot_role_ft_offense;
-
-void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
-{
- float t;
- FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
- if (STAT(FROZEN, it) == 1)
- {
- if(vdist(it.origin - org, >, sradius))
- continue;
- navigation_routerating(this, it, ratingscale, 2000);
- }
- else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
- {
- // If teamate is not frozen still seek them out as fight better
- // in a group.
- t = 0.2 * 150 / (this.health + this.armorvalue);
- navigation_routerating(this, it, t * ratingscale, 2000);
- }
- });
-}
-
-void havocbot_role_ft_offense(entity this)
-{
- if(IS_DEAD(this))
- return;
-
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + random() * 10 + 20;
-
- // Count how many players on team are unfrozen.
- int unfrozen = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
-
- // If only one left on team or if role has timed out then start trying to free players.
- if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
- {
- LOG_TRACE("changing role to freeing");
- this.havocbot_role = havocbot_role_ft_freeing;
- this.havocbot_role_timeout = 0;
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
- havocbot_goalrating_items(this, 10000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
- havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
- havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-void havocbot_role_ft_freeing(entity this)
-{
- if(IS_DEAD(this))
- return;
-
- if (!this.havocbot_role_timeout)
- this.havocbot_role_timeout = time + random() * 10 + 20;
-
- if (time > this.havocbot_role_timeout)
- {
- LOG_TRACE("changing role to offense");
- this.havocbot_role = havocbot_role_ft_offense;
- this.havocbot_role_timeout = 0;
- return;
- }
-
- if (navigation_goalrating_timeout(this))
- {
- navigation_goalrating_start(this);
- havocbot_goalrating_items(this, 8000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
- havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
- havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
- navigation_goalrating_end(this);
-
- navigation_goalrating_timeout_set(this);
- }
-}
-
-
-// ==============
-// Hook Functions
-// ==============
-
-void ft_RemovePlayer(entity this)
-{
- this.health = 0; // neccessary to update correctly alive stats
- if(!STAT(FROZEN, this))
- freezetag_LastPlayerForTeam_Notify(this);
- freezetag_Unfreeze(this);
- freezetag_count_alive_players();
-}
-
-MUTATOR_HOOKFUNCTION(ft, ClientDisconnect)
-{
- entity player = M_ARGV(0, entity);
-
- ft_RemovePlayer(player);
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, MakePlayerObserver)
-{
- entity player = M_ARGV(0, entity);
-
- ft_RemovePlayer(player);
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerDies)
-{
- entity frag_attacker = M_ARGV(1, entity);
- entity frag_target = M_ARGV(2, entity);
- float frag_deathtype = M_ARGV(3, float);
-
- if(round_handler_IsActive())
- if(round_handler_CountdownRunning())
- {
- if(STAT(FROZEN, frag_target))
- freezetag_Unfreeze(frag_target);
- freezetag_count_alive_players();
- return true; // let the player die so that he can respawn whenever he wants
- }
-
- // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
- // you succeed changing team through the menu: you both really die (gibbing) and get frozen
- if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
- || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
- {
- // let the player die, he will be automatically frozen when he respawns
- if(STAT(FROZEN, frag_target) != 1)
- {
- freezetag_Add_Score(frag_target, frag_attacker);
- freezetag_count_alive_players();
- freezetag_LastPlayerForTeam_Notify(frag_target);
- }
- else
- freezetag_Unfreeze(frag_target); // remove ice
- frag_target.health = 0; // Unfreeze resets health
- frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
- return true;
- }
-
- if(STAT(FROZEN, frag_target))
- return true;
-
- freezetag_Freeze(frag_target, frag_attacker);
- freezetag_LastPlayerForTeam_Notify(frag_target);
-
- if(frag_attacker == frag_target || frag_attacker == NULL)
- {
- if(IS_PLAYER(frag_target))
- Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
- }
- else
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- if(player.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
- return true; // do nothing, round is starting right now
-
- if(player.freezetag_frozen_timeout == -2) // player was dead
- {
- freezetag_Freeze(player, NULL);
- return true;
- }
-
- freezetag_count_alive_players();
-
- if(round_handler_IsActive())
- if(round_handler_IsRoundStarted())
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
- freezetag_Freeze(player, NULL);
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, reset_map_players)
-{
- FOREACH_CLIENT(IS_PLAYER(it), {
- CS(it).killcount = 0;
- it.freezetag_frozen_timeout = -1;
- PutClientInServer(it);
- it.freezetag_frozen_timeout = 0;
- });
- freezetag_count_alive_players();
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
-{
- M_ARGV(2, float) = 0; // no frags counted in Freeze Tag
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
-{
- if(game_stopped)
- return true;
-
- if(round_handler_IsActive())
- if(!round_handler_IsRoundStarted())
- return true;
-
- int n;
- entity o = NULL;
- entity player = M_ARGV(0, entity);
- //if(STAT(FROZEN, player))
- //if(player.freezetag_frozen_timeout > 0 && time < player.freezetag_frozen_timeout)
- //player.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (player.freezetag_frozen_timeout - time) / (player.freezetag_frozen_timeout - player.freezetag_frozen_time);
-
- if(player.freezetag_frozen_timeout > 0 && time >= player.freezetag_frozen_timeout)
- n = -1;
- else
- {
- vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
- n = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && it != player, {
- if(STAT(FROZEN, it) == 0)
- if(!IS_DEAD(it))
- if(SAME_TEAM(it, player))
- if(boxesoverlap(player.absmin - revive_extra_size, player.absmax + revive_extra_size, it.absmin, it.absmax))
- {
- if(!o)
- o = it;
- if(STAT(FROZEN, player) == 1)
- it.reviving = true;
- ++n;
- }
- });
-
- }
-
- if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
- {
- STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
- player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
-
- if(STAT(REVIVE_PROGRESS, player) >= 1)
- {
- freezetag_Unfreeze(player);
- freezetag_count_alive_players();
-
- if(n == -1)
- {
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, player.netname, autocvar_g_freezetag_frozen_maxtime);
- return true;
- }
-
- // EVERY team mate nearby gets a point (even if multiple!)
- FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
- GameRules_scoring_add(it, FREEZETAG_REVIVALS, +1);
- GameRules_scoring_add(it, SCORE, +1);
- nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
- });
-
- Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
- Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, player.netname);
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_FREEZETAG_REVIVED, player.netname, o.netname);
- }
-
- FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, {
- STAT(REVIVE_PROGRESS, it) = STAT(REVIVE_PROGRESS, player);
- it.reviving = false;
- });
- }
- else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
- {
- STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
- player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
- }
- else if(!n && !STAT(FROZEN, player))
- {
- STAT(REVIVE_PROGRESS, player) = 0; // thawing nobody
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, SetStartItems)
-{
- start_items &= ~IT_UNLIMITED_AMMO;
- //start_health = warmup_start_health = cvar("g_lms_start_health");
- //start_armorvalue = warmup_start_armorvalue = cvar("g_lms_start_armor");
- start_ammo_shells = warmup_start_ammo_shells = cvar("g_lms_start_ammo_shells");
- start_ammo_nails = warmup_start_ammo_nails = cvar("g_lms_start_ammo_nails");
- start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
- start_ammo_cells = warmup_start_ammo_cells = cvar("g_lms_start_ammo_cells");
- start_ammo_plasma = warmup_start_ammo_plasma = cvar("g_lms_start_ammo_plasma");
- start_ammo_fuel = warmup_start_ammo_fuel = cvar("g_lms_start_ammo_fuel");
-}
-
-MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
-{
- entity bot = M_ARGV(0, entity);
-
- if (!IS_DEAD(bot))
- {
- if (random() < 0.5)
- bot.havocbot_role = havocbot_role_ft_freeing;
- else
- bot.havocbot_role = havocbot_role_ft_offense;
- }
-
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
-{
- M_ARGV(0, float) = freezetag_teams;
-}
-
-MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
-{
- // most weapons arena
- if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
- M_ARGV(0, string) = "most";
-}
-
-MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
-{
- entity frag_attacker = M_ARGV(0, entity);
- entity frag_target = M_ARGV(1, entity);
- //float frag_deathtype = M_ARGV(2, float);
- int kill_count_to_attacker = M_ARGV(3, int);
- int kill_count_to_target = M_ARGV(4, int);
-
- if(STAT(FROZEN, frag_target))
- return; // target was already frozen, so this is just pushing them off the cliff
-
- Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
- Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
-
- return true;
-}
-
-void freezetag_Initialize()
-{
- freezetag_teams = autocvar_g_freezetag_teams_override;
- if(freezetag_teams < 2)
- freezetag_teams = cvar("g_freezetag_teams"); // read the cvar directly as it gets written earlier in the same frame
-
- freezetag_teams = BITS(bound(2, freezetag_teams, 4));
- GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
- field(SP_FREEZETAG_REVIVALS, "revivals", 0);
- });
-
- round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
- round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
-
- EliminatedPlayers_Init(freezetag_isEliminated);
-}
+++ /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;
-}
-
-
-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();
-}
+++ /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
-.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
-}
+++ /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"
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);
#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"
toucher.effects += EF_BLUE - EF_RED;
}
-void Portal_Think(entity this);
void Portal_MakeBrokenPortal(entity portal)
{
portal.skin = 2;
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); });
}
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);
}
resource_type = M_ARGV(1, int);
amount = M_ARGV(2, float);
- .float resource_field = GetResourceField(resource_type);
- if (e.(resource_field) == amount)
- {
- return;
- }
float max_amount = GetResourceLimit(e, resource_type);
+ float amount_wasted = 0;
if (amount > max_amount)
{
+ amount_wasted = amount - max_amount;
amount = max_amount;
}
- e.(resource_field) = amount;
+ .float resource_field = GetResourceField(resource_type);
+ if (e.(resource_field) != amount)
+ {
+ e.(resource_field) = amount;
+ MUTATOR_CALLHOOK(ResourceAmountChanged, e, resource_type, amount);
+ }
+ if (amount_wasted == 0)
+ {
+ return;
+ }
+ MUTATOR_CALLHOOK(ResourceWasted, e, resource_type, amount_wasted);
}
void GiveResource(entity receiver, int resource_type, float amount)
void GiveResourceWithLimit(entity receiver, int resource_type, float amount,
float limit)
{
+ if (amount == 0)
+ {
+ return;
+ }
+ bool forbid = MUTATOR_CALLHOOK(GiveResourceWithLimit, receiver,
+ resource_type, amount, limit);
+ if (forbid)
+ {
+ return;
+ }
+ resource_type = M_ARGV(1, int);
+ amount = M_ARGV(2, float);
+ limit = M_ARGV(3, float);
if (amount == 0)
{
return;
#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(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/triggers/target/spawnpoint.qh"
+#include "../common/mapobjects/subs.qh"
+#include "../common/mapobjects/target/spawnpoint.qh"
#include "../common/util.qh"
#include "../lib/warpzone/common.qh"
#include "../lib/warpzone/util_server.qh"
+#include <server/utils.qh>
bool SpawnPoint_Send(entity this, entity to, int sf)
{
**/
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"
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(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 != "") {
#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>
{
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);
#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>
// 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
{
#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>
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;
#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
// 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."
exec physicsXDF.cfg
// general gameplay
-set g_jump_grunt 1 // make enemies even easier to hear when they're jumping around
+// set g_jump_grunt 1 // just no
set g_shootfromcenter 1 // hit where you point at with the crosshair (almost so, no shooteye because it's really ugly)
set g_balance_kill_antispam 0
set g_forced_respawn 1
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
exec xonotic-server.cfg
exec balance-overkill.cfg
exec physicsOverkill.cfg
+exec randomitems-overkill.cfg
// general gameplay
set g_overkill 1
set menu_use_default_hostname 1
alias sethostname "set menu_use_default_hostname 0; hostname $*"
-seta cl_weaponpriority "vaporizer hmg rpc vortex fireball mortar machinegun hagar rifle arc electro devastator crylink minelayer shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
+seta cl_weaponpriority "vaporizer okhmg okrpc oknex vortex fireball mortar okmachinegun machinegun hagar rifle arc electro devastator crylink minelayer okshotgun shotgun shockwave hlac tuba blaster porto seeker hook" "weapon priority list"
seta cl_weaponpriority_useforcycling 0 "when set, weapon cycling by the mouse wheel makes use of the weapon priority list (the special value 2 uses the weapon ID list for cycling)"
-seta cl_weaponpriority0 "rpc devastator mortar hagar seeker fireball" "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun. Default value: explosives"
-seta cl_weaponpriority1 "vaporizer vortex crylink hlac arc electro blaster shockwave" "use weapon_priority_1_prev for prev gun from this list, weapon_priority_1_best for best gun, weapon_priority_1_next for next gun. Default value: energy"
-seta cl_weaponpriority2 "vaporizer vortex rifle" "use weapon_priority_2_prev for prev gun from this list, weapon_priority_2_best for best gun, weapon_priority_2_next for next gun. Default value: hitscan exact"
-seta cl_weaponpriority3 "vaporizer hmg vortex rifle machinegun shotgun shockwave" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
-seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker shotgun shockwave" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
+seta cl_weaponpriority0 "okrpc devastator mortar hagar seeker fireball" "use weapon_priority_0_prev for prev gun from this list, weapon_priority_0_best for best gun, weapon_priority_0_next for next gun. Default value: explosives"
+seta cl_weaponpriority1 "vaporizer oknex vortex crylink hlac arc electro blaster shockwave" "use weapon_priority_1_prev for prev gun from this list, weapon_priority_1_best for best gun, weapon_priority_1_next for next gun. Default value: energy"
+seta cl_weaponpriority2 "vaporizer oknex vortex rifle" "use weapon_priority_2_prev for prev gun from this list, weapon_priority_2_best for best gun, weapon_priority_2_next for next gun. Default value: hitscan exact"
+seta cl_weaponpriority3 "vaporizer okhmg oknex vortex rifle okmachinegun machinegun okshotgun shotgun shockwave" "use weapon_priority_3_prev for prev gun from this list, weapon_priority_3_best for best gun, weapon_priority_3_next for next gun. Default value: hitscan all"
+seta cl_weaponpriority4 "mortar minelayer hlac hagar crylink seeker okshotgun shotgun shockwave" "use weapon_priority_4_prev for prev gun from this list, weapon_priority_4_best for best gun, weapon_priority_4_next for next gun. Default value: spam weapons"
seta cl_weaponpriority5 "blaster shockwave hook porto" "use weapon_priority_5_prev for prev gun from this list, weapon_priority_5_best for best gun, weapon_priority_5_next for next gun. Default value: weapons for moving"
seta cl_weaponpriority6 "" "use weapon_priority_6_prev for prev gun from this list, weapon_priority_6_best for best gun, weapon_priority_6_next for next gun"
seta cl_weaponpriority7 "" "use weapon_priority_7_prev for prev gun from this list, weapon_priority_7_best for best gun, weapon_priority_7_next for next gun"
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
seta cl_items_nofade 0
seta cl_animate_items 1
seta cl_ghost_items 0.45 "enable ghosted items (when between 0 and 1, overrides the alpha value)"
-seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items, 0 0 0 leaves the color unchanged"
+seta cl_ghost_items_color "-1 -1 -1" "color of ghosted items (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)"
seta cl_simple_items 0 "enable simple items (if server allows)"
set cl_simpleitems_postfix "_luma" "posfix to add fo model name when simple items are enabled"
set cl_fullbright_items 0 "enable fullbright items (if server allows, controlled by g_fullbrightitems)"
-set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0"
+set cl_weapon_stay_color "2 0.5 0.5" "Color of picked up weapons when g_weapon_stay > 0 (colormod format: 0 0 0 leaves the color unchanged, negative values allowed)"
set cl_weapon_stay_alpha 0.75 "Alpha of picked up weapons when g_weapon_stay > 0"
seta cl_showspectators 0 "Show who's spectating you if server has sv_showspectators enabled"
set sv_timeout_leadtime 4 "how long the players will be informed that a timeout was called before it starts, in seconds"
set sv_timeout_resumetime 3 "how long the remaining timeout-time will be after a player called the timein command"
-set g_allow_oldvortexbeam 0 "If enabled, clients are allowed to use old v2.3 Vortex beam"
+set g_allow_oldvortexbeam 1 "If enabled, clients are allowed to use old v2.3 Vortex beam"
set g_telefrags 1 "telefragging, i.e. killing someone who stands in the way of someone who is teleporting"
set g_telefrags_teamplay 1 "never telefrag team mates"
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_aimskill_offset 0.3 "Amount of error induced to the bots aim"
set bot_ai_aimskill_think 1 "Aiming velocity. Use values below 1 for slower aiming"
set bot_ai_custom_weapon_priority_distances "300 850" "Define close and far distances in any order. Based on the distance to the enemy bots will choose different weapons"
-set bot_ai_custom_weapon_priority_far "vaporizer vortex rifle electro devastator mortar hagar hlac crylink blaster machinegun fireball seeker shotgun shockwave tuba minelayer" "Desired weapons for far distances ordered by priority"
-set bot_ai_custom_weapon_priority_mid "vaporizer devastator vortex fireball seeker mortar electro machinegun arc crylink hlac hagar shotgun shockwave blaster rifle tuba minelayer" "Desired weapons for middle distances ordered by priority"
-set bot_ai_custom_weapon_priority_close "vaporizer vortex shotgun shockwave machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer" "Desired weapons for close distances ordered by priority"
+set bot_ai_custom_weapon_priority_far "vaporizer oknex vortex rifle electro devastator mortar hagar hlac crylink blaster okmachinegun machinegun fireball seeker okshotgun shotgun shockwave tuba minelayer" "Desired weapons for far distances ordered by priority"
+set bot_ai_custom_weapon_priority_mid "vaporizer devastator oknex vortex fireball seeker mortar electro okmachinegun machinegun arc crylink hlac hagar okshotgun shotgun shockwave blaster rifle tuba minelayer" "Desired weapons for middle distances ordered by priority"
+set bot_ai_custom_weapon_priority_close "vaporizer oknex vortex okshotgun shotgun shockwave okmachinegun machinegun arc hlac tuba seeker hagar crylink mortar electro devastator blaster fireball rifle minelayer" "Desired weapons for close distances ordered by priority"
set bot_ai_weapon_combo 1 "Enable bots to do weapon combos"
set bot_ai_weapon_combo_threshold 0.4 "Try to make a combo N seconds after the last attack"
set bot_ai_friends_aware_pickup_radius "500" "Bots will not pickup items if a team mate is this distance near the item"
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 g_spawnshieldtime 1 "number of seconds you are invincible after you spawned, this shield is lost after you fire"
set g_spawnshield_blockdamage 1 "how much spawn shield protects you from damage (1 = full protection)"
-set g_antilag 2 "AntiLag (0 = no AntiLag, 1 = verified client side hit scan, 2 = server side hit scan in the past, 3 = unverified client side hit scan)"
+set g_antilag 2 "AntiLag (0 = no AntiLag, 1 = verified client side hit scan, 2 = server side hit scan in the past)"
set g_antilag_nudge 0 "don't touch"
set g_shootfromeye 0 "shots are fired from your eye/crosshair; visual gun position can still be influenced by cl_gunalign 1 and 2"
set g_shootfromcenter 0 "weapon gets moved to the center, shots still come from the barrel of your weapon; visual gun position can still be influenced by cl_gunalign 1 and 2"
set g_maplist_votable_timeout 30 "timeout for the map voting; must be below 50 seconds!"
set g_maplist_votable_suggestions 2
set g_maplist_votable_suggestions_override_mostrecent 0
-set g_maplist_votable_nodetail 1 "nodetail only shows total count instead of all vote counts per map, so votes don't influence others that much"
+set g_maplist_votable_nodetail 0 "nodetail only shows total count instead of all vote counts per map, so votes don't influence others that much"
set g_maplist_votable_abstain 0 "when 1, you can abstain from your vote"
set g_maplist_votable_screenshot_dir "maps levelshots" "where to look for map screenshots"
set sv_vote_gametype 0 "show a vote screen for gametypes before map vote screen"
set sv_vote_gametype_keeptwotime 10 "show only 2 options after this amount of time during gametype vote screen"
-set sv_vote_gametype_options "dm ctf ca lms tdm ft"
+set sv_vote_gametype_options "dm tdm ctf"
set sv_vote_gametype_timeout 20
set sv_vote_gametype_default_current 1 "Keep the current gametype if no one votes"
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"