- 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=6e591fe90a6b90e62fdfd531636dd6eb
+ - EXPECT=0a8b491cd50a1e77d930b048c98da88f
- HASH=$(${ENGINE} -noconfig -nohome +exec serverbench.cfg
| tee /dev/stderr
| grep '^:'
-Mon Jul 15 07:24:31 CEST 2019
+Tue Jul 30 07:24:47 CEST 2019
seta hud_panel_scoreboard_accuracy_showdelay 2 "how long to delay displaying accuracy below the scoreboard if it's too far down"
seta hud_panel_scoreboard_accuracy_showdelay_minpos 0.75 "delay displaying the accuracy panel only if its position is lower than this percentage of the screen height from the top"
-seta hud_panel_scoreboard_team_size_position 0 "where to show the team size (0 = do not show, 1 = left of scoreboard, 2 = right of scoreboard, and move team scores to the right)"
+seta hud_panel_scoreboard_team_size_position 0 "where to show the team size (0 = do not show, 1 = left of scoreboard, 2 = right of scoreboard), will move team scores to the other side if necessary"
// hud panel aliases
alias quickmenu "cl_cmd hud quickmenu ${* ?}"
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 12.5
-set g_balance_blaster_primary_force 300
-set g_balance_blaster_primary_force_zscale 1.25
+set g_balance_blaster_primary_edgedamage 10
+set g_balance_blaster_primary_force 375
+set g_balance_blaster_primary_force_zscale 1
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_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_force 360
+set g_balance_blaster_secondary_force_zscale 1
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_shotgun_reload_ammo 0
set g_balance_shotgun_reload_time 2
set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
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_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_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
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_burst_spread 0.02
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 14
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_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_radius 100
set g_balance_crylink_secondary_refire 0.65
set g_balance_crylink_secondary_shots 5
-set g_balance_crylink_secondary_speed 7000
+set g_balance_crylink_secondary_speed 4000
set g_balance_crylink_secondary_spread 0.08
set g_balance_crylink_secondary_spreadtype 0
set g_balance_crylink_switchdelay_drop 0.2
// }}}
// {{{ #8: Vortex
set g_balance_vortex_charge 0
+set g_balance_vortex_charge_always 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_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 400
+set g_balance_vaporizer_secondary_force 480
+set g_balance_vaporizer_secondary_force_zscale 1
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_seeker_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
+// {{{ #19: Shockwave
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_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 1500
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_burst_heat 5
+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_switchdelay_drop 0.2
set g_balance_arc_switchdelay_raise 0.2
set g_balance_arc_weaponreplace ""
set g_balance_arc_weaponstartoverride -1
set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okhmg_secondary_edgedamage 12.5
set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_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
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okmachinegun_secondary_edgedamage 12.5
set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_force_zscale 1
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_weaponstartoverride -1
set g_balance_okmachinegun_weaponthrowable 1
// }}}
-// {{{ Overkill Nex
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
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_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_force 300
+set g_balance_oknex_secondary_force_zscale 1
set g_balance_oknex_secondary_lifetime 5
set g_balance_oknex_secondary_radius 70
+set g_balance_oknex_secondary_refire 0.7
+set g_balance_oknex_secondary_refire_type 1
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_weaponstartoverride -1
set g_balance_oknex_weaponthrowable 1
// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
set g_balance_shotgun_reload_ammo 0
set g_balance_shotgun_reload_time 2
set g_balance_shotgun_secondary 2
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
set g_balance_shotgun_secondary_animtime 1.15
set g_balance_shotgun_secondary_damage 80
set g_balance_shotgun_secondary_force 200
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.15
set g_balance_shotgun_switchdelay_raise 0.15
set g_balance_shotgun_weaponreplace ""
set g_balance_shotgun_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
set g_balance_machinegun_burst 0
set g_balance_machinegun_burst_ammo 3
set g_balance_machinegun_burst_animtime 0.75
set g_balance_machinegun_burst_refire 0.05
set g_balance_machinegun_burst_refire2 0.75
-set g_balance_machinegun_burst_speed 0
+set g_balance_machinegun_burst_spread 0.04
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 30
// }}}
// {{{ #8: Vortex
set g_balance_vortex_charge 0
+set g_balance_vortex_charge_always 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_hagar_primary_radius 65
set g_balance_hagar_primary_refire 0.15
set g_balance_hagar_primary_speed 3000
-set g_balance_hagar_primary_spread 0.010
+set g_balance_hagar_primary_spread 0.01
set g_balance_hagar_reload_ammo 0
set g_balance_hagar_reload_time 2
set g_balance_hagar_secondary 1
set g_balance_vaporizer_secondary_delay 0
set g_balance_vaporizer_secondary_edgedamage 12.5
set g_balance_vaporizer_secondary_force 400
+set g_balance_vaporizer_secondary_force_zscale 1
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_seeker_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
+// {{{ #19: Shockwave
set g_balance_shockwave_blast_animtime 0.3
set g_balance_shockwave_blast_damage 20
set g_balance_shockwave_blast_distance 1000
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 1
-set g_balance_arc_overheat_max 5
-set g_balance_arc_overheat_min 3
set g_balance_arc_beam_heat 1
-set g_balance_arc_burst_heat 3
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_burst_damage 150
set g_balance_arc_burst_healing_aps 100
set g_balance_arc_burst_healing_hps 100
+set g_balance_arc_burst_heat 3
+set g_balance_arc_cooldown 2.5
+set g_balance_arc_cooldown_release 1
+set g_balance_arc_overheat_max 5
+set g_balance_arc_overheat_min 3
set g_balance_arc_switchdelay_drop 0.3
set g_balance_arc_switchdelay_raise 0.3
set g_balance_arc_weaponreplace ""
set g_balance_arc_weaponstartoverride -1
set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okhmg_secondary_edgedamage 12.5
set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_weaponthrowable 0
// }}}
-// {{{ #22: Overkill Rocket Propelled Chainsaw
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
+set g_balance_okmachinegun_primary_ammo 1
+set g_balance_okmachinegun_primary_damage 25
+set g_balance_okmachinegun_primary_force 5
+set g_balance_okmachinegun_primary_refire 0.1
+set g_balance_okmachinegun_primary_solidpenetration 63
+set g_balance_okmachinegun_primary_spread_add 0.012
+set g_balance_okmachinegun_primary_spread_max 0.05
+set g_balance_okmachinegun_primary_spread_min 0
+set g_balance_okmachinegun_reload_ammo 30
+set g_balance_okmachinegun_reload_time 1.5
+set g_balance_okmachinegun_secondary_animtime 0.2
+set g_balance_okmachinegun_secondary_damage 25
+set g_balance_okmachinegun_secondary_delay 0
+set g_balance_okmachinegun_secondary_edgedamage 12.5
+set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_force_zscale 1
+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
+// }}}
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
+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_delay 0
+set g_balance_oknex_secondary_edgedamage 12.5
+set g_balance_oknex_secondary_force 300
+set g_balance_oknex_secondary_force_zscale 1
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 70
+set g_balance_oknex_secondary_refire 0.7
+set g_balance_oknex_secondary_refire_type 1
+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
+// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okrpc_secondary_edgedamage 12.5
set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okrpc_weaponthrowable 0
// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
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_force_zscale 1
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_okmachinegun_secondary_delay 0
set g_balance_okmachinegun_secondary_edgedamage 10
set g_balance_okmachinegun_secondary_force 300
+set g_balance_okmachinegun_secondary_force_zscale 1
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_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_force_zscale 1
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_blaster_primary_delay 0
set g_balance_blaster_primary_edgedamage 12.5
set g_balance_blaster_primary_force 300
+set g_balance_blaster_primary_force_zscale 1
set g_balance_blaster_primary_lifetime 5
set g_balance_blaster_primary_radius 70
set g_balance_blaster_primary_refire 0.7
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
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_weaponstartoverride -1
set g_balance_blaster_weaponthrowable 0
// }}}
-// {{{ #2: Shockwave
-set g_balance_shockwave_blast_animtime 0.3
-set g_balance_shockwave_blast_damage 20
-set g_balance_shockwave_blast_distance 1000
-set g_balance_shockwave_blast_edgedamage 0
-set g_balance_shockwave_blast_force 200
-set g_balance_shockwave_blast_force_forwardbias 50
-set g_balance_shockwave_blast_force_zscale 2
-set g_balance_shockwave_blast_jump_damage 20
-set g_balance_shockwave_blast_jump_edgedamage 0
-set g_balance_shockwave_blast_jump_force 300
-set g_balance_shockwave_blast_jump_force_velocitybias 0
-set g_balance_shockwave_blast_jump_force_zscale 1.25
-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.5
-set g_balance_shockwave_blast_multiplier_distance 0.5
-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 1
-set g_balance_shockwave_weaponstartoverride -1
-set g_balance_shockwave_weaponthrowable 0
+// {{{ #2: Shotgun
+set g_balance_shotgun_primary_ammo 1
+set g_balance_shotgun_primary_animtime 0.2
+set g_balance_shotgun_primary_bullets 14
+set g_balance_shotgun_primary_damage 4
+set g_balance_shotgun_primary_force 15
+set g_balance_shotgun_primary_refire 0.75
+set g_balance_shotgun_primary_solidpenetration 3.8
+set g_balance_shotgun_primary_spread 0.12
+set g_balance_shotgun_reload_ammo 0
+set g_balance_shotgun_reload_time 2
+set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
+set g_balance_shotgun_secondary_animtime 1.15
+set g_balance_shotgun_secondary_damage 80
+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_switchdelay_drop 0.2
+set g_balance_shotgun_switchdelay_raise 0.2
+set g_balance_shotgun_weaponreplace ""
+set g_balance_shotgun_weaponstart 0
+set g_balance_shotgun_weaponstartoverride -1
+set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
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_burst_spread 0.02
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 14
set g_balance_electro_weaponstartoverride -1
set g_balance_electro_weaponthrowable 1
// }}}
-// {{{ #7: Arc
-set g_balance_arc_beam_ammo 0
-set g_balance_arc_beam_animtime 0.2
-set g_balance_arc_beam_botaimlifetime 0
-set g_balance_arc_beam_botaimspeed 0
-set g_balance_arc_beam_damage 150
-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 2000
-set g_balance_arc_beam_healing_amax 200
-set g_balance_arc_beam_healing_aps 50
-set g_balance_arc_beam_healing_hmax 200
-set g_balance_arc_beam_healing_hps 50
-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.5
-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 100
-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 2200
-set g_balance_arc_bolt_spread 0.03
-set g_balance_arc_burst_ammo 0
-set g_balance_arc_burst_damage 500
-set g_balance_arc_burst_healing_aps 100
-set g_balance_arc_burst_healing_hps 100
-set g_balance_arc_cooldown 2.5
-set g_balance_arc_cooldown_release 1
-set g_balance_arc_overheat_max 5
-set g_balance_arc_overheat_min 3
-set g_balance_arc_beam_heat 1
-set g_balance_arc_burst_heat 5
-set g_balance_arc_switchdelay_drop 0.3
-set g_balance_arc_switchdelay_raise 0.3
-set g_balance_arc_weaponreplace ""
-set g_balance_arc_weaponstart 0
-set g_balance_arc_weaponstartoverride -1
-set g_balance_arc_weaponthrowable 1
-// }}}
-// {{{ #8: Crylink
+// {{{ #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_weaponstartoverride -1
set g_balance_crylink_weaponthrowable 1
// }}}
-// {{{ #9: Vortex
+// {{{ #8: Vortex
set g_balance_vortex_charge 1
+set g_balance_vortex_charge_always 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_weaponstartoverride -1
set g_balance_vortex_weaponthrowable 1
// }}}
-// {{{ #10: Hagar
+// {{{ #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_weaponstartoverride -1
set g_balance_hagar_weaponthrowable 1
// }}}
-// {{{ #11: Devastator
+// {{{ #10: Devastator
set g_balance_devastator_ammo 4
set g_balance_devastator_animtime 0.4
set g_balance_devastator_damage 70
set g_balance_devastator_weaponstartoverride -1
set g_balance_devastator_weaponthrowable 1
// }}}
-// {{{ #12: Port-O-Launch
+// {{{ #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_weaponstartoverride -1
set g_balance_porto_weaponthrowable 1
// }}}
-// {{{ #13: Vaporizer
+// {{{ #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_secondary_delay 0
set g_balance_vaporizer_secondary_edgedamage 12.5
set g_balance_vaporizer_secondary_force 400
+set g_balance_vaporizer_secondary_force_zscale 1
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_weaponstartoverride -1
set g_balance_vaporizer_weaponthrowable 0
// }}}
-// {{{ #14: Grappling Hook
+// {{{ #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_weaponstartoverride -1
set g_balance_hook_weaponthrowable 1
// }}}
-// {{{ #15: Heavy Laser Assault Cannon (MUTATOR WEAPON)
+// {{{ #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_weaponstartoverride -1
set g_balance_hlac_weaponthrowable 1
// }}}
-// {{{ #16: @!#%'n Tuba
+// {{{ #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_weaponstartoverride -1
set g_balance_tuba_weaponthrowable 1
// }}}
-// {{{ #17: Rifle (MUTATOR WEAPON)
+// {{{ #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_weaponstartoverride -1
set g_balance_rifle_weaponthrowable 1
// }}}
-// {{{ #18: Fireball
+// {{{ #17: Fireball
set g_balance_fireball_primary_animtime 0.2
set g_balance_fireball_primary_bfgdamage 100
set g_balance_fireball_primary_bfgforce 0
set g_balance_fireball_weaponstartoverride -1
set g_balance_fireball_weaponthrowable 0
// }}}
-// {{{ #19: T.A.G. Seeker (MUTATOR WEAPON)
+// {{{ #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_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #20: Shotgun (MUTATOR WEAPON)
-set g_balance_shotgun_primary_ammo 1
-set g_balance_shotgun_primary_animtime 0.2
-set g_balance_shotgun_primary_bullets 14
-set g_balance_shotgun_primary_damage 4
-set g_balance_shotgun_primary_force 15
-set g_balance_shotgun_primary_refire 0.75
-set g_balance_shotgun_primary_solidpenetration 3.8
-set g_balance_shotgun_primary_spread 0.12
-set g_balance_shotgun_reload_ammo 0
-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 80
-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 0
-set g_balance_shotgun_weaponstartoverride -1
-set g_balance_shotgun_weaponthrowable 1
+// {{{ #19: Shockwave
+set g_balance_shockwave_blast_animtime 0.3
+set g_balance_shockwave_blast_damage 20
+set g_balance_shockwave_blast_distance 1000
+set g_balance_shockwave_blast_edgedamage 0
+set g_balance_shockwave_blast_force 200
+set g_balance_shockwave_blast_force_forwardbias 50
+set g_balance_shockwave_blast_force_zscale 2
+set g_balance_shockwave_blast_jump_damage 20
+set g_balance_shockwave_blast_jump_edgedamage 0
+set g_balance_shockwave_blast_jump_force 300
+set g_balance_shockwave_blast_jump_force_velocitybias 0
+set g_balance_shockwave_blast_jump_force_zscale 1.25
+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.5
+set g_balance_shockwave_blast_multiplier_distance 0.5
+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 1
+set g_balance_shockwave_weaponstartoverride -1
+set g_balance_shockwave_weaponthrowable 0
+// }}}
+// {{{ #20: Arc
+set g_balance_arc_beam_ammo 0
+set g_balance_arc_beam_animtime 0.2
+set g_balance_arc_beam_botaimlifetime 0
+set g_balance_arc_beam_botaimspeed 0
+set g_balance_arc_beam_damage 150
+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 2000
+set g_balance_arc_beam_healing_amax 200
+set g_balance_arc_beam_healing_aps 50
+set g_balance_arc_beam_healing_hmax 200
+set g_balance_arc_beam_healing_hps 50
+set g_balance_arc_beam_heat 1
+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.5
+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 100
+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 2200
+set g_balance_arc_bolt_spread 0.03
+set g_balance_arc_burst_ammo 0
+set g_balance_arc_burst_damage 500
+set g_balance_arc_burst_healing_aps 100
+set g_balance_arc_burst_healing_hps 100
+set g_balance_arc_burst_heat 5
+set g_balance_arc_cooldown 2.5
+set g_balance_arc_cooldown_release 1
+set g_balance_arc_overheat_max 5
+set g_balance_arc_overheat_min 3
+set g_balance_arc_switchdelay_drop 0.3
+set g_balance_arc_switchdelay_raise 0.3
+set g_balance_arc_weaponreplace ""
+set g_balance_arc_weaponstart 0
+set g_balance_arc_weaponstartoverride -1
+set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okhmg_secondary_edgedamage 12.5
set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_weaponthrowable 0
// }}}
-// {{{ #22: Overkill Rocket Propelled Chainsaw
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
+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_delay 0
+set g_balance_oknex_secondary_edgedamage 10
+set g_balance_oknex_secondary_force 0
+set g_balance_oknex_secondary_force_zscale 1
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 60
+set g_balance_oknex_secondary_refire 0
+set g_balance_oknex_secondary_refire_type 0
+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
+// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okrpc_secondary_edgedamage 12.5
set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okrpc_weaponthrowable 0
// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
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_force 375
+set g_balance_blaster_primary_force_zscale 1
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_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_force 360
+set g_balance_blaster_secondary_force_zscale 1
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_shotgun_reload_ammo 0
set g_balance_shotgun_reload_time 2
set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
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_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
set g_balance_shotgun_switchdelay_raise 0
set g_balance_shotgun_weaponreplace ""
set g_balance_shotgun_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
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_burst_spread 0.03
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 14
// }}}
// {{{ #8: Vortex
set g_balance_vortex_charge 0
+set g_balance_vortex_charge_always 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_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 400
+set g_balance_vaporizer_secondary_force 480
+set g_balance_vaporizer_secondary_force_zscale 1
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_seeker_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
+// {{{ #19: Shockwave
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_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_burst_damage 250
set g_balance_arc_burst_healing_aps 100
set g_balance_arc_burst_healing_hps 100
+set g_balance_arc_burst_heat 5
+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_switchdelay_drop 0
set g_balance_arc_switchdelay_raise 0
set g_balance_arc_weaponreplace ""
set g_balance_arc_weaponstartoverride -1
set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okhmg_secondary_edgedamage 12.5
set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_weaponthrowable 0
// }}}
-// {{{ #22: Overkill Rocket Propelled Chainsaw
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
+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_delay 0
+set g_balance_oknex_secondary_edgedamage 10
+set g_balance_oknex_secondary_force 0
+set g_balance_oknex_secondary_force_zscale 1
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 60
+set g_balance_oknex_secondary_refire 0
+set g_balance_oknex_secondary_refire_type 0
+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
+// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okrpc_secondary_edgedamage 12.5
set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okrpc_weaponthrowable 0
// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
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_force 375
+set g_balance_blaster_primary_force_zscale 1
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_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_force 360
+set g_balance_blaster_secondary_force_zscale 1
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_shotgun_reload_ammo 0
set g_balance_shotgun_reload_time 2
set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
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_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_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
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_burst_spread 0
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 14
// }}}
// {{{ #8: Vortex
set g_balance_vortex_charge 1
+set g_balance_vortex_charge_always 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_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 400
+set g_balance_vaporizer_secondary_force 480
+set g_balance_vaporizer_secondary_force_zscale 1
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_seeker_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
+// {{{ #19: Shockwave
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_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 1500
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_burst_heat 5
+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_switchdelay_drop 0.2
set g_balance_arc_switchdelay_raise 0.2
set g_balance_arc_weaponreplace ""
set g_balance_arc_weaponstartoverride -1
set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_solidpenetration 127
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_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_force 360
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_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
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
set g_balance_okmachinegun_primary_ammo 1
set g_balance_okmachinegun_primary_damage 25
set g_balance_okmachinegun_primary_force 5
set g_balance_okmachinegun_primary_refire 0.1
-set g_balance_okmachinegun_primary_solidpenetration 63
+set g_balance_okmachinegun_primary_solidpenetration 100
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_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_force 360
+set g_balance_okmachinegun_secondary_force_zscale 1
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_weaponstartoverride -1
set g_balance_okmachinegun_weaponthrowable 1
// }}}
-// {{{ Overkill Nex
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
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_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_force 360
+set g_balance_oknex_secondary_force_zscale 1
set g_balance_oknex_secondary_lifetime 5
set g_balance_oknex_secondary_radius 70
+set g_balance_oknex_secondary_refire 0.7
+set g_balance_oknex_secondary_refire_type 1
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_weaponstartoverride -1
set g_balance_oknex_weaponthrowable 1
// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
+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 360
+set g_balance_okrpc_secondary_force_zscale 1
+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
+// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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 360
+set g_balance_okshotgun_secondary_force_zscale 1
+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
+// }}}
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_force 375
+set g_balance_blaster_primary_force_zscale 1
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_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_force 360
+set g_balance_blaster_secondary_force_zscale 1
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_shotgun_reload_ammo 0
set g_balance_shotgun_reload_time 2
set g_balance_shotgun_secondary 1
+set g_balance_shotgun_secondary_alt_animtime 0.2
+set g_balance_shotgun_secondary_alt_refire 1.2
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_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_weaponstartoverride -1
set g_balance_shotgun_weaponthrowable 1
// }}}
-// {{{ #3: Machine Gun
+// {{{ #3: MachineGun
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_burst_spread 0
set g_balance_machinegun_first 1
set g_balance_machinegun_first_ammo 1
set g_balance_machinegun_first_damage 14
// }}}
// {{{ #8: Vortex
set g_balance_vortex_charge 1
+set g_balance_vortex_charge_always 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_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 400
+set g_balance_vaporizer_secondary_force 480
+set g_balance_vaporizer_secondary_force_zscale 1
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_seeker_weaponstartoverride -1
set g_balance_seeker_weaponthrowable 1
// }}}
-// {{{ #19: Shockwave (MUTATOR WEAPON)
+// {{{ #19: Shockwave
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_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_burst_damage 250
set g_balance_arc_burst_healing_aps 100
set g_balance_arc_burst_healing_hps 100
+set g_balance_arc_burst_heat 5
+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_switchdelay_drop 0.2
set g_balance_arc_switchdelay_raise 0.2
set g_balance_arc_weaponreplace ""
set g_balance_arc_weaponstartoverride -1
set g_balance_arc_weaponthrowable 1
// }}}
-// {{{ #21: Overkill Heavy Machine Gun
+// {{{ #21: Overkill Heavy Machine Gun (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okhmg_secondary_edgedamage 12.5
set g_balance_okhmg_secondary_force 300
+set g_balance_okhmg_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okhmg_weaponthrowable 0
// }}}
-// {{{ #22: Overkill Rocket Propelled Chainsaw
+// {{{ #22: Overkill MachineGun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
+// {{{ #23: Overkill Nex (MUTATOR WEAPON)
+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_delay 0
+set g_balance_oknex_secondary_edgedamage 10
+set g_balance_oknex_secondary_force 0
+set g_balance_oknex_secondary_force_zscale 1
+set g_balance_oknex_secondary_lifetime 5
+set g_balance_oknex_secondary_radius 60
+set g_balance_oknex_secondary_refire 0
+set g_balance_oknex_secondary_refire_type 0
+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
+// }}}
+// {{{ #24: Overkill Rocket Propelled Chainsaw (MUTATOR WEAPON)
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_secondary_delay 0
set g_balance_okrpc_secondary_edgedamage 12.5
set g_balance_okrpc_secondary_force 300
+set g_balance_okrpc_secondary_force_zscale 1
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_weaponstartoverride 0
set g_balance_okrpc_weaponthrowable 0
// }}}
+// {{{ #25: Overkill Shotgun (MUTATOR WEAPON)
+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_force_zscale 1
+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
+// }}}
set g_warmup_start_ammo_plasma 90 "starting values when being in warmup-stage"
set g_warmup_start_ammo_fuel 0 "starting values when being in warmup-stage"
set g_lms_start_health 200
-set g_lms_start_armor 200
+set g_lms_start_armor 100
set g_lms_start_ammo_shells 60
set g_lms_start_ammo_nails 320
set g_lms_start_ammo_rockets 160
set g_balance_pause_armor_rot_spawn 5
set g_balance_armor_regenstable 100
set g_balance_armor_rotstable 0
-set g_balance_armor_limit 200
+set g_balance_armor_limit 100
set g_balance_armor_blockpercent 0.6
set g_balance_fuel_regen 0.1 "fuel regeneration (only applies if the player owns IT_FUEL_REGEN)"
set g_balance_fuel_regenlinear 0
bind F11 disconnect
bind F12 screenshot
bind F4 ready
-bind ALT +showaccuracy
// Gamepad defaults. Tested with Logitech Rumblepad 2, I hope similar ones works as well.
bind JOY1 "+crouch"
seta "userbind32_press" ""; seta "userbind32_release" ""; seta "userbind32_description" ""
alias _userbind_call "${$1}"
alias +userbind "_userbind_call userbind${1}_press"
-alias -userbind "_userbind_call userbind${1}_release"
\ No newline at end of file
+alias -userbind "_userbind_call userbind${1}_release"
alias hud "qc_cmd_cl hud ${* ?}" // Commands regarding/controlling the HUD system
alias localprint "qc_cmd_cl localprint ${* ?}" // Create your own centerprint sent to yourself
//alias mv_download "qc_cmd_cl mv_download ${* ?}" // Retrieve mapshot picture from the server
-alias sendcvar "qc_cmd_cl sendcvar ${* ?}" // Send a cvar to the server (like weaponpriority)
+alias sendcvar "qc_cmd_cl sendcvar ${* ?}" // Send a cvar to the server (like cl_weaponpriority)
alias weapon_find "qc_cmd_cl weapon_find ${* ?}" // Show spawn locations of a weapon
alias exit "quit"
alias scoreboard_columns_help "qc_cmd_cl hud scoreboard_columns_help"
alias scoreboard_columns_set "qc_cmd_cl hud scoreboard_columns_set ${* ?}"
-// changes a cvar and reports it to the server (for the client to notify the server about changes)
-alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
-
// ========================================================
// cmd (client-to-server command) - server/command/cmd.qc
"Project-Id-Version: Xonotic\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2019-05-19 07:23+0200\n"
-"PO-Revision-Date: 2019-06-14 06:43+0000\n"
-"Last-Translator: Liang Liu <dxkliu@126.com>\n"
+"PO-Revision-Date: 2019-07-30 05:15+0000\n"
+"Last-Translator: 杜茂森 <dumaosen_main01@outlook.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/quickmenu.qc:806
msgid "QMCMD^dropped weapon %w^7 (l:%l^7)"
-msgstr ""
+msgstr "QMCMD^掉落武器 %w^7 (l:%l^7)"
#: qcsrc/client/hud/panel/quickmenu.qc:807
msgid "QMCMD^drop flag/key, icon"
-msgstr ""
+msgstr "QMCMD^掉落旗帜/钥匙, icon"
#: qcsrc/client/hud/panel/quickmenu.qc:807
msgid "QMCMD^dropped flag/key %w^7 (l:%l^7)"
// side-scrolling crosshair
seta crosshair_2d 54 "selects crosshair to use in side-scrolling mode (\"\" uses regular crosshair and 0 is none)"
+// third person chase-camera crosshair
+seta crosshair_chase 1 "adjust the crosshair while in third person mode to where the shot will actually hit"
+seta crosshair_chase_playeralpha 0.25 "opacity of the player while they obstruct the view when crosshair_chase is enabled, can be a value between 0 and 1"
+
// =========================
// Crosshair ring settings
seta g_ca_teams_override 0
set g_ca_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
set g_ca_teams 0
+set g_ca_weaponarena "most" "starting weapons - takes the same options as g_weaponarena"
// ==================
set g_ctf_stalemate_endcondition 1 "condition for stalemate mode to be finished: 1 = If ONE flag is no longer stale, 2 = If BOTH flags are no longer stale"
set g_ctf_stalemate_time 60 "time for each flag until stalemate mode is activated"
set g_ctf_flagcarrier_waypointforenemy_spotting 1 "show the enemy flagcarrier location if a team mate presses +use to spot them"
-set g_ctf_dropped_capture_delay 1 "dropped capture delay"
+set g_ctf_dropped_capture_delay 1.5 "autocapture delay when flag is thrown onto the base - counted from throw, not landing"
set g_ctf_dropped_capture_radius 100 "allow dropped flags to be automatically captured by base flags if the dropped flag is within this radius of it"
set g_ctf_flag_damageforcescale 2
set g_ctf_portalteleport 0 "allow flag carriers to go through portals made in portal gun without dropping the flag"
seta g_freezetag_teams_override 0
set g_freezetag_team_spawns 0 "when 1, players spawn from the team spawnpoints of the map, if any"
set g_freezetag_teams 0
+set g_freezetag_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
// ==========
set g_lms_regenerate 0
set g_lms_last_join 3 "if g_lms_join_anytime is false, new players can only join if the worst active player has more than (fraglimit - g_lms_last_join) lives"
set g_lms_join_anytime 1 "if true, new players can join, but get same amount of lives as the worst player"
+set g_lms_weaponarena "most_available" "starting weapons - takes the same options as g_weaponarena"
// =========
// ==========
// overkill
// ==========
-set g_overkill 0 "internal cvar, to enable overkill, use `exec ruleset-overkill.cfg`"
+set g_overkill 0 "internal cvar, to enable overkill, use `exec ruleset-overkill.cfg`"
set g_overkill_weapons 0 "Whether to enable overkill weapons outside of overkill ruleset."
-set g_overkill_powerups_replace 1
-set g_overkill_itemwaypoints 1
+set g_overkill_powerups_replace 1 "replace strength and shield with HMG and RPC"
+set g_overkill_itemwaypoints 1 "show waypoints with timer before health and armor spawns"
set g_overkill_filter_healthmega 0
-set g_overkill_filter_armormedium 0
-set g_overkill_filter_armorbig 0
+set g_overkill_filter_armormedium 1
+set g_overkill_filter_armorbig 1
set g_overkill_filter_armormega 0
g_mod_physics Overkill
sv_gravity 800
-sv_maxspeed 400
+sv_maxspeed 360
sv_maxairspeed 360
sv_stopspeed 100
sv_aircontrol_power 2
sv_aircontrol_backwards 0
sv_aircontrol_sidewards 0
-sv_airspeedlimit_nonqw 900
+sv_airspeedlimit_nonqw 800
sv_warsowbunny_turnaccel 0
sv_warsowbunny_accel 0.1593
sv_warsowbunny_topspeed 925
float autocvar_cl_announcer_maptime = 3;
bool autocvar_cl_autodemo_delete;
bool autocvar_cl_autodemo_delete_keeprecords;
-bool autocvar_cl_casings;
float autocvar_cl_casings_bronze_time;
int autocvar_cl_casings_maxcount = 100;
float autocvar_cl_casings_shell_time;
float autocvar_crosshair_ring_reload_alpha;
float autocvar_crosshair_ring_reload_size;
float autocvar_crosshair_size;
+bool autocvar_crosshair_chase = true;
+float crosshair_chase_playeralpha = 0.25;
int autocvar_ekg;
float autocvar_fov;
bool autocvar_hud_cursormode = true;
float autocvar_hud_panel_mapvote_highlight_border = 1;
bool autocvar_hud_panel_modicons;
int autocvar_hud_panel_modicons_ca_layout;
-int autocvar_hud_panel_modicons_dom_layout;
int autocvar_hud_panel_modicons_freezetag_layout;
bool autocvar_hud_panel_notify;
float autocvar_hud_panel_notify_fadetime;
case CMD_REQUEST_USAGE:
{
LOG_INFO("Usage:^3 cl_cmd sendcvar <cvar>");
- LOG_INFO(" Where 'cvar' is the cvar plus arguments to send to the server.");
+ LOG_INFO(" Where 'cvar' is the cvar to send to the server.");
return;
}
}
CLIENT_COMMAND(hud, "Commands regarding/controlling the HUD system") { LocalCommand_hud(request, arguments); }
CLIENT_COMMAND(localprint, "Create your own centerprint sent to yourself") { LocalCommand_localprint(request, arguments); }
CLIENT_COMMAND(mv_download, "Retrieve mapshot picture from the server") { LocalCommand_mv_download(request, arguments); }
-CLIENT_COMMAND(sendcvar, "Send a cvar to the server (like weaponpriority)") { LocalCommand_sendcvar(request, arguments); }
+CLIENT_COMMAND(sendcvar, "Send a cvar to the server (like cl_weaponpriority)") { LocalCommand_sendcvar(request, arguments); }
void LocalCommand_macro_help()
{
float w_issilent, w_random;
vector w_org, w_backoff;
+float autoswitch;
+bool cvar_cl_allow_uid2name;
+bool cvar_cl_allow_uidranking;
+float cvar_cl_autoscreenshot;
+float cvar_cl_autotaunt;
+float cvar_cl_clippedspectating;
+float cvar_cl_handicap;
+float cvar_cl_jetpack_jump;
+float cvar_cl_movement_track_canjump;
+float cvar_cl_noantilag;
+string cvar_cl_physics;
+float cvar_cl_voice_directional;
+float cvar_cl_voice_directional_taunt_attenuation;
+float cvar_cl_weaponimpulsemode;
+string cvar_g_xonoticversion;
+float cvar_cl_cts_noautoswitch;
+bool cvar_cl_weapon_switch_reload;
+bool cvar_cl_weapon_switch_fallback_to_impulse;
+
+REPLICATE(autoswitch, bool, "cl_autoswitch");
+REPLICATE(cvar_cl_allow_uid2name, bool, "cl_allow_uid2name");
+REPLICATE(cvar_cl_allow_uidranking, bool, "cl_allow_uidranking");
+REPLICATE(cvar_cl_autoscreenshot, int, "cl_autoscreenshot");
+REPLICATE(cvar_cl_autotaunt, float, "cl_autotaunt");
+REPLICATE(cvar_cl_clippedspectating, bool, "cl_clippedspectating");
+REPLICATE(cvar_cl_handicap, float, "cl_handicap");
+REPLICATE(cvar_cl_jetpack_jump, bool, "cl_jetpack_jump");
+REPLICATE(cvar_cl_movement_track_canjump, bool, "cl_movement_track_canjump");
+REPLICATE(cvar_cl_noantilag, bool, "cl_noantilag");
+REPLICATE(cvar_cl_physics, string, "cl_physics");
+REPLICATE(cvar_cl_voice_directional, int, "cl_voice_directional");
+REPLICATE(cvar_cl_voice_directional_taunt_attenuation, float, "cl_voice_directional_taunt_attenuation");
+REPLICATE(cvar_cl_weaponimpulsemode, int, "cl_weaponimpulsemode");
+REPLICATE(cvar_g_xonoticversion, string, "g_xonoticversion");
+REPLICATE(cvar_cl_cts_noautoswitch, bool, "cl_cts_noautoswitch");
+REPLICATE(cvar_cl_weapon_switch_reload, bool, "cl_weapon_switch_reload");
+REPLICATE(cvar_cl_weapon_switch_fallback_to_impulse, bool, "cl_weapon_switch_fallback_to_impulse");
+/*
+// this is also a STAT
+// pointless sending this cvars since server can't change gun alignment during the match
+int cvar_cl_gunalign;
+REPLICATE(cvar_cl_gunalign, int, "cl_gunalign");
+
+// cvar cl_newusekeysupported doesn't exist
+float cvar_cl_newusekeysupported;
+REPLICATE(cvar_cl_newusekeysupported, bool, "cl_newusekeysupported");
+*/
+string cvar_cl_allow_uidtracking;
+REPLICATE(cvar_cl_allow_uidtracking, string, "cl_allow_uidtracking");
+
+string cvar_cl_weaponpriority;
+REPLICATE(cvar_cl_weaponpriority, string, "cl_weaponpriority");
+
+string cvar_cl_weaponpriorities[10];
+REPLICATE(cvar_cl_weaponpriorities[0], string, "cl_weaponpriority0");
+REPLICATE(cvar_cl_weaponpriorities[1], string, "cl_weaponpriority1");
+REPLICATE(cvar_cl_weaponpriorities[2], string, "cl_weaponpriority2");
+REPLICATE(cvar_cl_weaponpriorities[3], string, "cl_weaponpriority3");
+REPLICATE(cvar_cl_weaponpriorities[4], string, "cl_weaponpriority4");
+REPLICATE(cvar_cl_weaponpriorities[5], string, "cl_weaponpriority5");
+REPLICATE(cvar_cl_weaponpriorities[6], string, "cl_weaponpriority6");
+REPLICATE(cvar_cl_weaponpriorities[7], string, "cl_weaponpriority7");
+REPLICATE(cvar_cl_weaponpriorities[8], string, "cl_weaponpriority8");
+REPLICATE(cvar_cl_weaponpriorities[9], string, "cl_weaponpriority9");
+
float bgmtime;
string weaponorder_byimpulse;
// Mod icons (#10)
-bool mod_active; // is there any active mod icon?
-
void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
{
TC(int, layout); TC(int, i);
}
}
-// CTF HUD modicon section
-int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
-int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
-float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
-
-void HUD_Mod_CTF_Reset()
-{
- redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
- redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
- redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
-}
-
-int autocvar__teams_available;
-void HUD_Mod_CTF(vector pos, vector mySize)
-{
- vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
- vector flag_size;
- float f; // every function should have that
-
- int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
- float redflag_statuschange_elapsedtime = 0, blueflag_statuschange_elapsedtime = 0, yellowflag_statuschange_elapsedtime = 0, pinkflag_statuschange_elapsedtime = 0, neutralflag_statuschange_elapsedtime = 0; // time since the status changed
- bool ctf_oneflag; // one-flag CTF mode enabled/disabled
- bool ctf_stalemate; // currently in stalemate
- int stat_items = STAT(CTF_FLAGSTATUS);
- float fs, fs2, fs3, size1, size2;
- vector e1, e2;
-
- int nteams = autocvar__teams_available;
-
- redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
- blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
- yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
- pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
- neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
-
- ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
-
- ctf_stalemate = (stat_items & CTF_STALEMATE);
-
- mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag || (stat_items & CTF_SHIELDED));
-
- if (autocvar__hud_configure) {
- redflag = 1;
- blueflag = 2;
- if (nteams & BIT(2))
- yellowflag = 2;
- if (nteams & BIT(3))
- pinkflag = 3;
- ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
- }
-
- // when status CHANGES, set old status into prevstatus and current status into status
- #define X(team) MACRO_BEGIN \
- if (team##flag != team##flag_prevframe) { \
- team##flag_statuschange_time = time; \
- team##flag_prevstatus = team##flag_prevframe; \
- team##flag_prevframe = team##flag; \
- } \
- team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time; \
- MACRO_END
- X(red);
- X(blue);
- X(yellow);
- X(pink);
- X(neutral);
- #undef X
-
- const float BLINK_FACTOR = 0.15;
- const float BLINK_BASE = 0.85;
- // note:
- // RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
- // thus
- // BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
- // ensure RMS == 1
- const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
-
- #define X(team, cond) \
- string team##_icon = string_null, team##_icon_prevstatus = string_null; \
- int team##_alpha, team##_alpha_prevstatus; \
- team##_alpha = team##_alpha_prevstatus = 1; \
- MACRO_BEGIN \
- switch (team##flag) { \
- case 1: team##_icon = "flag_" #team "_taken"; break; \
- case 2: team##_icon = "flag_" #team "_lost"; break; \
- case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
- default: \
- if ((stat_items & CTF_SHIELDED) && (cond)) { \
- team##_icon = "flag_" #team "_shielded"; \
- } else { \
- team##_icon = string_null; \
- } \
- break; \
- } \
- switch (team##flag_prevstatus) { \
- case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
- case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
- case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
- default: \
- if (team##flag == 3) { \
- team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
- } else if((stat_items & CTF_SHIELDED) && (cond)) { \
- team##_icon_prevstatus = "flag_" #team "_shielded"; \
- } else { \
- team##_icon_prevstatus = string_null; \
- } \
- break; \
- } \
- MACRO_END
- X(red, myteam != NUM_TEAM_1 && (nteams & BIT(0)));
- X(blue, myteam != NUM_TEAM_2 && (nteams & BIT(1)));
- X(yellow, myteam != NUM_TEAM_3 && (nteams & BIT(2)));
- X(pink, myteam != NUM_TEAM_4 && (nteams & BIT(3)));
- X(neutral, ctf_oneflag);
- #undef X
-
- int tcount = 2;
- if(nteams & BIT(2))
- tcount = 3;
- if(nteams & BIT(3))
- tcount = 4;
-
- if (ctf_oneflag) {
- // hacky, but these aren't needed
- red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
- fs = fs2 = fs3 = 1;
- } else switch (tcount) {
- default:
- case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
- case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
- case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
- }
-
- if (mySize_x > mySize_y) {
- size1 = mySize_x;
- size2 = mySize_y;
- e1 = eX;
- e2 = eY;
- } else {
- size1 = mySize_y;
- size2 = mySize_x;
- e1 = eY;
- e2 = eX;
- }
-
- switch (myteam) {
- default:
- case NUM_TEAM_1: {
- redflag_pos = pos;
- blueflag_pos = pos + eX * fs2 * size1;
- yellowflag_pos = pos - eX * fs2 * size1;
- pinkflag_pos = pos + eX * fs3 * size1;
- break;
- }
- case NUM_TEAM_2: {
- redflag_pos = pos + eX * fs2 * size1;
- blueflag_pos = pos;
- yellowflag_pos = pos - eX * fs2 * size1;
- pinkflag_pos = pos + eX * fs3 * size1;
- break;
- }
- case NUM_TEAM_3: {
- redflag_pos = pos + eX * fs3 * size1;
- blueflag_pos = pos - eX * fs2 * size1;
- yellowflag_pos = pos;
- pinkflag_pos = pos + eX * fs2 * size1;
- break;
- }
- case NUM_TEAM_4: {
- redflag_pos = pos - eX * fs2 * size1;
- blueflag_pos = pos + eX * fs3 * size1;
- yellowflag_pos = pos + eX * fs2 * size1;
- pinkflag_pos = pos;
- break;
- }
- }
- neutralflag_pos = pos;
- flag_size = e1 * fs * size1 + e2 * size2;
-
- #define X(team) MACRO_BEGIN \
- f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
- if (team##_icon && ctf_stalemate) \
- drawpic_aspect_skin(team##flag_pos, "flag_stalemate", flag_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); \
- if (team##_icon_prevstatus && f < 1) \
- drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
- if (team##_icon) \
- drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
- MACRO_END
- X(red);
- X(blue);
- X(yellow);
- X(pink);
- X(neutral);
- #undef X
-}
-
-// Keyhunt HUD modicon section
-vector KH_SLOTS[4];
-
-void HUD_Mod_KH(vector pos, vector mySize)
-{
- mod_active = 1; // keyhunt should never hide the mod icons panel
-
- // Read current state
- int state = STAT(KH_KEYS);
- if(!state) return;
-
- int i, key_state;
- int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
- all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
-
- for(i = 0; i < 4; ++i)
- {
- key_state = (bitshift(state, i * -5) & 31) - 1;
-
- if(key_state == -1)
- continue;
-
- if(key_state == 30)
- {
- ++carrying_keys;
- key_state = myteam;
- }
-
- switch(key_state)
- {
- case NUM_TEAM_1: ++team1_keys; break;
- case NUM_TEAM_2: ++team2_keys; break;
- case NUM_TEAM_3: ++team3_keys; break;
- case NUM_TEAM_4: ++team4_keys; break;
- case 29: ++dropped_keys; break;
- }
-
- ++all_keys;
- }
-
- // Calculate slot measurements
- vector slot_size;
- if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
- {
- // Quadratic arrangement
- slot_size = vec2(mySize.x * 0.5, mySize.y * 0.5);
- KH_SLOTS[0] = pos;
- KH_SLOTS[1] = pos + eX * slot_size.x;
- KH_SLOTS[2] = pos + eY * slot_size.y;
- KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
- }
- else
- {
- if(mySize.x > mySize.y)
- {
- // Horizontal arrangement
- slot_size = vec2(mySize.x / all_keys, mySize.y);
- for(i = 0; i < all_keys; ++i)
- KH_SLOTS[i] = pos + eX * slot_size.x * i;
- }
- else
- {
- // Vertical arrangement
- slot_size = vec2(mySize.x, mySize.y / all_keys);
- for(i = 0; i < all_keys; ++i)
- KH_SLOTS[i] = pos + eY * slot_size.y * i;
- }
- }
-
- // Make icons blink in case of RUN HERE
-
- float alpha = 1;
- if(carrying_keys)
- {
- float blink = 0.6 + sin(2 * M_PI * time) * 0.4; // Oscillate between 0.2 and 1
- switch(myteam)
- {
- case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
- case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
- }
- }
-
- // Draw icons
-
- i = 0;
-
- while(team1_keys--)
- if(myteam == NUM_TEAM_1 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team2_keys--)
- if(myteam == NUM_TEAM_2 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team3_keys--)
- if(myteam == NUM_TEAM_3 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(team4_keys--)
- if(myteam == NUM_TEAM_4 && carrying_keys)
- {
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
- --carrying_keys;
- }
- else
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-
- while(dropped_keys--)
- drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
-}
-
-// Keepaway HUD mod icon
-int kaball_prevstatus; // last remembered status
-float kaball_statuschange_time; // time when the status changed
-
-// we don't need to reset for keepaway since it immediately
-// autocorrects prevstatus as to if the player has the ball or not
-
-void HUD_Mod_Keepaway(vector pos, vector mySize)
-{
- mod_active = 1; // keepaway should always show the mod HUD
-
- float BLINK_FACTOR = 0.15;
- float BLINK_BASE = 0.85;
- float BLINK_FREQ = 5;
- float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
-
- int stat_items = STAT(ITEMS);
- int kaball = (stat_items/IT_KEY1) & 1;
-
- if(kaball != kaball_prevstatus)
- {
- kaball_statuschange_time = time;
- kaball_prevstatus = kaball;
- }
-
- vector kaball_pos, kaball_size;
-
- if(mySize.x > mySize.y) {
- kaball_pos = pos + eX * 0.25 * mySize.x;
- kaball_size = vec2(0.5 * mySize.x, mySize.y);
- } else {
- kaball_pos = pos + eY * 0.25 * mySize.y;
- kaball_size = vec2(mySize.x, 0.5 * mySize.y);
- }
-
- float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
- float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
-
- if(kaball_prevstatus && f < 1)
- drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
-
- if(kaball)
- drawpic_aspect_skin(pos, "keepawayball_carrying", vec2(mySize.x, mySize.y), '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
-}
-
-
-// Nexball HUD mod icon
-void HUD_Mod_NexBall(vector pos, vector mySize)
-{
- float nb_pb_starttime, dt, p;
- int stat_items;
-
- stat_items = STAT(ITEMS);
- nb_pb_starttime = STAT(NB_METERSTART);
-
- if (stat_items & IT_KEY1)
- mod_active = 1;
- else
- mod_active = 0;
-
- //Manage the progress bar if any
- if (nb_pb_starttime > 0)
- {
- dt = (time - nb_pb_starttime) % nb_pb_period;
- // one period of positive triangle
- p = 2 * dt / nb_pb_period;
- if (p > 1)
- p = 2 - p;
-
- HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- if (stat_items & IT_KEY1)
- drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
-}
-
// Race/CTS HUD mod icons
float crecordtime_prev; // last remembered crecordtime
float crecordtime_change_time; // time when crecordtime last changed
}
}
-void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
-{
- TC(int, layout); TC(int, i);
- float stat = -1;
- string pic = "";
- vector color = '0 0 0';
- switch(i)
- {
- case 0: stat = STAT(DOM_PPS_RED); pic = "dom_icon_red"; color = '1 0 0'; break;
- case 1: stat = STAT(DOM_PPS_BLUE); pic = "dom_icon_blue"; color = '0 0 1'; break;
- case 2: stat = STAT(DOM_PPS_YELLOW); pic = "dom_icon_yellow"; color = '1 1 0'; break;
- default:
- case 3: stat = STAT(DOM_PPS_PINK); pic = "dom_icon_pink"; color = '1 0 1'; break;
- }
- float pps_ratio = 0;
- if(STAT(DOM_TOTAL_PPS))
- pps_ratio = stat / STAT(DOM_TOTAL_PPS);
-
- if(mySize.x/mySize.y > aspect_ratio)
- {
- i = aspect_ratio * mySize.y;
- myPos.x = myPos.x + (mySize.x - i) / 2;
- mySize.x = i;
- }
- else
- {
- i = 1/aspect_ratio * mySize.x;
- myPos.y = myPos.y + (mySize.y - i) / 2;
- mySize.y = i;
- }
-
- if (layout) // show text too
- {
- //draw the text
- color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
- if (layout == 2) // average pps
- drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), vec2((2/3) * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
- else // percentage of average pps
- drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), vec2((2/3) * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
- }
-
- //draw the icon
- drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- if (stat > 0)
- {
- drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
- drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawresetcliparea();
- }
-}
-
-void HUD_Mod_Dom(vector myPos, vector mySize)
-{
- mod_active = 1; // required in each mod function that always shows something
-
- int layout = autocvar_hud_panel_modicons_dom_layout;
- int rows, columns;
- float aspect_ratio;
- aspect_ratio = (layout) ? 3 : 1;
- rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
- columns = ceil(team_count/rows);
-
- int i;
- float row = 0, column = 0;
- vector pos, itemSize;
- itemSize = vec2(mySize.x / columns, mySize.y / rows);
- for(i=0; i<team_count; ++i)
- {
- pos = myPos + vec2(column * itemSize.x, row * itemSize.y);
-
- DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
-
- ++row;
- if(row >= rows)
- {
- row = 0;
- ++column;
- }
- }
-}
-
void HUD_ModIcons_SetFunc()
{
HUD_ModIcons_GameType = gametype.m_modicons;
#pragma once
#include "../panel.qh"
+
+bool mod_active; // is there any active mod icon?
}
if (weapon_stats < 0 && !((weapons_stat & set) || (weapons_inmap & set)))
{
- if (((it.spawnflags & WEP_FLAG_HIDDEN) || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED)))
+ if (it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK))
++nHidden;
else
++disownedcnt;
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 | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)) nHidden += 1; \
}); \
vector table_size = HUD_GetTableSize_BestItemAR((Weapons_COUNT - 1) - nHidden, panel_size, aspect); \
columns = table_size.x; \
{
int j = 0;
FOREACH(Weapons, it != WEP_Null && it.impulse >= 0 && (it.impulse % 3 != 0) && j < 6, {
- if(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED))
+ if(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_SPECIALATTACK))
{
if(!panel_switchweapon || j < 4)
panel_switchweapon = it;
}
else
{
- if (((it.spawnflags & WEP_FLAG_HIDDEN) || (it.spawnflags & WEP_FLAG_MUTATORBLOCKED)) && !(weapons_stat & WepSet_FromWeapon(it)))
+ if (it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)
+ && !(weapons_stat & WepSet_FromWeapon(it)))
+ {
continue;
+ }
}
// figure out the drawing position of weapon
registercvar("cl_weapon_switch_reload", "1");
registercvar("cl_weapon_switch_fallback_to_impulse", "1");
+ registercvar("cl_allow_uidranking", "1");
+
if(autocvar_cl_lockview)
cvar_set("cl_lockview", "0");
deactivate_minigame();
HUD_MinigameMenu_Close(NULL, NULL, NULL);
+
+ ReplicateVars(true); // destroy
}
.float has_team;
.bool ready;
.bool eliminated;
-.void(entity) draw;
IntrusiveList g_drawables;
-STATIC_INIT(g_drawables) { g_drawables = IL_NEW(); }
-.void(entity) draw2d;
IntrusiveList g_drawables_2d;
-STATIC_INIT(g_drawables_2d) { g_drawables_2d = IL_NEW(); }
+IntrusiveList g_radarlinks;
+IntrusiveList g_radaricons;
+STATIC_INIT(main)
+{
+ g_drawables = IL_NEW();
+ g_drawables_2d = IL_NEW();
+ g_radarlinks = IL_NEW();
+ g_radaricons = IL_NEW();
+}
+
+.void(entity) draw;
+.void(entity) draw2d;
.void(entity) entremove;
float drawframetime;
vector view_origin, view_forward, view_right, view_up;
-IntrusiveList g_radarlinks;
-STATIC_INIT(g_radarlinks) { g_radarlinks = IL_NEW(); }
-IntrusiveList g_radaricons;
-STATIC_INIT(g_radaricons) { g_radaricons = IL_NEW(); }
bool button_zoom;
bool spectatorbutton_zoom;
return;
int mask = (intermission || (STAT(HEALTH) <= 0) || autocvar_chase_active) ? 0 : MASK_NORMAL;
float a = ((autocvar_cl_viewmodel_alpha) ? bound(-1, autocvar_cl_viewmodel_alpha, this.m_alpha) : this.m_alpha);
+ int wepskin = this.m_skin;
bool invehicle = player_localentnum > maxclients;
if (invehicle) a = -1;
Weapon wep = this.activeweapon;
{
e.drawmask = mask;
e.alpha = a;
+ e.skin = wepskin;
e.colormap = 256 + c; // colormap == 0 is black, c == 0 is white
e.glowmod = g;
e.csqcmodel_effects = fx;
showfps_prevfps_time = currentTime; // we must initialize it to avoid an instant low frame sending
}
-STATIC_INIT(Porto)
-{
- entity e = new_pure(porto);
- e.draw = Porto_Draw;
- IL_PUSH(g_drawables, e);
- e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
-}
-
-const int polyline_length = 16;
-.vector polyline[polyline_length];
-void Porto_Draw(entity this)
-{
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- entity wepent = viewmodels[slot];
-
- if (wepent.activeweapon != WEP_PORTO) continue;
- if (spectatee_status) continue;
- if (WEP_CVAR(porto, secondary)) continue;
- if (intermission == 1) continue;
- if (intermission == 2) continue;
- if (STAT(HEALTH) <= 0) continue;
-
- vector pos = view_origin;
- vector dir = view_forward;
- makevectors(((autocvar_chase_active) ? warpzone_save_view_angles : view_angles));
- pos += v_right * -wepent.movedir.y
- + v_up * wepent.movedir.z;
-
- if (wepent.angles_held_status)
- {
- makevectors(wepent.angles_held);
- dir = v_forward;
- }
-
- wepent.polyline[0] = pos;
-
- int portal_number = 0, portal1_idx = 1, portal_max = 2;
- int n = 1 + 2; // 2 lines == 3 points
- for (int idx = 0; idx < n && idx < polyline_length - 1; )
- {
- traceline(pos, pos + 65536 * dir, true, this);
- dir = reflect(dir, trace_plane_normal);
- pos = trace_endpos;
- wepent.polyline[++idx] = pos;
- if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
- {
- n += 1;
- continue;
- }
- if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
- {
- n = max(2, idx);
- break;
- }
- // check size
- {
- vector ang = vectoangles2(trace_plane_normal, dir);
- ang.x = -ang.x;
- makevectors(ang);
- if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
- {
- n = max(2, idx);
- break;
- }
- }
- portal_number += 1;
- if (portal_number >= portal_max) break;
- if (portal_number == 1) portal1_idx = idx;
- }
- for (int idx = 0; idx < n - 1; ++idx)
- {
- vector p = wepent.polyline[idx], q = wepent.polyline[idx + 1];
- if (idx == 0) p -= view_up * 16; // line from player
- vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1';
- Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin);
- }
- }
-}
-
float drawtime;
float avgspeed;
vector GetCurrentFov(float fov)
float TrueAimCheck(entity wepent)
{
+ if(wepent.activeweapon.spawnflags & WEP_FLAG_NOTRUEAIM)
+ return SHOTTYPE_HITWORLD;
+
float nudge = 1; // added to traceline target and subtracted from result TOOD(divVerent): do we still need this? Doesn't the engine do this now for us?
vector vecs, trueaimpoint, w_shotorg;
vector mi, ma, dv;
switch(wepent.activeweapon) // WEAPONTODO
{
- case WEP_TUBA: // no aim
- case WEP_PORTO: // shoots from eye
- case WEP_NEXBALL: // shoots from eye
- case WEP_HOOK: // no trueaim
- case WEP_MORTAR: // toss curve
- return SHOTTYPE_HITWORLD;
case WEP_VORTEX:
case WEP_OVERKILL_NEX:
case WEP_VAPORIZER:
// wcross_origin = '0.5 0 0' * vid_conwidth + '0 0.5 0' * vid_conheight;
if(csqcplayer.viewloc && (csqcplayer.viewloc.spawnflags & VIEWLOC_FREEAIM))
wcross_origin = viewloc_mousepos;
+ else if(autocvar_chase_active > 0 && autocvar_crosshair_chase)
+ {
+ vector player_org = ((csqcplayer) ? csqcplayer.origin + csqcplayer.view_ofs : view_origin);
+ if(csqcplayer && crosshair_chase_playeralpha && crosshair_chase_playeralpha < 1)
+ {
+ traceline(view_origin, view_origin + max_shot_distance * view_forward, MOVE_NORMAL, NULL);
+ if(trace_ent == csqcplayer)
+ csqcplayer.alpha = crosshair_chase_playeralpha;
+ else
+ csqcplayer.alpha = csqcplayer.m_alpha;
+ }
+ traceline(player_org, player_org + max_shot_distance * view_forward, MOVE_WORLDONLY, NULL);
+ wcross_origin = project_3d_to_2d(trace_endpos);
+ }
else
wcross_origin = project_3d_to_2d(view_origin + max_shot_distance * view_forward);
wcross_origin.z = 0;
lasthud = hud;
+ ReplicateVars(false);
+ if (ReplicateVars_NOT_SENDING())
+ ReplicateVars_DELAY(0.8 + random() * 0.4); // no need to check cvars every frame
+
HUD_Scale_Disable();
if(autocvar__hud_showbinds_reload) // menu can set this one
void calc_followmodel_ofs(entity view);
-void Porto_Draw(entity this);
-
void CSQC_Demo_Camera();
void TrueAim_Init();
// a bit more constant
const vector PL_MAX_CONST = '16 16 45';
const vector PL_MIN_CONST = '-16 -16 -24';
+const vector PL_CROUCH_MAX_CONST = '16 16 25';
+const vector PL_CROUCH_MIN_CONST = '-16 -16 -24';
// gametype vote flags
const int GTV_FORBIDDEN = 0; // Cannot be voted
# define TAG_VIEWLOC_NAME tag_networkviewloc
# define TAG_VIEWLOC_TYPE int
.float tag_networkviewloc;
+
+# define ALPHA m_alpha
+.float m_alpha;
#else
# define TAG_ENTITY_NAME tag_entity
# define TAG_ENTITY_TYPE entity
# define TAG_VIEWLOC_NAME viewloc
# define TAG_VIEWLOC_TYPE entity
+
+# define ALPHA alpha
#endif
// add properties you want networked to CSQC here
CSQCMODEL_PROPERTY(BIT(0), int, ReadShort, WriteShort, colormap) \
CSQCMODEL_PROPERTY(BIT(1), int, ReadInt24_t, WriteInt24_t, effects) \
CSQCMODEL_PROPERTY(BIT(2), int, ReadByte, WriteByte, modelflags) \
- CSQCMODEL_PROPERTY_SCALED(BIT(3), float, ReadByte, WriteByte, alpha, 254, -1, 254) \
+ CSQCMODEL_PROPERTY_SCALED(BIT(3), float, ReadByte, WriteByte, ALPHA, 254, -1, 254) \
CSQCMODEL_PROPERTY(BIT(4), int, ReadByte, WriteByte, skin) \
CSQCMODEL_PROPERTY(BIT(5), float, ReadApproxPastTime, WriteApproxPastTime, death_time) \
CSQCMODEL_PROPERTY(BIT(6), float, ReadByte, WriteByte, solid) \
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) << 12;
-const int DEATH_HITTYPEMASK = HITTYPE_SECONDARY | HITTYPE_SPLASH | HITTYPE_BOUNCE | HITTYPE_ARMORPIERCE | HITTYPE_RESERVED;
+const int HITTYPE_SOUND = BITS(1) << 12;
+const int DEATH_HITTYPEMASK = HITTYPE_SECONDARY | HITTYPE_SPLASH | HITTYPE_BOUNCE | HITTYPE_ARMORPIERCE | HITTYPE_SOUND;
// normal deaths begin
const int DT_FIRST = BIT(13);
REGISTER_NET_TEMP(casings)
+#if defined(SVQC)
+.bool cvar_cl_casings;
+#elif defined(CSQC)
+bool cvar_cl_casings;
+#endif
+REPLICATE(cvar_cl_casings, bool, "cl_casings");
+
#ifdef SVQC
void SpawnCasing(vector vel, float randomvel, vector ang, vector avel, float randomavel, int casingtype, entity casingowner, .entity weaponentity)
{
+ if (!(CS(casingowner).cvar_cl_casings))
+ return;
+
entity wep = casingowner.(weaponentity);
vector org = casingowner.origin + casingowner.view_ofs + wep.spawnorigin.x * v_forward - wep.spawnorigin.y * v_right + wep.spawnorigin.z * v_up;
ang_z = ReadByte() * 360 / 256;
return = true;
- if (!autocvar_cl_casings) return;
-
Casing casing = RubbleNew("casing");
casing.silent = (_state & 0x80);
casing.state = (_state & 0x7F);
NET_HANDLE(ENT_CLIENT_DAMAGEINFO, bool isNew)
{
- const float ATTEN_LOW = 0.2;
float thedamage, rad, edge, thisdmg;
bool hitplayer = false;
int species, forcemul;
w_random = prandom();
traceline(w_org - normalize(force) * 16, w_org + normalize(force) * 16, MOVE_NOMONSTERS, NULL);
- if(trace_fraction < 1 && hitwep != WEP_VORTEX && hitwep != WEP_VAPORIZER)
+ if(trace_fraction < 1 && !(hitwep.spawnflags & WEP_TYPE_HITSCAN))
w_backoff = trace_plane_normal;
else
w_backoff = -1 * normalize(force);
#include "sv_assault.qh"
+#include <common/mapobjects/func/breakable.qh>
+
.entity sprite;
#define AS_ROUND_DELAY 5
return true;
}
-spawnfunc(func_breakable);
spawnfunc(func_assault_destructible)
{
if (!g_assault) { delete(this); return; }
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, SetWeaponArena)
{
- // most weapons arena
- if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "") M_ARGV(0, string) = "most";
+ if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+ M_ARGV(0, string) = autocvar_g_ca_weaponarena;
+}
+
+MUTATOR_HOOKFUNCTION(ca, SV_ParseServerCommand)
+{
+ string cmd_name = M_ARGV(0, string);
+ if (cmd_name == "shuffleteams")
+ shuffleteams_on_reset_map = !allowed_to_spawn;
+ return false;
}
#include <common/mutators/base.qh>
#include <server/round_handler.qh>
#include <server/miscfunctions.qh>
+#include <server/command/sv_cmd.qh>
int autocvar_g_ca_point_limit;
int autocvar_g_ca_point_leadlimit;
//int autocvar_g_ca_teams;
int autocvar_g_ca_teams_override;
float autocvar_g_ca_warmup;
+string autocvar_g_ca_weaponarena = "most";
int ca_teams;
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/ctf/cl_ctf.qc>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/ctf/sv_ctf.qc>
#endif
// generated file; do not modify
#include <common/gamemodes/gamemode/ctf/ctf.qh>
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/ctf/cl_ctf.qh>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/ctf/sv_ctf.qh>
#endif
--- /dev/null
+#include "cl_ctf.qh"
+
+#include <client/hud/panel/modicons.qh>
+
+// CTF HUD modicon section
+int redflag_prevframe, blueflag_prevframe, yellowflag_prevframe, pinkflag_prevframe, neutralflag_prevframe; // status during previous frame
+int redflag_prevstatus, blueflag_prevstatus, yellowflag_prevstatus, pinkflag_prevstatus, neutralflag_prevstatus; // last remembered status
+float redflag_statuschange_time, blueflag_statuschange_time, yellowflag_statuschange_time, pinkflag_statuschange_time, neutralflag_statuschange_time; // time when the status changed
+
+void HUD_Mod_CTF_Reset()
+{
+ redflag_prevstatus = blueflag_prevstatus = yellowflag_prevstatus = pinkflag_prevstatus = neutralflag_prevstatus = 0;
+ redflag_prevframe = blueflag_prevframe = yellowflag_prevframe = pinkflag_prevframe = neutralflag_prevframe = 0;
+ redflag_statuschange_time = blueflag_statuschange_time = yellowflag_statuschange_time = pinkflag_statuschange_time = neutralflag_statuschange_time = 0;
+}
+
+int autocvar__teams_available;
+void HUD_Mod_CTF(vector pos, vector mySize)
+{
+ vector redflag_pos, blueflag_pos, yellowflag_pos, pinkflag_pos, neutralflag_pos;
+ vector flag_size;
+ float f; // every function should have that
+
+ int redflag, blueflag, yellowflag, pinkflag, neutralflag; // current status
+ float redflag_statuschange_elapsedtime = 0, blueflag_statuschange_elapsedtime = 0, yellowflag_statuschange_elapsedtime = 0, pinkflag_statuschange_elapsedtime = 0, neutralflag_statuschange_elapsedtime = 0; // time since the status changed
+ bool ctf_oneflag; // one-flag CTF mode enabled/disabled
+ bool ctf_stalemate; // currently in stalemate
+ int stat_items = STAT(CTF_FLAGSTATUS);
+ float fs, fs2, fs3, size1, size2;
+ vector e1, e2;
+
+ int nteams = autocvar__teams_available;
+
+ redflag = (stat_items/CTF_RED_FLAG_TAKEN) & 3;
+ blueflag = (stat_items/CTF_BLUE_FLAG_TAKEN) & 3;
+ yellowflag = (stat_items/CTF_YELLOW_FLAG_TAKEN) & 3;
+ pinkflag = (stat_items/CTF_PINK_FLAG_TAKEN) & 3;
+ neutralflag = (stat_items/CTF_NEUTRAL_FLAG_TAKEN) & 3;
+
+ ctf_oneflag = (stat_items & CTF_FLAG_NEUTRAL);
+
+ ctf_stalemate = (stat_items & CTF_STALEMATE);
+
+ mod_active = (redflag || blueflag || yellowflag || pinkflag || neutralflag || (stat_items & CTF_SHIELDED));
+
+ if (autocvar__hud_configure) {
+ redflag = 1;
+ blueflag = 2;
+ if (nteams & BIT(2))
+ yellowflag = 2;
+ if (nteams & BIT(3))
+ pinkflag = 3;
+ ctf_oneflag = neutralflag = 0; // disable neutral flag in hud editor?
+ }
+
+ // when status CHANGES, set old status into prevstatus and current status into status
+ #define X(team) MACRO_BEGIN \
+ if (team##flag != team##flag_prevframe) { \
+ team##flag_statuschange_time = time; \
+ team##flag_prevstatus = team##flag_prevframe; \
+ team##flag_prevframe = team##flag; \
+ } \
+ team##flag_statuschange_elapsedtime = time - team##flag_statuschange_time; \
+ MACRO_END
+ X(red);
+ X(blue);
+ X(yellow);
+ X(pink);
+ X(neutral);
+ #undef X
+
+ const float BLINK_FACTOR = 0.15;
+ const float BLINK_BASE = 0.85;
+ // note:
+ // RMS = sqrt(BLINK_BASE^2 + 0.5 * BLINK_FACTOR^2)
+ // thus
+ // BLINK_BASE = sqrt(RMS^2 - 0.5 * BLINK_FACTOR^2)
+ // ensure RMS == 1
+ const float BLINK_FREQ = 5; // circle frequency, = 2*pi*frequency in hertz
+
+ #define X(team, cond) \
+ string team##_icon = string_null, team##_icon_prevstatus = string_null; \
+ int team##_alpha, team##_alpha_prevstatus; \
+ team##_alpha = team##_alpha_prevstatus = 1; \
+ MACRO_BEGIN \
+ switch (team##flag) { \
+ case 1: team##_icon = "flag_" #team "_taken"; break; \
+ case 2: team##_icon = "flag_" #team "_lost"; break; \
+ case 3: team##_icon = "flag_" #team "_carrying"; team##_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+ default: \
+ if ((stat_items & CTF_SHIELDED) && (cond)) { \
+ team##_icon = "flag_" #team "_shielded"; \
+ } else { \
+ team##_icon = string_null; \
+ } \
+ break; \
+ } \
+ switch (team##flag_prevstatus) { \
+ case 1: team##_icon_prevstatus = "flag_" #team "_taken"; break; \
+ case 2: team##_icon_prevstatus = "flag_" #team "_lost"; break; \
+ case 3: team##_icon_prevstatus = "flag_" #team "_carrying"; team##_alpha_prevstatus = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ); break; \
+ default: \
+ if (team##flag == 3) { \
+ team##_icon_prevstatus = "flag_" #team "_carrying"; /* make it more visible */\
+ } else if((stat_items & CTF_SHIELDED) && (cond)) { \
+ team##_icon_prevstatus = "flag_" #team "_shielded"; \
+ } else { \
+ team##_icon_prevstatus = string_null; \
+ } \
+ break; \
+ } \
+ MACRO_END
+ X(red, myteam != NUM_TEAM_1 && (nteams & BIT(0)));
+ X(blue, myteam != NUM_TEAM_2 && (nteams & BIT(1)));
+ X(yellow, myteam != NUM_TEAM_3 && (nteams & BIT(2)));
+ X(pink, myteam != NUM_TEAM_4 && (nteams & BIT(3)));
+ X(neutral, ctf_oneflag);
+ #undef X
+
+ int tcount = 2;
+ if(nteams & BIT(2))
+ tcount = 3;
+ if(nteams & BIT(3))
+ tcount = 4;
+
+ if (ctf_oneflag) {
+ // hacky, but these aren't needed
+ red_icon = red_icon_prevstatus = blue_icon = blue_icon_prevstatus = yellow_icon = yellow_icon_prevstatus = pink_icon = pink_icon_prevstatus = string_null;
+ fs = fs2 = fs3 = 1;
+ } else switch (tcount) {
+ default:
+ case 2: fs = 0.5; fs2 = 0.5; fs3 = 0.5; break;
+ case 3: fs = 1; fs2 = 0.35; fs3 = 0.35; break;
+ case 4: fs = 0.75; fs2 = 0.25; fs3 = 0.5; break;
+ }
+
+ if (mySize_x > mySize_y) {
+ size1 = mySize_x;
+ size2 = mySize_y;
+ e1 = eX;
+ e2 = eY;
+ } else {
+ size1 = mySize_y;
+ size2 = mySize_x;
+ e1 = eY;
+ e2 = eX;
+ }
+
+ switch (myteam) {
+ default:
+ case NUM_TEAM_1: {
+ redflag_pos = pos;
+ blueflag_pos = pos + eX * fs2 * size1;
+ yellowflag_pos = pos - eX * fs2 * size1;
+ pinkflag_pos = pos + eX * fs3 * size1;
+ break;
+ }
+ case NUM_TEAM_2: {
+ redflag_pos = pos + eX * fs2 * size1;
+ blueflag_pos = pos;
+ yellowflag_pos = pos - eX * fs2 * size1;
+ pinkflag_pos = pos + eX * fs3 * size1;
+ break;
+ }
+ case NUM_TEAM_3: {
+ redflag_pos = pos + eX * fs3 * size1;
+ blueflag_pos = pos - eX * fs2 * size1;
+ yellowflag_pos = pos;
+ pinkflag_pos = pos + eX * fs2 * size1;
+ break;
+ }
+ case NUM_TEAM_4: {
+ redflag_pos = pos - eX * fs2 * size1;
+ blueflag_pos = pos + eX * fs3 * size1;
+ yellowflag_pos = pos + eX * fs2 * size1;
+ pinkflag_pos = pos;
+ break;
+ }
+ }
+ neutralflag_pos = pos;
+ flag_size = e1 * fs * size1 + e2 * size2;
+
+ #define X(team) MACRO_BEGIN \
+ f = bound(0, team##flag_statuschange_elapsedtime * 2, 1); \
+ if (team##_icon && ctf_stalemate) \
+ drawpic_aspect_skin(team##flag_pos, "flag_stalemate", flag_size, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL); \
+ if (team##_icon_prevstatus && f < 1) \
+ drawpic_aspect_skin_expanding(team##flag_pos, team##_icon_prevstatus, flag_size, '1 1 1', panel_fg_alpha * team##_alpha_prevstatus, DRAWFLAG_NORMAL, f); \
+ if (team##_icon) \
+ drawpic_aspect_skin(team##flag_pos, team##_icon, flag_size, '1 1 1', panel_fg_alpha * team##_alpha * f, DRAWFLAG_NORMAL); \
+ MACRO_END
+ X(red);
+ X(blue);
+ X(yellow);
+ X(pink);
+ X(neutral);
+ #undef X
+}
--- /dev/null
+#pragma once
+
+#include "ctf.qh"
+
+void HUD_Mod_CTF_Reset();
+void HUD_Mod_CTF(vector pos, vector mySize);
ctf_Handle_Throw(frag_target, NULL, DROP_THROW);
}
+MUTATOR_HOOKFUNCTION(ctf, LogDeath_AppendItemCodes)
+{
+ entity player = M_ARGV(0, entity);
+ if(player.flagcarried)
+ M_ARGV(1, string) = strcat(M_ARGV(1, string), "F"); // item codes
+}
+
// ==========
// Spawnfuncs
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); }
+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?
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/domination/cl_domination.qc>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/domination/sv_domination.qc>
#endif
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/domination/cl_domination.qh>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/domination/sv_domination.qh>
#endif
--- /dev/null
+#include "cl_domination.qh"
+
+#include <client/hud/panel/modicons.qh>
+
+int autocvar_hud_panel_modicons_dom_layout;
+
+void DrawDomItem(vector myPos, vector mySize, float aspect_ratio, int layout, int i)
+{
+ TC(int, layout); TC(int, i);
+ float stat = -1;
+ string pic = "";
+ vector color = '0 0 0';
+ switch(i)
+ {
+ case 0: stat = STAT(DOM_PPS_RED); pic = "dom_icon_red"; color = '1 0 0'; break;
+ case 1: stat = STAT(DOM_PPS_BLUE); pic = "dom_icon_blue"; color = '0 0 1'; break;
+ case 2: stat = STAT(DOM_PPS_YELLOW); pic = "dom_icon_yellow"; color = '1 1 0'; break;
+ default:
+ case 3: stat = STAT(DOM_PPS_PINK); pic = "dom_icon_pink"; color = '1 0 1'; break;
+ }
+ float pps_ratio = 0;
+ if(STAT(DOM_TOTAL_PPS))
+ pps_ratio = stat / STAT(DOM_TOTAL_PPS);
+
+ if(mySize.x/mySize.y > aspect_ratio)
+ {
+ i = aspect_ratio * mySize.y;
+ myPos.x = myPos.x + (mySize.x - i) / 2;
+ mySize.x = i;
+ }
+ else
+ {
+ i = 1/aspect_ratio * mySize.x;
+ myPos.y = myPos.y + (mySize.y - i) / 2;
+ mySize.y = i;
+ }
+
+ if (layout) // show text too
+ {
+ //draw the text
+ color *= 0.5 + pps_ratio * (1 - 0.5); // half saturated color at min, full saturated at max
+ if (layout == 2) // average pps
+ drawstring_aspect(myPos + eX * mySize.y, ftos_decimals(stat, 2), vec2((2/3) * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ else // percentage of average pps
+ drawstring_aspect(myPos + eX * mySize.y, strcat( ftos(floor(pps_ratio*100 + 0.5)), "%" ), vec2((2/3) * mySize.x, mySize.y), color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ //draw the icon
+ drawpic_aspect_skin(myPos, pic, '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ if (stat > 0)
+ {
+ drawsetcliparea(myPos.x, myPos.y + mySize.y * (1 - pps_ratio), mySize.y, mySize.y * pps_ratio);
+ drawpic_aspect_skin(myPos, strcat(pic, "-highlighted"), '1 1 0' * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawresetcliparea();
+ }
+}
+
+void HUD_Mod_Dom(vector myPos, vector mySize)
+{
+ mod_active = 1; // required in each mod function that always shows something
+
+ int layout = autocvar_hud_panel_modicons_dom_layout;
+ int rows, columns;
+ float aspect_ratio;
+ aspect_ratio = (layout) ? 3 : 1;
+ rows = HUD_GetRowCount(team_count, mySize, aspect_ratio);
+ columns = ceil(team_count/rows);
+
+ int i;
+ float row = 0, column = 0;
+ vector pos, itemSize;
+ itemSize = vec2(mySize.x / columns, mySize.y / rows);
+ for(i=0; i<team_count; ++i)
+ {
+ pos = myPos + vec2(column * itemSize.x, row * itemSize.y);
+
+ DrawDomItem(pos, itemSize, aspect_ratio, layout, i);
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
+ }
+}
--- /dev/null
+#pragma once
+
+void HUD_Mod_Dom(vector myPos, vector mySize);
if (STAT(FROZEN, frag_target) == FROZEN_NORMAL)
Unfreeze(frag_target, true);
freezetag_count_alive_players();
- return true; // let the player die so that he can respawn whenever he wants
+ frag_target.respawn_time = time;
+ frag_target.respawn_flags |= RESPAWN_FORCE;
+ return true;
}
// Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
{
- // most weapons arena
if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
- M_ARGV(0, string) = "most";
+ M_ARGV(0, string) = autocvar_g_freezetag_weaponarena;
}
MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
return true;
}
+MUTATOR_HOOKFUNCTION(ft, SV_ParseServerCommand)
+{
+ string cmd_name = M_ARGV(0, string);
+ if (cmd_name == "shuffleteams")
+ shuffleteams_on_reset_map = !(round_handler_IsActive() && !round_handler_IsRoundStarted());
+ return false;
+}
+
void freezetag_Initialize()
{
freezetag_teams = autocvar_g_freezetag_teams_override;
#pragma once
#include <common/mutators/base.qh>
+#include <server/command/sv_cmd.qh>
+
int autocvar_g_freezetag_point_limit;
int autocvar_g_freezetag_point_leadlimit;
bool autocvar_g_freezetag_team_spawns;
+string autocvar_g_freezetag_weaponarena = "most_available";
+
void freezetag_Initialize();
REGISTER_MUTATOR(ft, false)
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/keepaway/cl_keepaway.qc>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/keepaway/sv_keepaway.qc>
#endif
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/keepaway/cl_keepaway.qh>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/keepaway/sv_keepaway.qh>
#endif
--- /dev/null
+#include "cl_keepaway.qh"
+
+#include <client/hud/panel/modicons.qh>
+
+// Keepaway HUD mod icon
+int kaball_prevstatus; // last remembered status
+float kaball_statuschange_time; // time when the status changed
+
+// we don't need to reset for keepaway since it immediately
+// autocorrects prevstatus as to if the player has the ball or not
+
+void HUD_Mod_Keepaway(vector pos, vector mySize)
+{
+ mod_active = 1; // keepaway should always show the mod HUD
+
+ float BLINK_FACTOR = 0.15;
+ float BLINK_BASE = 0.85;
+ float BLINK_FREQ = 5;
+ float kaball_alpha = BLINK_BASE + BLINK_FACTOR * cos(time * BLINK_FREQ);
+
+ int stat_items = STAT(ITEMS);
+ int kaball = (stat_items/IT_KEY1) & 1;
+
+ if(kaball != kaball_prevstatus)
+ {
+ kaball_statuschange_time = time;
+ kaball_prevstatus = kaball;
+ }
+
+ vector kaball_pos, kaball_size;
+
+ if(mySize.x > mySize.y) {
+ kaball_pos = pos + eX * 0.25 * mySize.x;
+ kaball_size = vec2(0.5 * mySize.x, mySize.y);
+ } else {
+ kaball_pos = pos + eY * 0.25 * mySize.y;
+ kaball_size = vec2(mySize.x, 0.5 * mySize.y);
+ }
+
+ float kaball_statuschange_elapsedtime = time - kaball_statuschange_time;
+ float f = bound(0, kaball_statuschange_elapsedtime*2, 1);
+
+ if(kaball_prevstatus && f < 1)
+ drawpic_aspect_skin_expanding(kaball_pos, "keepawayball_carrying", kaball_size, '1 1 1', panel_fg_alpha * kaball_alpha, DRAWFLAG_NORMAL, f);
+
+ if(kaball)
+ drawpic_aspect_skin(pos, "keepawayball_carrying", vec2(mySize.x, mySize.y), '1 1 1', panel_fg_alpha * kaball_alpha * f, DRAWFLAG_NORMAL);
+}
--- /dev/null
+#pragma once
+
+void HUD_Mod_Keepaway(vector pos, vector mySize);
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/keyhunt/cl_keyhunt.qc>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/keyhunt/sv_keyhunt.qc>
#endif
// generated file; do not modify
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/keyhunt/cl_keyhunt.qh>
+#endif
#ifdef SVQC
#include <common/gamemodes/gamemode/keyhunt/sv_keyhunt.qh>
#endif
--- /dev/null
+#include "cl_keyhunt.qh"
+
+#include <client/hud/panel/modicons.qh>
+
+// Keyhunt HUD modicon section
+vector KH_SLOTS[4];
+
+void HUD_Mod_KH(vector pos, vector mySize)
+{
+ mod_active = 1; // keyhunt should never hide the mod icons panel
+
+ // Read current state
+ int state = STAT(KH_KEYS);
+ if(!state) return;
+
+ int i, key_state;
+ int all_keys, team1_keys, team2_keys, team3_keys, team4_keys, dropped_keys, carrying_keys;
+ all_keys = team1_keys = team2_keys = team3_keys = team4_keys = dropped_keys = carrying_keys = 0;
+
+ for(i = 0; i < 4; ++i)
+ {
+ key_state = (bitshift(state, i * -5) & 31) - 1;
+
+ if(key_state == -1)
+ continue;
+
+ if(key_state == 30)
+ {
+ ++carrying_keys;
+ key_state = myteam;
+ }
+
+ switch(key_state)
+ {
+ case NUM_TEAM_1: ++team1_keys; break;
+ case NUM_TEAM_2: ++team2_keys; break;
+ case NUM_TEAM_3: ++team3_keys; break;
+ case NUM_TEAM_4: ++team4_keys; break;
+ case 29: ++dropped_keys; break;
+ }
+
+ ++all_keys;
+ }
+
+ // Calculate slot measurements
+ vector slot_size;
+ if(all_keys == 4 && mySize.x * 0.5 < mySize.y && mySize.y * 0.5 < mySize.x)
+ {
+ // Quadratic arrangement
+ slot_size = vec2(mySize.x * 0.5, mySize.y * 0.5);
+ KH_SLOTS[0] = pos;
+ KH_SLOTS[1] = pos + eX * slot_size.x;
+ KH_SLOTS[2] = pos + eY * slot_size.y;
+ KH_SLOTS[3] = pos + eX * slot_size.x + eY * slot_size.y;
+ }
+ else
+ {
+ if(mySize.x > mySize.y)
+ {
+ // Horizontal arrangement
+ slot_size = vec2(mySize.x / all_keys, mySize.y);
+ for(i = 0; i < all_keys; ++i)
+ KH_SLOTS[i] = pos + eX * slot_size.x * i;
+ }
+ else
+ {
+ // Vertical arrangement
+ slot_size = vec2(mySize.x, mySize.y / all_keys);
+ for(i = 0; i < all_keys; ++i)
+ KH_SLOTS[i] = pos + eY * slot_size.y * i;
+ }
+ }
+
+ // Make icons blink in case of RUN HERE
+
+ float alpha = 1;
+ if(carrying_keys)
+ {
+ float blink = 0.6 + sin(2 * M_PI * time) * 0.4; // Oscillate between 0.2 and 1
+ switch(myteam)
+ {
+ case NUM_TEAM_1: if(team1_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_2: if(team2_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_3: if(team3_keys == all_keys) alpha = blink; break;
+ case NUM_TEAM_4: if(team4_keys == all_keys) alpha = blink; break;
+ }
+ }
+
+ // Draw icons
+
+ i = 0;
+
+ while(team1_keys--)
+ if(myteam == NUM_TEAM_1 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_red_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team2_keys--)
+ if(myteam == NUM_TEAM_2 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_blue_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team3_keys--)
+ if(myteam == NUM_TEAM_3 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_yellow_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(team4_keys--)
+ if(myteam == NUM_TEAM_4 && carrying_keys)
+ {
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_carrying", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+ --carrying_keys;
+ }
+ else
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_pink_taken", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+
+ while(dropped_keys--)
+ drawpic_aspect_skin(KH_SLOTS[i++], "kh_dropped", slot_size, '1 1 1', alpha, DRAWFLAG_NORMAL);
+}
--- /dev/null
+#pragma once
+
+void HUD_Mod_KH(vector pos, vector mySize);
int autocvar_g_keyhunt_teams_override;
// #define KH_PLAYER_USE_ATTACHMENT
+// TODO? no model exists for this
// #define KH_PLAYER_USE_CARRIEDMODEL
#ifdef KH_PLAYER_USE_ATTACHMENT
return 0;
}
-//entity kh_worldkeylist;
-.entity kh_worldkeynext;
entity kh_controller;
//bool kh_tracking_enabled;
int kh_teams;
return true;
}
+MUTATOR_HOOKFUNCTION(kh, LogDeath_AppendItemCodes)
+{
+ entity player = M_ARGV(0, entity);
+ if(player.kh_next)
+ M_ARGV(1, string) = strcat(M_ARGV(1, string), "K"); // item codes
+}
+
MUTATOR_HOOKFUNCTION(kh, DropSpecialItems)
{
entity frag_target = M_ARGV(0, entity);
return 0;
}
+entity kh_worldkeylist;
+.entity kh_worldkeynext;
+
#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
return true;
}
-MUTATOR_HOOKFUNCTION(lms, WantWeapon)
+MUTATOR_HOOKFUNCTION(lms, SetWeaponArena)
{
- M_ARGV(2, bool) = true; // all weapons
+ if(M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
+ M_ARGV(0, string) = autocvar_g_lms_weaponarena;
}
MUTATOR_HOOKFUNCTION(lms, GetPlayerStatus)
#include <common/mutators/base.qh>
#include <common/scores.qh>
+
.float lms_spectate_warning;
+
#define autocvar_g_lms_lives_override cvar("g_lms_lives_override")
+string autocvar_g_lms_weaponarena = "most_available";
+
void lms_Initialize();
REGISTER_MUTATOR(lms, false)
// generated file; do not modify
-#include <common/gamemodes/gamemode/nexball/nexball.qc>
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/nexball/cl_nexball.qc>
+#endif
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/nexball/sv_nexball.qc>
+#endif
#include <common/gamemodes/gamemode/nexball/weapon.qc>
#ifdef SVQC
#include <common/gamemodes/gamemode/nexball/sv_weapon.qc>
// generated file; do not modify
-#include <common/gamemodes/gamemode/nexball/nexball.qh>
+#ifdef CSQC
+ #include <common/gamemodes/gamemode/nexball/cl_nexball.qh>
+#endif
+#ifdef SVQC
+ #include <common/gamemodes/gamemode/nexball/sv_nexball.qh>
+#endif
#include <common/gamemodes/gamemode/nexball/weapon.qh>
#ifdef SVQC
#include <common/gamemodes/gamemode/nexball/sv_weapon.qh>
--- /dev/null
+#include "cl_nexball.qh"
+
+#include <client/hud/panel/modicons.qh>
+
+// Nexball HUD mod icon
+void HUD_Mod_NexBall(vector pos, vector mySize)
+{
+ float nb_pb_starttime, dt, p;
+ int stat_items;
+
+ stat_items = STAT(ITEMS);
+ nb_pb_starttime = STAT(NB_METERSTART);
+
+ if (stat_items & IT_KEY1)
+ mod_active = 1;
+ else
+ mod_active = 0;
+
+ //Manage the progress bar if any
+ if (nb_pb_starttime > 0)
+ {
+ dt = (time - nb_pb_starttime) % nb_pb_period;
+ // one period of positive triangle
+ p = 2 * dt / nb_pb_period;
+ if (p > 1)
+ p = 2 - p;
+
+ HUD_Panel_DrawProgressBar(pos, mySize, "progressbar", p, (mySize.x <= mySize.y), 0, autocvar_hud_progressbar_nexball_color, autocvar_hud_progressbar_alpha * panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ if (stat_items & IT_KEY1)
+ drawpic_aspect_skin(pos, "nexball_carrying", eX * mySize.x + eY * mySize.y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+int autocvar_cl_eventchase_nexball = 1;
+
+REGISTER_MUTATOR(cl_nb, true);
+
+MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase)
+{
+ if(autocvar_cl_eventchase_nexball && ISGAMETYPE(NEXBALL) && !(WepSet_GetFromStat() & WEPSET(NEXBALL)))
+ return true;
+ return false;
+}
--- /dev/null
+#pragma once
+
+void HUD_Mod_NexBall(vector pos, vector mySize);
+++ /dev/null
-#include "nexball.qh"
-
-#ifdef CSQC
-int autocvar_cl_eventchase_nexball = 1;
-
-REGISTER_MUTATOR(cl_nb, true);
-
-MUTATOR_HOOKFUNCTION(cl_nb, WantEventchase)
-{
- if(autocvar_cl_eventchase_nexball && ISGAMETYPE(NEXBALL) && !(WepSet_GetFromStat() & WEPSET(NEXBALL)))
- return true;
- return false;
-}
-#endif
-#ifdef SVQC
-.entity ballcarried;
-
-int autocvar_g_nexball_goalleadlimit;
-#define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit")
-
-bool autocvar_g_nexball_basketball_jumppad = true;
-float autocvar_g_nexball_basketball_bouncefactor;
-float autocvar_g_nexball_basketball_bouncestop;
-float autocvar_g_nexball_basketball_carrier_highspeed;
-bool autocvar_g_nexball_basketball_meter;
-float autocvar_g_nexball_basketball_meter_maxpower;
-float autocvar_g_nexball_basketball_meter_minpower;
-float autocvar_g_nexball_delay_collect;
-float autocvar_g_nexball_delay_goal;
-float autocvar_g_nexball_delay_start;
-bool autocvar_g_nexball_football_jumppad = true;
-float autocvar_g_nexball_football_bouncefactor;
-float autocvar_g_nexball_football_bouncestop;
-bool autocvar_g_nexball_radar_showallplayers;
-bool autocvar_g_nexball_sound_bounce;
-int autocvar_g_nexball_trail_color;
-bool autocvar_g_nexball_playerclip_collisions = true;
-
-float autocvar_g_nexball_safepass_turnrate;
-float autocvar_g_nexball_safepass_maxdist;
-float autocvar_g_nexball_safepass_holdtime;
-float autocvar_g_nexball_viewmodel_scale;
-float autocvar_g_nexball_tackling;
-vector autocvar_g_nexball_viewmodel_offset;
-
-float autocvar_g_balance_nexball_primary_animtime;
-float autocvar_g_balance_nexball_primary_refire;
-float autocvar_g_balance_nexball_primary_speed;
-float autocvar_g_balance_nexball_secondary_animtime;
-float autocvar_g_balance_nexball_secondary_force;
-float autocvar_g_balance_nexball_secondary_lifetime;
-float autocvar_g_balance_nexball_secondary_refire;
-float autocvar_g_balance_nexball_secondary_speed;
-
-void basketball_touch(entity this, entity toucher);
-void football_touch(entity this, entity toucher);
-void ResetBall(entity this);
-const int NBM_NONE = 0;
-const int NBM_FOOTBALL = 2;
-const int NBM_BASKETBALL = 4;
-float nexball_mode;
-
-float OtherTeam(float t) //works only if there are two teams on the map!
-{
- entity e;
- e = find(NULL, classname, "nexball_team");
- if(e.team == t)
- e = find(e, classname, "nexball_team");
- return e.team;
-}
-
-const int ST_NEXBALL_GOALS = 1;
-void nb_ScoreRules(int teams)
-{
- GameRules_scoring(teams, 0, 0, {
- field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
- field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
- field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
- });
-}
-
-void LogNB(string mode, entity actor)
-{
- string s;
- if(!autocvar_sv_eventlog)
- return;
- s = strcat(":nexball:", mode);
- if(actor != NULL)
- s = strcat(s, ":", ftos(actor.playerid));
- GameLogEcho(s);
-}
-
-void ball_restart(entity this)
-{
- if(this.owner)
- DropBall(this, this.owner.origin, '0 0 0');
- ResetBall(this);
-}
-
-void nexball_setstatus(entity this)
-{
- this.items &= ~IT_KEY1;
- if(this.ballcarried)
- {
- if(this.ballcarried.teamtime && (this.ballcarried.teamtime < time))
- {
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
- entity e = this.ballcarried;
- DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0');
- ResetBall(e);
- }
- else
- this.items |= IT_KEY1;
- }
-}
-
-void relocate_nexball(entity this)
-{
- tracebox(this.origin, BALL_MINS, BALL_MAXS, this.origin, true, this);
- if(trace_startsolid)
- {
- vector o = this.origin;
- if (!move_out_of_solid(this)) {
- objerror(this, "could not get out of solid at all!");
- }
- LOG_INFOF(
- "^1NOTE: this map needs FIXING. %s at %s needs to be moved out of solid, e.g. by %s",
- this.classname,
- vtos(o - '0 0 1'),
- vtos(this.origin - o)
- );
- this.origin = o;
- }
-}
-
-void DropOwner(entity this)
-{
- entity ownr;
- ownr = this.owner;
- DropBall(this, ownr.origin, ownr.velocity);
- makevectors(ownr.v_angle.y * '0 1 0');
- ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
- UNSET_ONGROUND(ownr);
-}
-
-void GiveBall(entity plyr, entity ball)
-{
- .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
- entity ownr = ball.owner;
- if(ownr)
- {
- ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
- ownr.ballcarried = NULL;
- GameRules_scoring_vip(ownr, false);
- if(STAT(NB_METERSTART, ownr))
- {
- STAT(NB_METERSTART, ownr) = 0;
- ownr.(weaponentity).state = WS_READY;
- }
- WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
- }
- else
- {
- WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
- }
-
- //setattachment(ball, plyr, "");
- setorigin(ball, plyr.origin + plyr.view_ofs);
-
- if(ball.team != plyr.team)
- ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
-
- ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
- ball.weaponentity_fld = weaponentity;
- ball.team = plyr.team;
- plyr.ballcarried = ball;
- GameRules_scoring_vip(plyr, true);
- ball.nb_dropper = plyr;
-
- plyr.effects |= autocvar_g_nexball_basketball_effects_default;
- ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
- ball.velocity = '0 0 0';
- set_movetype(ball, MOVETYPE_NONE);
- settouch(ball, func_null);
- ball.effects |= EF_NOSHADOW;
- ball.scale = 1; // scale down.
-
- WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
- WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- if(autocvar_g_nexball_basketball_delay_hold)
- {
- setthink(ball, DropOwner);
- ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
- }
-
- STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
- plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
- STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
- Weapon w = WEP_NEXBALL;
- w.wr_resetplayer(w, plyr);
- plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
- W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity);
-}
-
-void DropBall(entity ball, vector org, vector vel)
-{
- ball.effects |= autocvar_g_nexball_basketball_effects_default;
- ball.effects &= ~EF_NOSHADOW;
- ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
-
- setattachment(ball, NULL, "");
- setorigin(ball, org);
- set_movetype(ball, MOVETYPE_BOUNCE);
- UNSET_ONGROUND(ball);
- ball.scale = ball_scale;
- ball.velocity = vel;
- ball.nb_droptime = time;
- settouch(ball, basketball_touch);
- setthink(ball, ResetBall);
- ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
-
- if(STAT(NB_METERSTART, ball.owner))
- {
- STAT(NB_METERSTART, ball.owner) = 0;
- .entity weaponentity = ball.weaponentity_fld;
- ball.owner.(weaponentity).state = WS_READY;
- }
-
- WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
- WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
- WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
-
- entity e = ball.owner; ball.owner = NULL;
- e.ballcarried = NULL;
- GameRules_scoring_vip(e, false);
-}
-
-void InitBall(entity this)
-{
- if(game_stopped) return;
- UNSET_ONGROUND(this);
- set_movetype(this, MOVETYPE_BOUNCE);
- if(this.classname == "nexball_basketball")
- settouch(this, basketball_touch);
- else if(this.classname == "nexball_football")
- settouch(this, football_touch);
- this.cnt = 0;
- setthink(this, ResetBall);
- this.nextthink = time + autocvar_g_nexball_delay_idle + 3;
- this.teamtime = 0;
- this.pusher = NULL;
- this.team = false;
- _sound(this, CH_TRIGGER, this.noise1, VOL_BASE, ATTEN_NORM);
- WaypointSprite_Ping(this.waypointsprite_attachedforcarrier);
- LogNB("init", NULL);
-}
-
-void ResetBall(entity this)
-{
- if(this.cnt < 2) // step 1
- {
- if(time == this.teamtime)
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
-
- settouch(this, func_null);
- set_movetype(this, MOVETYPE_NOCLIP);
- this.velocity = '0 0 0'; // just in case?
- if(!this.cnt)
- LogNB("resetidle", NULL);
- this.cnt = 2;
- this.nextthink = time;
- }
- else if(this.cnt < 4) // step 2 and 3
- {
-// dprint("Step ", ftos(this.cnt), ": Calculated velocity: ", vtos(this.spawnorigin - this.origin), ", time: ", ftos(time), "\n");
- this.velocity = (this.spawnorigin - this.origin) * (this.cnt - 1); // 1 or 0.5 second movement
- this.nextthink = time + 0.5;
- this.cnt += 1;
- }
- else // step 4
- {
-// dprint("Step 4: time: ", ftos(time), "\n");
- if(vdist(this.origin - this.spawnorigin, >, 10)) // should not happen anymore
- LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
- vtos(this.origin - this.spawnorigin), " Velocity: ", vtos(this.velocity), "\n");
- this.velocity = '0 0 0';
- setorigin(this, this.spawnorigin); // make sure it's positioned correctly anyway
- set_movetype(this, MOVETYPE_NONE);
- setthink(this, InitBall);
- this.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
- }
-}
-
-void football_touch(entity this, entity toucher)
-{
- if(toucher.solid == SOLID_BSP)
- {
- if(time > this.lastground + 0.1)
- {
- _sound(this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
- this.lastground = time;
- }
- if(this.velocity && !this.cnt)
- this.nextthink = time + autocvar_g_nexball_delay_idle;
- return;
- }
- if (!IS_PLAYER(toucher) && !IS_VEHICLE(toucher))
- return;
- if(GetResource(toucher, RES_HEALTH) < 1)
- return;
- if(!this.cnt)
- this.nextthink = time + autocvar_g_nexball_delay_idle;
-
- this.pusher = toucher;
- this.team = toucher.team;
-
- if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
- {
- if(toucher.velocity)
- this.velocity = toucher.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
- }
- else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
- {
- makevectors(toucher.v_angle);
- this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
- }
- else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
- {
- makevectors(toucher.v_angle.y * '0 1 0');
- this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
- }
- else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
- {
- makevectors(toucher.v_angle);
- this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
- }
- this.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
-}
-
-void basketball_touch(entity this, entity toucher)
-{
- if(toucher.ballcarried)
- {
- football_touch(this, toucher);
- return;
- }
- if(!this.cnt && IS_PLAYER(toucher) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (toucher != this.nb_dropper || time > this.nb_droptime + autocvar_g_nexball_delay_collect))
- {
- if(GetResource(toucher, RES_HEALTH) < 1)
- return;
- LogNB("caught", toucher);
- GiveBall(toucher, this);
- }
- else if(toucher.solid == SOLID_BSP)
- {
- _sound(this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
- if(this.velocity && !this.cnt)
- this.nextthink = min(time + autocvar_g_nexball_delay_idle, this.teamtime);
- }
-}
-
-void GoalTouch(entity this, entity toucher)
-{
- entity ball;
- float isclient, pscore, otherteam;
- string pname;
-
- if(game_stopped) return;
- if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried)
- ball = toucher.ballcarried;
- else
- ball = toucher;
- if(ball.classname != "nexball_basketball")
- if(ball.classname != "nexball_football")
- return;
- if((!ball.pusher && this.team != GOAL_OUT) || ball.cnt)
- return;
- EXACTTRIGGER_TOUCH(this, toucher);
-
-
- if(NumTeams(nb_teams) == 2)
- otherteam = OtherTeam(ball.team);
- else
- otherteam = 0;
-
- if((isclient = IS_CLIENT(ball.pusher)))
- pname = ball.pusher.netname;
- else
- pname = "Someone (?)";
-
- if(ball.team == this.team) //owngoal (regular goals)
- {
- LogNB("owngoal", ball.pusher);
- bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
- pscore = -1;
- }
- else if(this.team == GOAL_FAULT)
- {
- LogNB("fault", ball.pusher);
- if(NumTeams(nb_teams) == 2)
- bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
- else
- bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
- pscore = -1;
- }
- else if(this.team == GOAL_OUT)
- {
- LogNB("out", ball.pusher);
- if((this.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
- bprint(pname, "^7 went out of bounds.\n");
- else
- bprint("The ball was returned.\n");
- pscore = 0;
- }
- else //score
- {
- LogNB(strcat("goal:", ftos(this.team)), ball.pusher);
- bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
- pscore = 1;
- }
-
- _sound(ball, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NONE);
-
- if(ball.team && pscore)
- {
- if(NumTeams(nb_teams) == 2 && pscore < 0)
- TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
- else
- TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
- }
- if(isclient)
- {
- if(pscore > 0)
- GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore);
- else if(pscore < 0)
- GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore);
- }
-
- if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
- DropBall(ball, ball.owner.origin, ball.owner.velocity);
-
- WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
-
- ball.cnt = 1;
- setthink(ball, ResetBall);
- if(ball.classname == "nexball_basketball")
- settouch(ball, football_touch); // better than func_null: football control until the ball gets reset
- ball.nextthink = time + autocvar_g_nexball_delay_goal * (this.team != GOAL_OUT);
-}
-
-//=======================//
-// team ents //
-//=======================//
-spawnfunc(nexball_team)
-{
- if(!g_nexball)
- {
- delete(this);
- return;
- }
- this.team = this.cnt + 1;
-}
-
-void nb_spawnteam(string teamname, float teamcolor)
-{
- LOG_TRACE("^2spawned team ", teamname);
- entity e = new(nexball_team);
- e.netname = teamname;
- e.cnt = teamcolor;
- e.team = e.cnt + 1;
- //nb_teams += 1;
-}
-
-void nb_spawnteams()
-{
- bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
- entity e;
- for(e = NULL; (e = find(e, classname, "nexball_goal"));)
- {
- switch(e.team)
- {
- case NUM_TEAM_1:
- if(!t_red)
- {
- nb_spawnteam("Red", e.team-1) ;
- nb_teams |= BIT(0);
- t_red = true;
- }
- break;
- case NUM_TEAM_2:
- if(!t_blue)
- {
- nb_spawnteam("Blue", e.team-1) ;
- t_blue = true;
- nb_teams |= BIT(1);
- }
- break;
- case NUM_TEAM_3:
- if(!t_yellow)
- {
- nb_spawnteam("Yellow", e.team-1);
- t_yellow = true;
- nb_teams |= BIT(2);
- }
- break;
- case NUM_TEAM_4:
- if(!t_pink)
- {
- nb_spawnteam("Pink", e.team-1) ;
- t_pink = true;
- nb_teams |= BIT(3);
- }
- break;
- }
- }
-}
-
-void nb_delayedinit(entity this)
-{
- if(find(NULL, classname, "nexball_team") == NULL)
- nb_spawnteams();
- nb_ScoreRules(nb_teams);
-}
-
-
-//=======================//
-// spawnfuncs //
-//=======================//
-
-void SpawnBall(entity this)
-{
- if(!g_nexball) { delete(this); return; }
-
-// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
-
- if(this.model == "")
- {
- this.model = "models/nexball/ball.md3";
- this.scale = 1.3;
- }
-
- precache_model(this.model);
- _setmodel(this, this.model);
- setsize(this, BALL_MINS, BALL_MAXS);
- ball_scale = this.scale;
-
- relocate_nexball(this);
- this.spawnorigin = this.origin;
-
- this.effects = this.effects | EF_LOWPRECISION;
-
- if(cvar(strcat("g_", this.classname, "_trail"))) //nexball_basketball :p
- {
- this.glow_color = autocvar_g_nexball_trail_color;
- this.glow_trail = true;
- }
-
- set_movetype(this, MOVETYPE_FLY);
-
- if(autocvar_g_nexball_playerclip_collisions)
- this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
-
- if(!autocvar_g_nexball_sound_bounce)
- this.noise = "";
- else if(this.noise == "")
- this.noise = strzone(SND(NB_BOUNCE));
- //bounce sound placeholder (FIXME)
- if(this.noise1 == "")
- this.noise1 = strzone(SND(NB_DROP));
- //ball drop sound placeholder (FIXME)
- if(this.noise2 == "")
- this.noise2 = strzone(SND(NB_STEAL));
- //stealing sound placeholder (FIXME)
- if(this.noise) precache_sound(this.noise);
- precache_sound(this.noise1);
- precache_sound(this.noise2);
-
- WaypointSprite_AttachCarrier(WP_NbBall, this, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
-
- this.reset = ball_restart;
- setthink(this, InitBall);
- this.nextthink = game_starttime + autocvar_g_nexball_delay_start;
-}
-
-spawnfunc(nexball_basketball)
-{
- nexball_mode |= NBM_BASKETBALL;
- this.classname = "nexball_basketball";
- if (!(balls & BALL_BASKET))
- {
- /*
- CVTOV(g_nexball_basketball_effects_default);
- CVTOV(g_nexball_basketball_delay_hold);
- CVTOV(g_nexball_basketball_delay_hold_forteam);
- CVTOV(g_nexball_basketball_teamsteal);
- */
- autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
- }
- if(!this.effects)
- this.effects = autocvar_g_nexball_basketball_effects_default;
- this.solid = SOLID_TRIGGER;
- this.pushable = autocvar_g_nexball_basketball_jumppad;
- balls |= BALL_BASKET;
- this.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
- this.bouncestop = autocvar_g_nexball_basketball_bouncestop;
- SpawnBall(this);
-}
-
-spawnfunc(nexball_football)
-{
- nexball_mode |= NBM_FOOTBALL;
- this.classname = "nexball_football";
- this.solid = SOLID_TRIGGER;
- balls |= BALL_FOOT;
- this.pushable = autocvar_g_nexball_football_jumppad;
- this.bouncefactor = autocvar_g_nexball_football_bouncefactor;
- this.bouncestop = autocvar_g_nexball_football_bouncestop;
- SpawnBall(this);
-}
-
-bool nb_Goal_Customize(entity this, entity client)
-{
- entity e = WaypointSprite_getviewentity(client);
- entity wp_owner = this.owner;
- if(SAME_TEAM(e, wp_owner)) { return false; }
-
- return true;
-}
-
-void SpawnGoal(entity this)
-{
- if(!g_nexball) { delete(this); return; }
-
- EXACTTRIGGER_INIT;
-
- if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
- {
- entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
- wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
- setcefc(this.sprite, nb_Goal_Customize);
- }
-
- this.classname = "nexball_goal";
- if(this.noise == "")
- this.noise = "ctf/respawn.wav";
- precache_sound(this.noise);
- settouch(this, GoalTouch);
-}
-
-spawnfunc(nexball_redgoal)
-{
- this.team = NUM_TEAM_1;
- SpawnGoal(this);
-}
-spawnfunc(nexball_bluegoal)
-{
- this.team = NUM_TEAM_2;
- SpawnGoal(this);
-}
-spawnfunc(nexball_yellowgoal)
-{
- this.team = NUM_TEAM_3;
- SpawnGoal(this);
-}
-spawnfunc(nexball_pinkgoal)
-{
- this.team = NUM_TEAM_4;
- SpawnGoal(this);
-}
-
-spawnfunc(nexball_fault)
-{
- this.team = GOAL_FAULT;
- if(this.noise == "")
- this.noise = strzone(SND(TYPEHIT));
- SpawnGoal(this);
-}
-
-spawnfunc(nexball_out)
-{
- this.team = GOAL_OUT;
- if(this.noise == "")
- this.noise = strzone(SND(TYPEHIT));
- SpawnGoal(this);
-}
-
-//
-//Spawnfuncs preserved for compatibility
-//
-
-spawnfunc(ball)
-{
- spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_football)
-{
- spawnfunc_nexball_football(this);
-}
-spawnfunc(ball_basketball)
-{
- spawnfunc_nexball_basketball(this);
-}
-// The "red goal" is defended by blue team. A ball in there counts as a point for red.
-spawnfunc(ball_redgoal)
-{
- spawnfunc_nexball_bluegoal(this); // I blame Revenant
-}
-spawnfunc(ball_bluegoal)
-{
- spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
-}
-spawnfunc(ball_fault)
-{
- spawnfunc_nexball_fault(this);
-}
-spawnfunc(ball_bound)
-{
- spawnfunc_nexball_out(this);
-}
-
-bool ball_customize(entity this, entity client)
-{
- if(!this.owner)
- {
- this.effects &= ~EF_FLAME;
- this.scale = 1;
- setcefc(this, func_null);
- return true;
- }
-
- if(client == this.owner)
- {
- this.scale = autocvar_g_nexball_viewmodel_scale;
- if(this.enemy)
- this.effects |= EF_FLAME;
- else
- this.effects &= ~EF_FLAME;
- }
- else
- {
- this.effects &= ~EF_FLAME;
- this.scale = 1;
- }
-
- return true;
-}
-
-void nb_DropBall(entity player)
-{
- if(player.ballcarried && g_nexball)
- DropBall(player.ballcarried, player.origin, player.velocity);
-}
-
-MUTATOR_HOOKFUNCTION(nb, ClientDisconnect)
-{
- entity player = M_ARGV(0, entity);
-
- nb_DropBall(player);
-}
-
-MUTATOR_HOOKFUNCTION(nb, PlayerDies)
-{
- entity frag_target = M_ARGV(2, entity);
-
- nb_DropBall(frag_target);
-}
-
-MUTATOR_HOOKFUNCTION(nb, MakePlayerObserver)
-{
- entity player = M_ARGV(0, entity);
-
- nb_DropBall(player);
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nb, PlayerPreThink)
-{
- entity player = M_ARGV(0, entity);
-
- makevectors(player.v_angle);
- if(nexball_mode & NBM_BASKETBALL)
- {
- if(player.ballcarried)
- {
- // 'view ball'
- player.ballcarried.velocity = player.velocity;
- setcefc(player.ballcarried, ball_customize);
-
- vector org = player.origin + player.view_ofs +
- v_forward * autocvar_g_nexball_viewmodel_offset.x +
- v_right * autocvar_g_nexball_viewmodel_offset.y +
- v_up * autocvar_g_nexball_viewmodel_offset.z;
- setorigin(player.ballcarried, org);
-
- // 'safe passing'
- if(autocvar_g_nexball_safepass_maxdist)
- {
- if(player.ballcarried.wait < time && player.ballcarried.enemy)
- {
- //centerprint(player, sprintf("Lost lock on %s", player.ballcarried.enemy.netname));
- player.ballcarried.enemy = NULL;
- }
-
-
- //tracebox(player.origin + player.view_ofs, '-2 -2 -2', '2 2 2', player.origin + player.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
- crosshair_trace(player);
- if( trace_ent &&
- IS_CLIENT(trace_ent) &&
- !IS_DEAD(trace_ent) &&
- trace_ent.team == player.team &&
- vdist(trace_ent.origin - player.origin, <=, autocvar_g_nexball_safepass_maxdist) )
- {
-
- //if(player.ballcarried.enemy != trace_ent)
- // centerprint(player, sprintf("Locked to %s", trace_ent.netname));
- player.ballcarried.enemy = trace_ent;
- player.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
-
-
- }
- }
- }
- else
- {
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
-
- if(STAT(WEAPONS, player.(weaponentity)))
- {
- 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);
-
- STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
- }
- }
- }
-
- }
-
- nexball_setstatus(player);
-}
-
-MUTATOR_HOOKFUNCTION(nb, SpectateCopy)
-{
- entity spectatee = M_ARGV(0, entity);
- entity client = M_ARGV(1, entity);
-
- STAT(NB_METERSTART, client) = STAT(NB_METERSTART, spectatee);
-}
-
-MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
-{
- entity player = M_ARGV(0, entity);
-
- STAT(NB_METERSTART, player) = 0;
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
- {
- .entity weaponentity = weaponentities[slot];
- STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
- }
-
- if (nexball_mode & NBM_BASKETBALL)
- STAT(WEAPONS, player) |= WEPSET(NEXBALL);
- else
- STAT(WEAPONS, player) = '0 0 0';
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nb, PlayerPhysics_UpdateStats)
-{
- entity player = M_ARGV(0, entity);
- // these automatically reset, no need to worry
-
- if(player.ballcarried)
- STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nexball_basketball_carrier_highspeed;
-}
-
-MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon)
-{
- //entity player = M_ARGV(0, entity);
- entity wepent = M_ARGV(1, entity);
-
- return wepent.m_weapon == WEP_NEXBALL;
-}
-
-MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon)
-{
- //entity player = M_ARGV(0, entity);
- int wep = M_ARGV(1, int);
-
- return wep == WEP_MORTAR.m_id; // TODO: what is this for?
-}
-
-MUTATOR_HOOKFUNCTION(nb, FilterItem)
-{
- entity item = M_ARGV(0, entity);
-
- if(Item_IsLoot(item))
- if(item.weapon == WEP_NEXBALL.m_id)
- return true;
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nb, ItemTouch)
-{
- entity item = M_ARGV(0, entity);
- entity toucher = M_ARGV(1, entity);
-
- if(item.weapon && toucher.ballcarried)
- return MUT_ITEMTOUCH_RETURN; // no new weapons for you, mister!
-
- return MUT_ITEMTOUCH_CONTINUE;
-}
-
-MUTATOR_HOOKFUNCTION(nb, TeamBalance_CheckAllowedTeams)
-{
- M_ARGV(1, string) = "nexball_team";
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(nb, WantWeapon)
-{
- M_ARGV(1, float) = 0; // weapon is set a few lines later, apparently
- return true;
-}
-
-MUTATOR_HOOKFUNCTION(nb, DropSpecialItems)
-{
- entity frag_target = M_ARGV(0, entity);
-
- if(frag_target.ballcarried)
- DropBall(frag_target.ballcarried, frag_target.origin, frag_target.velocity);
-
- return false;
-}
-
-MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
-{
- M_ARGV(2, int) &= ~0x80;
-}
-
-REGISTER_MUTATOR(nb, g_nexball)
-{
- MUTATOR_STATIC();
- MUTATOR_ONADD
- {
- g_nexball_meter_period = autocvar_g_nexball_meter_period;
- if(g_nexball_meter_period <= 0)
- g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
- g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
-
- // General settings
- /*
- CVTOV(g_nexball_football_boost_forward); //100
- CVTOV(g_nexball_football_boost_up); //200
- CVTOV(g_nexball_delay_idle); //10
- CVTOV(g_nexball_football_physics); //0
- */
- radar_showennemies = autocvar_g_nexball_radar_showallplayers;
-
- InitializeEntity(NULL, nb_delayedinit, INITPRIO_GAMETYPE);
- WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
-
- GameRules_teams(true);
- GameRules_limit_score(autocvar_g_nexball_goallimit);
- GameRules_limit_lead(autocvar_g_nexball_goalleadlimit);
- }
-
- MUTATOR_ONROLLBACK_OR_REMOVE
- {
- WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
- }
- return 0;
-}
-
-#endif
+++ /dev/null
-#pragma once
-
-#ifdef SVQC
-//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
-const float BALL_EFFECTMASK = 1229;
-const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
-const vector BALL_MAXS = '16 16 16';
-const vector BALL_ATTACHORG = '3 0 16';
-const float BALL_FOOT = 1;
-const float BALL_BASKET = 2;
-//spawnflags
-const float GOAL_TOUCHPLAYER = 1;
-//goal types
-const float GOAL_FAULT = -1;
-const float GOAL_OUT = -2;
-
-void DropBall(entity ball, vector org, vector vel);
-float autocvar_g_nexball_football_boost_forward;
-float autocvar_g_nexball_football_boost_up;
-float autocvar_g_nexball_football_physics;
-float autocvar_g_nexball_delay_idle;
-float autocvar_g_nexball_basketball_delay_hold;
-float autocvar_g_nexball_basketball_delay_hold_forteam;
-float autocvar_g_nexball_basketball_effects_default;
-float autocvar_g_nexball_basketball_teamsteal;
-float autocvar_g_nexball_meter_period;
-
-float balls;
-float ball_scale;
-float nb_teams;
-
-.entity nb_dropper;
-.float nb_droptime;
-
-.float teamtime;
-#endif
--- /dev/null
+#include "sv_nexball.qh"
+
+.entity ballcarried;
+
+int autocvar_g_nexball_goalleadlimit;
+#define autocvar_g_nexball_goallimit cvar("g_nexball_goallimit")
+
+bool autocvar_g_nexball_basketball_jumppad = true;
+float autocvar_g_nexball_basketball_bouncefactor;
+float autocvar_g_nexball_basketball_bouncestop;
+float autocvar_g_nexball_basketball_carrier_highspeed;
+bool autocvar_g_nexball_basketball_meter;
+float autocvar_g_nexball_basketball_meter_maxpower;
+float autocvar_g_nexball_basketball_meter_minpower;
+float autocvar_g_nexball_delay_collect;
+float autocvar_g_nexball_delay_goal;
+float autocvar_g_nexball_delay_start;
+bool autocvar_g_nexball_football_jumppad = true;
+float autocvar_g_nexball_football_bouncefactor;
+float autocvar_g_nexball_football_bouncestop;
+bool autocvar_g_nexball_radar_showallplayers;
+bool autocvar_g_nexball_sound_bounce;
+int autocvar_g_nexball_trail_color;
+bool autocvar_g_nexball_playerclip_collisions = true;
+
+float autocvar_g_nexball_safepass_turnrate;
+float autocvar_g_nexball_safepass_maxdist;
+float autocvar_g_nexball_safepass_holdtime;
+float autocvar_g_nexball_viewmodel_scale;
+float autocvar_g_nexball_tackling;
+vector autocvar_g_nexball_viewmodel_offset;
+
+float autocvar_g_balance_nexball_primary_animtime;
+float autocvar_g_balance_nexball_primary_refire;
+float autocvar_g_balance_nexball_primary_speed;
+float autocvar_g_balance_nexball_secondary_animtime;
+float autocvar_g_balance_nexball_secondary_force;
+float autocvar_g_balance_nexball_secondary_lifetime;
+float autocvar_g_balance_nexball_secondary_refire;
+float autocvar_g_balance_nexball_secondary_speed;
+
+void basketball_touch(entity this, entity toucher);
+void football_touch(entity this, entity toucher);
+void ResetBall(entity this);
+const int NBM_NONE = 0;
+const int NBM_FOOTBALL = 2;
+const int NBM_BASKETBALL = 4;
+float nexball_mode;
+
+float OtherTeam(float t) //works only if there are two teams on the map!
+{
+ entity e;
+ e = find(NULL, classname, "nexball_team");
+ if(e.team == t)
+ e = find(e, classname, "nexball_team");
+ return e.team;
+}
+
+const int ST_NEXBALL_GOALS = 1;
+void nb_ScoreRules(int teams)
+{
+ GameRules_scoring(teams, 0, 0, {
+ field_team(ST_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+ field(SP_NEXBALL_GOALS, "goals", SFL_SORT_PRIO_PRIMARY);
+ field(SP_NEXBALL_FAULTS, "faults", SFL_SORT_PRIO_SECONDARY | SFL_LOWER_IS_BETTER);
+ });
+}
+
+void LogNB(string mode, entity actor)
+{
+ string s;
+ if(!autocvar_sv_eventlog)
+ return;
+ s = strcat(":nexball:", mode);
+ if(actor != NULL)
+ s = strcat(s, ":", ftos(actor.playerid));
+ GameLogEcho(s);
+}
+
+void ball_restart(entity this)
+{
+ if(this.owner)
+ DropBall(this, this.owner.origin, '0 0 0');
+ ResetBall(this);
+}
+
+void nexball_setstatus(entity this)
+{
+ this.items &= ~IT_KEY1;
+ if(this.ballcarried)
+ {
+ if(this.ballcarried.teamtime && (this.ballcarried.teamtime < time))
+ {
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
+ entity e = this.ballcarried;
+ DropBall(this.ballcarried, this.ballcarried.owner.origin, '0 0 0');
+ ResetBall(e);
+ }
+ else
+ this.items |= IT_KEY1;
+ }
+}
+
+void relocate_nexball(entity this)
+{
+ tracebox(this.origin, BALL_MINS, BALL_MAXS, this.origin, true, this);
+ if(trace_startsolid)
+ {
+ vector o = this.origin;
+ if (!move_out_of_solid(this)) {
+ objerror(this, "could not get out of solid at all!");
+ }
+ LOG_INFOF(
+ "^1NOTE: this map needs FIXING. %s at %s needs to be moved out of solid, e.g. by %s",
+ this.classname,
+ vtos(o - '0 0 1'),
+ vtos(this.origin - o)
+ );
+ this.origin = o;
+ }
+}
+
+void DropOwner(entity this)
+{
+ entity ownr;
+ ownr = this.owner;
+ DropBall(this, ownr.origin, ownr.velocity);
+ makevectors(ownr.v_angle.y * '0 1 0');
+ ownr.velocity += ('0 0 0.75' - v_forward) * 1000;
+ UNSET_ONGROUND(ownr);
+}
+
+void GiveBall(entity plyr, entity ball)
+{
+ .entity weaponentity = weaponentities[0]; // TODO: find ballstealer
+ entity ownr = ball.owner;
+ if(ownr)
+ {
+ ownr.effects &= ~autocvar_g_nexball_basketball_effects_default;
+ ownr.ballcarried = NULL;
+ GameRules_scoring_vip(ownr, false);
+ if(STAT(NB_METERSTART, ownr))
+ {
+ STAT(NB_METERSTART, ownr) = 0;
+ ownr.(weaponentity).state = WS_READY;
+ }
+ WaypointSprite_Kill(ownr.waypointsprite_attachedforcarrier);
+ }
+ else
+ {
+ WaypointSprite_Kill(ball.waypointsprite_attachedforcarrier);
+ }
+
+ //setattachment(ball, plyr, "");
+ setorigin(ball, plyr.origin + plyr.view_ofs);
+
+ if(ball.team != plyr.team)
+ ball.teamtime = time + autocvar_g_nexball_basketball_delay_hold_forteam;
+
+ ball.owner = ball.pusher = plyr; //"owner" is set to the player carrying, "pusher" to the last player who touched it
+ ball.weaponentity_fld = weaponentity;
+ ball.team = plyr.team;
+ plyr.ballcarried = ball;
+ GameRules_scoring_vip(plyr, true);
+ ball.nb_dropper = plyr;
+
+ plyr.effects |= autocvar_g_nexball_basketball_effects_default;
+ ball.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+ ball.velocity = '0 0 0';
+ set_movetype(ball, MOVETYPE_NONE);
+ settouch(ball, func_null);
+ ball.effects |= EF_NOSHADOW;
+ ball.scale = 1; // scale down.
+
+ WaypointSprite_AttachCarrier(WP_NbBall, plyr, RADARICON_FLAGCARRIER);
+ WaypointSprite_UpdateRule(plyr.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+ if(autocvar_g_nexball_basketball_delay_hold)
+ {
+ setthink(ball, DropOwner);
+ ball.nextthink = time + autocvar_g_nexball_basketball_delay_hold;
+ }
+
+ STAT(WEAPONS, plyr.(weaponentity)) = STAT(WEAPONS, plyr);
+ plyr.m_switchweapon = plyr.(weaponentity).m_weapon;
+ STAT(WEAPONS, plyr) = WEPSET(NEXBALL);
+ Weapon w = WEP_NEXBALL;
+ w.wr_resetplayer(w, plyr);
+ plyr.(weaponentity).m_switchweapon = WEP_NEXBALL;
+ W_SwitchWeapon(plyr, WEP_NEXBALL, weaponentity);
+}
+
+void DropBall(entity ball, vector org, vector vel)
+{
+ ball.effects |= autocvar_g_nexball_basketball_effects_default;
+ ball.effects &= ~EF_NOSHADOW;
+ ball.owner.effects &= ~autocvar_g_nexball_basketball_effects_default;
+
+ setattachment(ball, NULL, "");
+ setorigin(ball, org);
+ set_movetype(ball, MOVETYPE_BOUNCE);
+ UNSET_ONGROUND(ball);
+ ball.scale = ball_scale;
+ ball.velocity = vel;
+ ball.nb_droptime = time;
+ settouch(ball, basketball_touch);
+ setthink(ball, ResetBall);
+ ball.nextthink = min(time + autocvar_g_nexball_delay_idle, ball.teamtime);
+
+ if(STAT(NB_METERSTART, ball.owner))
+ {
+ STAT(NB_METERSTART, ball.owner) = 0;
+ .entity weaponentity = ball.weaponentity_fld;
+ ball.owner.(weaponentity).state = WS_READY;
+ }
+
+ WaypointSprite_Kill(ball.owner.waypointsprite_attachedforcarrier);
+ WaypointSprite_Spawn(WP_NbBall, 0, 0, ball, '0 0 64', NULL, ball.team, ball, waypointsprite_attachedforcarrier, false, RADARICON_FLAGCARRIER); // no health bar please
+ WaypointSprite_UpdateRule(ball.waypointsprite_attachedforcarrier, 0, SPRITERULE_DEFAULT);
+
+ entity e = ball.owner; ball.owner = NULL;
+ e.ballcarried = NULL;
+ GameRules_scoring_vip(e, false);
+}
+
+void InitBall(entity this)
+{
+ if(game_stopped) return;
+ UNSET_ONGROUND(this);
+ set_movetype(this, MOVETYPE_BOUNCE);
+ if(this.classname == "nexball_basketball")
+ settouch(this, basketball_touch);
+ else if(this.classname == "nexball_football")
+ settouch(this, football_touch);
+ this.cnt = 0;
+ setthink(this, ResetBall);
+ this.nextthink = time + autocvar_g_nexball_delay_idle + 3;
+ this.teamtime = 0;
+ this.pusher = NULL;
+ this.team = false;
+ _sound(this, CH_TRIGGER, this.noise1, VOL_BASE, ATTEN_NORM);
+ WaypointSprite_Ping(this.waypointsprite_attachedforcarrier);
+ LogNB("init", NULL);
+}
+
+void ResetBall(entity this)
+{
+ if(this.cnt < 2) // step 1
+ {
+ if(time == this.teamtime)
+ Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(this.team, INFO_NEXBALL_RETURN_HELD));
+
+ settouch(this, func_null);
+ set_movetype(this, MOVETYPE_NOCLIP);
+ this.velocity = '0 0 0'; // just in case?
+ if(!this.cnt)
+ LogNB("resetidle", NULL);
+ this.cnt = 2;
+ this.nextthink = time;
+ }
+ else if(this.cnt < 4) // step 2 and 3
+ {
+// dprint("Step ", ftos(this.cnt), ": Calculated velocity: ", vtos(this.spawnorigin - this.origin), ", time: ", ftos(time), "\n");
+ this.velocity = (this.spawnorigin - this.origin) * (this.cnt - 1); // 1 or 0.5 second movement
+ this.nextthink = time + 0.5;
+ this.cnt += 1;
+ }
+ else // step 4
+ {
+// dprint("Step 4: time: ", ftos(time), "\n");
+ if(vdist(this.origin - this.spawnorigin, >, 10)) // should not happen anymore
+ LOG_TRACE("The ball moved too far away from its spawn origin.\nOffset: ",
+ vtos(this.origin - this.spawnorigin), " Velocity: ", vtos(this.velocity), "\n");
+ this.velocity = '0 0 0';
+ setorigin(this, this.spawnorigin); // make sure it's positioned correctly anyway
+ set_movetype(this, MOVETYPE_NONE);
+ setthink(this, InitBall);
+ this.nextthink = max(time, game_starttime) + autocvar_g_nexball_delay_start;
+ }
+}
+
+void football_touch(entity this, entity toucher)
+{
+ if(toucher.solid == SOLID_BSP)
+ {
+ if(time > this.lastground + 0.1)
+ {
+ _sound(this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ this.lastground = time;
+ }
+ if(this.velocity && !this.cnt)
+ this.nextthink = time + autocvar_g_nexball_delay_idle;
+ return;
+ }
+ if (!IS_PLAYER(toucher) && !IS_VEHICLE(toucher))
+ return;
+ if(GetResource(toucher, RES_HEALTH) < 1)
+ return;
+ if(!this.cnt)
+ this.nextthink = time + autocvar_g_nexball_delay_idle;
+
+ this.pusher = toucher;
+ this.team = toucher.team;
+
+ if(autocvar_g_nexball_football_physics == -1) // MrBougo try 1, before decompiling Rev's original
+ {
+ if(toucher.velocity)
+ this.velocity = toucher.velocity * 1.5 + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ }
+ else if(autocvar_g_nexball_football_physics == 1) // MrBougo's modded Rev style: partially independant of the height of the aiming point
+ {
+ makevectors(toucher.v_angle);
+ this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + '0 0 1' * autocvar_g_nexball_football_boost_up;
+ }
+ else if(autocvar_g_nexball_football_physics == 2) // 2nd mod try: totally independant. Really playable!
+ {
+ makevectors(toucher.v_angle.y * '0 1 0');
+ this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ }
+ else // Revenant's original style (from the original mod's disassembly, acknowledged by Revenant)
+ {
+ makevectors(toucher.v_angle);
+ this.velocity = toucher.velocity + v_forward * autocvar_g_nexball_football_boost_forward + v_up * autocvar_g_nexball_football_boost_up;
+ }
+ this.avelocity = -250 * v_forward; // maybe there is a way to make it look better?
+}
+
+void basketball_touch(entity this, entity toucher)
+{
+ if(toucher.ballcarried)
+ {
+ football_touch(this, toucher);
+ return;
+ }
+ if(!this.cnt && IS_PLAYER(toucher) && !STAT(FROZEN, toucher) && !IS_DEAD(toucher) && (toucher != this.nb_dropper || time > this.nb_droptime + autocvar_g_nexball_delay_collect))
+ {
+ if(GetResource(toucher, RES_HEALTH) < 1)
+ return;
+ LogNB("caught", toucher);
+ GiveBall(toucher, this);
+ }
+ else if(toucher.solid == SOLID_BSP)
+ {
+ _sound(this, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
+ if(this.velocity && !this.cnt)
+ this.nextthink = min(time + autocvar_g_nexball_delay_idle, this.teamtime);
+ }
+}
+
+void GoalTouch(entity this, entity toucher)
+{
+ entity ball;
+ float isclient, pscore, otherteam;
+ string pname;
+
+ if(game_stopped) return;
+ if((this.spawnflags & GOAL_TOUCHPLAYER) && toucher.ballcarried)
+ ball = toucher.ballcarried;
+ else
+ ball = toucher;
+ if(ball.classname != "nexball_basketball")
+ if(ball.classname != "nexball_football")
+ return;
+ if((!ball.pusher && this.team != GOAL_OUT) || ball.cnt)
+ return;
+ EXACTTRIGGER_TOUCH(this, toucher);
+
+
+ if(NumTeams(nb_teams) == 2)
+ otherteam = OtherTeam(ball.team);
+ else
+ otherteam = 0;
+
+ if((isclient = IS_CLIENT(ball.pusher)))
+ pname = ball.pusher.netname;
+ else
+ pname = "Someone (?)";
+
+ if(ball.team == this.team) //owngoal (regular goals)
+ {
+ LogNB("owngoal", ball.pusher);
+ bprint("Boo! ", pname, "^7 scored a goal against their own team!\n");
+ pscore = -1;
+ }
+ else if(this.team == GOAL_FAULT)
+ {
+ LogNB("fault", ball.pusher);
+ if(NumTeams(nb_teams) == 2)
+ bprint(Team_ColoredFullName(otherteam), " gets a point due to ", pname, "^7's silliness.\n");
+ else
+ bprint(Team_ColoredFullName(ball.team), " loses a point due to ", pname, "^7's silliness.\n");
+ pscore = -1;
+ }
+ else if(this.team == GOAL_OUT)
+ {
+ LogNB("out", ball.pusher);
+ if((this.spawnflags & GOAL_TOUCHPLAYER) && ball.owner)
+ bprint(pname, "^7 went out of bounds.\n");
+ else
+ bprint("The ball was returned.\n");
+ pscore = 0;
+ }
+ else //score
+ {
+ LogNB(strcat("goal:", ftos(this.team)), ball.pusher);
+ bprint("Goaaaaal! ", pname, "^7 scored a point for the ", Team_ColoredFullName(ball.team), ".\n");
+ pscore = 1;
+ }
+
+ _sound(ball, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NONE);
+
+ if(ball.team && pscore)
+ {
+ if(NumTeams(nb_teams) == 2 && pscore < 0)
+ TeamScore_AddToTeam(otherteam, ST_NEXBALL_GOALS, -pscore);
+ else
+ TeamScore_AddToTeam(ball.team, ST_NEXBALL_GOALS, pscore);
+ }
+ if(isclient)
+ {
+ if(pscore > 0)
+ GameRules_scoring_add(ball.pusher, NEXBALL_GOALS, pscore);
+ else if(pscore < 0)
+ GameRules_scoring_add(ball.pusher, NEXBALL_FAULTS, -pscore);
+ }
+
+ if(ball.owner) // Happens on spawnflag GOAL_TOUCHPLAYER
+ DropBall(ball, ball.owner.origin, ball.owner.velocity);
+
+ WaypointSprite_Ping(ball.waypointsprite_attachedforcarrier);
+
+ ball.cnt = 1;
+ setthink(ball, ResetBall);
+ if(ball.classname == "nexball_basketball")
+ settouch(ball, football_touch); // better than func_null: football control until the ball gets reset
+ ball.nextthink = time + autocvar_g_nexball_delay_goal * (this.team != GOAL_OUT);
+}
+
+//=======================//
+// team ents //
+//=======================//
+spawnfunc(nexball_team)
+{
+ if(!g_nexball)
+ {
+ delete(this);
+ return;
+ }
+ this.team = this.cnt + 1;
+}
+
+void nb_spawnteam(string teamname, float teamcolor)
+{
+ LOG_TRACE("^2spawned team ", teamname);
+ entity e = new(nexball_team);
+ e.netname = teamname;
+ e.cnt = teamcolor;
+ e.team = e.cnt + 1;
+ //nb_teams += 1;
+}
+
+void nb_spawnteams()
+{
+ bool t_red = false, t_blue = false, t_yellow = false, t_pink = false;
+ entity e;
+ for(e = NULL; (e = find(e, classname, "nexball_goal"));)
+ {
+ switch(e.team)
+ {
+ case NUM_TEAM_1:
+ if(!t_red)
+ {
+ nb_spawnteam("Red", e.team-1) ;
+ nb_teams |= BIT(0);
+ t_red = true;
+ }
+ break;
+ case NUM_TEAM_2:
+ if(!t_blue)
+ {
+ nb_spawnteam("Blue", e.team-1) ;
+ t_blue = true;
+ nb_teams |= BIT(1);
+ }
+ break;
+ case NUM_TEAM_3:
+ if(!t_yellow)
+ {
+ nb_spawnteam("Yellow", e.team-1);
+ t_yellow = true;
+ nb_teams |= BIT(2);
+ }
+ break;
+ case NUM_TEAM_4:
+ if(!t_pink)
+ {
+ nb_spawnteam("Pink", e.team-1) ;
+ t_pink = true;
+ nb_teams |= BIT(3);
+ }
+ break;
+ }
+ }
+}
+
+void nb_delayedinit(entity this)
+{
+ if(find(NULL, classname, "nexball_team") == NULL)
+ nb_spawnteams();
+ nb_ScoreRules(nb_teams);
+}
+
+
+//=======================//
+// spawnfuncs //
+//=======================//
+
+void SpawnBall(entity this)
+{
+ if(!g_nexball) { delete(this); return; }
+
+// balls += 4; // using the remaining bits to count balls will leave more than the max edict count, so it's fine
+
+ if(this.model == "")
+ {
+ this.model = "models/nexball/ball.md3";
+ this.scale = 1.3;
+ }
+
+ precache_model(this.model);
+ _setmodel(this, this.model);
+ setsize(this, BALL_MINS, BALL_MAXS);
+ ball_scale = this.scale;
+
+ relocate_nexball(this);
+ this.spawnorigin = this.origin;
+
+ this.effects = this.effects | EF_LOWPRECISION;
+
+ if(cvar(strcat("g_", this.classname, "_trail"))) //nexball_basketball :p
+ {
+ this.glow_color = autocvar_g_nexball_trail_color;
+ this.glow_trail = true;
+ }
+
+ set_movetype(this, MOVETYPE_FLY);
+
+ if(autocvar_g_nexball_playerclip_collisions)
+ this.dphitcontentsmask = DPCONTENTS_BODY | DPCONTENTS_SOLID | DPCONTENTS_PLAYERCLIP;
+
+ if(!autocvar_g_nexball_sound_bounce)
+ this.noise = "";
+ else if(this.noise == "")
+ this.noise = strzone(SND(NB_BOUNCE));
+ //bounce sound placeholder (FIXME)
+ if(this.noise1 == "")
+ this.noise1 = strzone(SND(NB_DROP));
+ //ball drop sound placeholder (FIXME)
+ if(this.noise2 == "")
+ this.noise2 = strzone(SND(NB_STEAL));
+ //stealing sound placeholder (FIXME)
+ if(this.noise) precache_sound(this.noise);
+ precache_sound(this.noise1);
+ precache_sound(this.noise2);
+
+ WaypointSprite_AttachCarrier(WP_NbBall, this, RADARICON_FLAGCARRIER); // the ball's team is not set yet, no rule update needed
+
+ this.reset = ball_restart;
+ setthink(this, InitBall);
+ this.nextthink = game_starttime + autocvar_g_nexball_delay_start;
+}
+
+spawnfunc(nexball_basketball)
+{
+ nexball_mode |= NBM_BASKETBALL;
+ this.classname = "nexball_basketball";
+ if (!(balls & BALL_BASKET))
+ {
+ /*
+ CVTOV(g_nexball_basketball_effects_default);
+ CVTOV(g_nexball_basketball_delay_hold);
+ CVTOV(g_nexball_basketball_delay_hold_forteam);
+ CVTOV(g_nexball_basketball_teamsteal);
+ */
+ autocvar_g_nexball_basketball_effects_default = autocvar_g_nexball_basketball_effects_default & BALL_EFFECTMASK;
+ }
+ if(!this.effects)
+ this.effects = autocvar_g_nexball_basketball_effects_default;
+ this.solid = SOLID_TRIGGER;
+ this.pushable = autocvar_g_nexball_basketball_jumppad;
+ balls |= BALL_BASKET;
+ this.bouncefactor = autocvar_g_nexball_basketball_bouncefactor;
+ this.bouncestop = autocvar_g_nexball_basketball_bouncestop;
+ SpawnBall(this);
+}
+
+spawnfunc(nexball_football)
+{
+ nexball_mode |= NBM_FOOTBALL;
+ this.classname = "nexball_football";
+ this.solid = SOLID_TRIGGER;
+ balls |= BALL_FOOT;
+ this.pushable = autocvar_g_nexball_football_jumppad;
+ this.bouncefactor = autocvar_g_nexball_football_bouncefactor;
+ this.bouncestop = autocvar_g_nexball_football_bouncestop;
+ SpawnBall(this);
+}
+
+bool nb_Goal_Customize(entity this, entity client)
+{
+ entity e = WaypointSprite_getviewentity(client);
+ entity wp_owner = this.owner;
+ if(SAME_TEAM(e, wp_owner)) { return false; }
+
+ return true;
+}
+
+void SpawnGoal(entity this)
+{
+ if(!g_nexball) { delete(this); return; }
+
+ EXACTTRIGGER_INIT;
+
+ if(this.team != GOAL_OUT && Team_IsValidTeam(this.team))
+ {
+ entity wp = WaypointSprite_SpawnFixed(WP_NbGoal, (this.absmin + this.absmax) * 0.5, this, sprite, RADARICON_NONE);
+ wp.colormod = ((this.team) ? Team_ColorRGB(this.team) : '1 0.5 0');
+ setcefc(this.sprite, nb_Goal_Customize);
+ }
+
+ this.classname = "nexball_goal";
+ if(this.noise == "")
+ this.noise = "ctf/respawn.wav";
+ precache_sound(this.noise);
+ settouch(this, GoalTouch);
+}
+
+spawnfunc(nexball_redgoal)
+{
+ this.team = NUM_TEAM_1;
+ SpawnGoal(this);
+}
+spawnfunc(nexball_bluegoal)
+{
+ this.team = NUM_TEAM_2;
+ SpawnGoal(this);
+}
+spawnfunc(nexball_yellowgoal)
+{
+ this.team = NUM_TEAM_3;
+ SpawnGoal(this);
+}
+spawnfunc(nexball_pinkgoal)
+{
+ this.team = NUM_TEAM_4;
+ SpawnGoal(this);
+}
+
+spawnfunc(nexball_fault)
+{
+ this.team = GOAL_FAULT;
+ if(this.noise == "")
+ this.noise = strzone(SND(TYPEHIT));
+ SpawnGoal(this);
+}
+
+spawnfunc(nexball_out)
+{
+ this.team = GOAL_OUT;
+ if(this.noise == "")
+ this.noise = strzone(SND(TYPEHIT));
+ SpawnGoal(this);
+}
+
+//
+//Spawnfuncs preserved for compatibility
+//
+
+spawnfunc(ball)
+{
+ spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_football)
+{
+ spawnfunc_nexball_football(this);
+}
+spawnfunc(ball_basketball)
+{
+ spawnfunc_nexball_basketball(this);
+}
+// The "red goal" is defended by blue team. A ball in there counts as a point for red.
+spawnfunc(ball_redgoal)
+{
+ spawnfunc_nexball_bluegoal(this); // I blame Revenant
+}
+spawnfunc(ball_bluegoal)
+{
+ spawnfunc_nexball_redgoal(this); // but he didn't mean to cause trouble :p
+}
+spawnfunc(ball_fault)
+{
+ spawnfunc_nexball_fault(this);
+}
+spawnfunc(ball_bound)
+{
+ spawnfunc_nexball_out(this);
+}
+
+bool ball_customize(entity this, entity client)
+{
+ if(!this.owner)
+ {
+ this.effects &= ~EF_FLAME;
+ this.scale = 1;
+ setcefc(this, func_null);
+ return true;
+ }
+
+ if(client == this.owner)
+ {
+ this.scale = autocvar_g_nexball_viewmodel_scale;
+ if(this.enemy)
+ this.effects |= EF_FLAME;
+ else
+ this.effects &= ~EF_FLAME;
+ }
+ else
+ {
+ this.effects &= ~EF_FLAME;
+ this.scale = 1;
+ }
+
+ return true;
+}
+
+void nb_DropBall(entity player)
+{
+ if(player.ballcarried && g_nexball)
+ DropBall(player.ballcarried, player.origin, player.velocity);
+}
+
+MUTATOR_HOOKFUNCTION(nb, ClientDisconnect)
+{
+ entity player = M_ARGV(0, entity);
+
+ nb_DropBall(player);
+}
+
+MUTATOR_HOOKFUNCTION(nb, PlayerDies)
+{
+ entity frag_target = M_ARGV(2, entity);
+
+ nb_DropBall(frag_target);
+}
+
+MUTATOR_HOOKFUNCTION(nb, MakePlayerObserver)
+{
+ entity player = M_ARGV(0, entity);
+
+ nb_DropBall(player);
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nb, PlayerPreThink)
+{
+ entity player = M_ARGV(0, entity);
+
+ makevectors(player.v_angle);
+ if(nexball_mode & NBM_BASKETBALL)
+ {
+ if(player.ballcarried)
+ {
+ // 'view ball'
+ player.ballcarried.velocity = player.velocity;
+ setcefc(player.ballcarried, ball_customize);
+
+ vector org = player.origin + player.view_ofs +
+ v_forward * autocvar_g_nexball_viewmodel_offset.x +
+ v_right * autocvar_g_nexball_viewmodel_offset.y +
+ v_up * autocvar_g_nexball_viewmodel_offset.z;
+ setorigin(player.ballcarried, org);
+
+ // 'safe passing'
+ if(autocvar_g_nexball_safepass_maxdist)
+ {
+ if(player.ballcarried.wait < time && player.ballcarried.enemy)
+ {
+ //centerprint(player, sprintf("Lost lock on %s", player.ballcarried.enemy.netname));
+ player.ballcarried.enemy = NULL;
+ }
+
+
+ //tracebox(player.origin + player.view_ofs, '-2 -2 -2', '2 2 2', player.origin + player.view_ofs + v_forward * autocvar_g_nexball_safepass_maxdist);
+ crosshair_trace(player);
+ if( trace_ent &&
+ IS_CLIENT(trace_ent) &&
+ !IS_DEAD(trace_ent) &&
+ trace_ent.team == player.team &&
+ vdist(trace_ent.origin - player.origin, <=, autocvar_g_nexball_safepass_maxdist) )
+ {
+
+ //if(player.ballcarried.enemy != trace_ent)
+ // centerprint(player, sprintf("Locked to %s", trace_ent.netname));
+ player.ballcarried.enemy = trace_ent;
+ player.ballcarried.wait = time + autocvar_g_nexball_safepass_holdtime;
+
+
+ }
+ }
+ }
+ else
+ {
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+
+ if(STAT(WEAPONS, player.(weaponentity)))
+ {
+ 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);
+
+ STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
+ }
+ }
+ }
+
+ }
+
+ nexball_setstatus(player);
+}
+
+MUTATOR_HOOKFUNCTION(nb, SpectateCopy)
+{
+ entity spectatee = M_ARGV(0, entity);
+ entity client = M_ARGV(1, entity);
+
+ STAT(NB_METERSTART, client) = STAT(NB_METERSTART, spectatee);
+}
+
+MUTATOR_HOOKFUNCTION(nb, PlayerSpawn)
+{
+ entity player = M_ARGV(0, entity);
+
+ STAT(NB_METERSTART, player) = 0;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ .entity weaponentity = weaponentities[slot];
+ STAT(WEAPONS, player.(weaponentity)) = '0 0 0';
+ }
+
+ if (nexball_mode & NBM_BASKETBALL)
+ STAT(WEAPONS, player) |= WEPSET(NEXBALL);
+ else
+ STAT(WEAPONS, player) = '0 0 0';
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nb, PlayerPhysics_UpdateStats)
+{
+ entity player = M_ARGV(0, entity);
+ // these automatically reset, no need to worry
+
+ if(player.ballcarried)
+ STAT(MOVEVARS_HIGHSPEED, player) *= autocvar_g_nexball_basketball_carrier_highspeed;
+}
+
+MUTATOR_HOOKFUNCTION(nb, ForbidThrowCurrentWeapon)
+{
+ //entity player = M_ARGV(0, entity);
+ entity wepent = M_ARGV(1, entity);
+
+ return wepent.m_weapon == WEP_NEXBALL;
+}
+
+MUTATOR_HOOKFUNCTION(nb, ForbidDropCurrentWeapon)
+{
+ //entity player = M_ARGV(0, entity);
+ int wep = M_ARGV(1, int);
+
+ return wep == WEP_MORTAR.m_id; // TODO: what is this for?
+}
+
+MUTATOR_HOOKFUNCTION(nb, FilterItem)
+{
+ entity item = M_ARGV(0, entity);
+
+ if(Item_IsLoot(item))
+ if(item.weapon == WEP_NEXBALL.m_id)
+ return true;
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nb, ItemTouch)
+{
+ entity item = M_ARGV(0, entity);
+ entity toucher = M_ARGV(1, entity);
+
+ if(item.weapon && toucher.ballcarried)
+ return MUT_ITEMTOUCH_RETURN; // no new weapons for you, mister!
+
+ return MUT_ITEMTOUCH_CONTINUE;
+}
+
+MUTATOR_HOOKFUNCTION(nb, TeamBalance_CheckAllowedTeams)
+{
+ M_ARGV(1, string) = "nexball_team";
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(nb, WantWeapon)
+{
+ M_ARGV(1, float) = 0; // weapon is set a few lines later, apparently
+ return true;
+}
+
+MUTATOR_HOOKFUNCTION(nb, DropSpecialItems)
+{
+ entity frag_target = M_ARGV(0, entity);
+
+ if(frag_target.ballcarried)
+ DropBall(frag_target.ballcarried, frag_target.origin, frag_target.velocity);
+
+ return false;
+}
+
+MUTATOR_HOOKFUNCTION(nb, SendWaypoint)
+{
+ M_ARGV(2, int) &= ~0x80;
+}
+
+REGISTER_MUTATOR(nb, false)
+{
+ MUTATOR_STATIC();
+ MUTATOR_ONADD
+ {
+ g_nexball_meter_period = autocvar_g_nexball_meter_period;
+ if(g_nexball_meter_period <= 0)
+ g_nexball_meter_period = 2; // avoid division by zero etc. due to silly users
+ g_nexball_meter_period = rint(g_nexball_meter_period * 32) / 32; //Round to 1/32ths to send as a byte multiplied by 32
+
+ // General settings
+ /*
+ CVTOV(g_nexball_football_boost_forward); //100
+ CVTOV(g_nexball_football_boost_up); //200
+ CVTOV(g_nexball_delay_idle); //10
+ CVTOV(g_nexball_football_physics); //0
+ */
+ radar_showennemies = autocvar_g_nexball_radar_showallplayers;
+
+ InitializeEntity(NULL, nb_delayedinit, INITPRIO_GAMETYPE);
+ WEP_NEXBALL.spawnflags &= ~WEP_FLAG_MUTATORBLOCKED;
+
+ GameRules_teams(true);
+ GameRules_limit_score(autocvar_g_nexball_goallimit);
+ GameRules_limit_lead(autocvar_g_nexball_goalleadlimit);
+ }
+
+ MUTATOR_ONROLLBACK_OR_REMOVE
+ {
+ WEP_NEXBALL.spawnflags |= WEP_FLAG_MUTATORBLOCKED;
+ }
+ return 0;
+}
--- /dev/null
+#pragma once
+
+//EF_BRIGHTFIELD|EF_BRIGHTLIGHT|EF_DIMLIGHT|EF_BLUE|EF_RED|EF_FLAME
+const float BALL_EFFECTMASK = 1229;
+const vector BALL_MINS = '-16 -16 -16'; // The model is 24*24*24
+const vector BALL_MAXS = '16 16 16';
+const vector BALL_ATTACHORG = '3 0 16';
+const float BALL_FOOT = 1;
+const float BALL_BASKET = 2;
+//spawnflags
+const float GOAL_TOUCHPLAYER = 1;
+//goal types
+const float GOAL_FAULT = -1;
+const float GOAL_OUT = -2;
+
+void DropBall(entity ball, vector org, vector vel);
+float autocvar_g_nexball_football_boost_forward;
+float autocvar_g_nexball_football_boost_up;
+float autocvar_g_nexball_football_physics;
+float autocvar_g_nexball_delay_idle;
+float autocvar_g_nexball_basketball_delay_hold;
+float autocvar_g_nexball_basketball_delay_hold_forteam;
+float autocvar_g_nexball_basketball_effects_default;
+float autocvar_g_nexball_basketball_teamsteal;
+float autocvar_g_nexball_meter_period;
+
+float balls;
+float ball_scale;
+float nb_teams;
+
+.entity nb_dropper;
+.float nb_droptime;
+
+.float teamtime;
#pragma once
CLASS(BallStealer, PortoLaunch)
-/* flags */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(BallStealer, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_NOTRUEAIM);
/* impulse */ ATTRIB(BallStealer, impulse, int, 0);
/* refname */ ATTRIB(BallStealer, netname, string, "ballstealer");
/* wepname */ ATTRIB(BallStealer, m_name, string, _("Ball Stealer"));
{
Send_Notification(NOTIF_ONE, it, MSG_CENTER, CENTER_ONS_NOTSHIELDED_TEAM);
msg_entity = it;
- soundto(MSG_ONE, this, CHAN_AUTO, SND(KH_ALARM), VOL_BASE, ATTEN_NONE); // FIXME: unique sound?
+ soundto(MSG_ONE, this, CHAN_AUTO, SND(ONS_GENERATOR_ALARM), VOL_BASE, ATTEN_NONE);
}
else
Send_Notification(NOTIF_ONE, it, MSG_CENTER, APP_TEAM_NUM(this.team, CENTER_ONS_NOTSHIELDED));
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);
+ sf = 0;
+ sf = BITSET(sf, BIT(0), this.target_random);
+
+ sf = BITSET(sf, BIT(1), this.target && this.target != "");
+ sf = BITSET(sf, BIT(2), this.target2 && this.target2 != "");
+ sf = BITSET(sf, BIT(3), this.target3 && this.target3 != "");
+ sf = BITSET(sf, BIT(4), this.target4 && this.target4 != "");
+ sf = BITSET(sf, BIT(5), this.targetname && this.targetname != "");
+
+ WriteByte(MSG_ENTITY, sf);
+ if(sf & BIT(1))
+ WriteString(MSG_ENTITY, this.target);
+ if(sf & BIT(2))
+ WriteString(MSG_ENTITY, this.target2);
+ if(sf & BIT(3))
+ WriteString(MSG_ENTITY, this.target3);
+ if(sf & BIT(4))
+ WriteString(MSG_ENTITY, this.target4);
+ if(sf & BIT(5))
+ WriteString(MSG_ENTITY, this.targetname);
WriteByte(MSG_ENTITY, this.wait);
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();
+ int targbits = ReadByte();
+ this.target_random = (targbits & BIT(0));
+
+ this.target = ((targbits & BIT(1)) ? strzone(ReadString()) : string_null);
+ this.target2 = ((targbits & BIT(2)) ? strzone(ReadString()) : string_null);
+ this.target3 = ((targbits & BIT(3)) ? strzone(ReadString()) : string_null);
+ this.target4 = ((targbits & BIT(4)) ? strzone(ReadString()) : string_null);
+ this.targetname = ((targbits & BIT(5)) ? strzone(ReadString()) : string_null);
this.wait = ReadByte();
void dynlight_find_aiment(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
void dynlight_find_path(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
void dynlight_find_target(entity this)
{
entity targ;
- if (!this.target)
+ if (!this.target || this.target == "")
objerror (this, "dynlight: no target to follow");
targ = find(NULL, targetname, this.target);
{
}
else
+ {
objerror (this, "^3Teleport destination without a targetname");
+ return; // don't link it to CSQC in this case!
+ }
teleport_dest_link(this);
}
void Ent_TriggerMusic_Think(entity this)
{
- if(this.active == ACTIVE_NOT)
+ if(this.active == ACTIVE_NOT || intermission)
{
return;
}
if(n == 0)
{
// no dest!
- objerror (this, "Teleporter with nonexistant target");
+ objerror (this, "Teleporter with nonexistent target");
return;
}
else if(n == 1)
void counter_use(entity this, entity actor, entity trigger)
{
entity store = this;
- if(this.spawnflags & COUNTER_PER_PLAYER)
+ if(this.spawnflags & COUNTER_PER_PLAYER) // FIXME: multiple counters in the map will not function correctly, and upon trigger reset the player won't be able to use it again!
{
if(!IS_PLAYER(actor))
return;
toucher.triggerhealtime = time + this.delay;
bool playthesound = (this.spawnflags & HEAL_SOUND_ALWAYS);
- bool healed = Heal(toucher, this, GetResource(this, RES_HEALTH), this.max_health);
+ bool healed = Heal(toucher, this, this.health, this.max_health);
if(playthesound || healed)
_sound (toucher, CH_TRIGGER, this.noise, VOL_BASE, ATTEN_NORM);
this.active = ACTIVE_ACTIVE;
if(!this.delay)
this.delay = 1;
- if(!GetResource(this, RES_HEALTH))
- SetResourceExplicit(this, RES_HEALTH, 10); // TODO: use a special field for this, it doesn't have actual health!
+ if(!this.health)
+ this.health = 10;
if(!this.max_health)
this.max_health = 200; // max health topoff for field
if(this.noise == "")
}
#endif
+#ifdef SVQC
+vector trigger_push_get_start_point(entity this)
+{
+ // 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;
+ return org;
+}
+
+float trigger_push_get_push_time(entity this, vector endpos)
+{
+ vector org = trigger_push_get_start_point(this);
+
+ float grav = PHYS_GRAVITY(NULL);
+
+ entity t = this.enemy;
+ if (t)
+ {
+ entity e = spawn();
+ setsize(e, PL_MIN_CONST, PL_MAX_CONST);
+ e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
+ vector v = trigger_push_calculatevelocity(org, t, this.height, e);
+ vector v2 = trigger_push_calculatevelocity(endpos, t, this.height, e);
+ delete(e);
+ return (v.z + v2.z) / grav;
+ }
+ else if (!(this.target && this.target != ""))
+ {
+ if (!this.team)
+ {
+ vector v = this.movedir;
+
+ float t = v.z / grav;
+ float jump_height = 1/2 * grav * (t ** 2);
+ float remaining_height = org.z + jump_height - endpos.z;
+ float v2_z = sqrt(2 * grav * remaining_height);
+
+ return (v.z + v2_z) / grav;
+ }
+ }
+ return 0;
+}
+#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;
+#ifdef SVQC
+ vector org = trigger_push_get_start_point(this);
+#endif
if (this.target)
{
#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);
+#include <common/weapons/weapon/tuba.qh>
+bool magicear_matched;
string trigger_magicear_processmessage(entity ear, entity source, float teamsay, entity privatesay, string msgin)
{
float domatch, dotrigger, matchstart, l;
/*
* t_swamp.c
-* Adds spawnfunc_trigger_swamp and suppoart routines for xonotic 1.2.1+
+* Adds spawnfunc_trigger_swamp and support routines for nexuiz 1.2.1+ and xonotic
* Author tZork (Jakob MG)
* jakob@games43.se
* 2005 11 29
*/
-.float swamp_interval; //Hurt players in swamp with this interval
-.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
-.float swamp_lifetime; // holds the points remaining until slug dies (not quite health!)
-.entity swampslug;
-
-#ifdef SVQC
-spawnfunc(trigger_swamp);
-#endif
-void swamp_touch(entity this, entity toucher);
-void swampslug_think(entity this);
-
/*
* Uses a entity calld swampslug to handle players in the swamp
//Slug dead? then remove curses.
if(GetResource(this, RES_HEALTH) <= 0)
{
- this.owner.in_swamp = 0;
+ if(this.owner.swampslug == this)
+ {
+ this.owner.in_swamp = false;
+ this.owner.swampslug = NULL;
+ }
delete(this);
//centerprint(this.owner,"Killing slug...\n");
return;
EXACTTRIGGER_TOUCH(this, toucher);
// Chech if player alredy got a swampslug.
- if(toucher.in_swamp != 1)
+ if(!toucher.in_swamp)
{
// If not attach one.
//centerprint(toucher,"Entering swamp!\n");
- toucher.swampslug = spawn();
+ if(!toucher.swampslug) // just incase
+ toucher.swampslug = spawn();
toucher.swampslug.swamp_lifetime = 2;
setthink(toucher.swampslug, swampslug_think);
toucher.swampslug.nextthink = time;
toucher.swampslug.dmg = this.dmg;
toucher.swampslug.swamp_interval = this.swamp_interval;
toucher.swamp_slowdown = this.swamp_slowdown;
- toucher.in_swamp = 1;
+ toucher.in_swamp = true;
return;
}
- //toucher.in_swamp = 1;
+ //toucher.in_swamp = true;
//Revitalize players swampslug
toucher.swampslug.swamp_lifetime = 2;
}
/*QUAKED spawnfunc_trigger_swamp (.5 .5 .5) ?
-Players gettin into the swamp will
-get slowd down and damaged
+Players in the swamp will be
+slowed down and damaged over time
*/
spawnfunc(trigger_swamp)
{
.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
+.bool in_swamp;
.entity swampslug; // Uses this to release from swamp ("untouch" fix)
+
+.float swamp_interval; //Hurt players in swamp with this interval
+.float swamp_slowdown; //Players in swamp get slowd down by this mutch 0-1 is slowdown 1-~ is speedup (!?)
+.float swamp_lifetime; // holds the points remaining until slug dies (not quite health!)
+
+#ifdef SVQC
+spawnfunc(trigger_swamp);
+#endif
+void swamp_touch(entity this, entity toucher);
+void swampslug_think(entity this);
{
for ( e = HUD_MinigameMenu_entries; e != NULL; e = e.list_next )
{
- if ( e.flags & 2 && e.origin_x == this.origin_x)
+ if ( (e.flags & 2) && e.origin_x == this.origin_x)
HUD_MinigameMenu_Click(e);
}
LOG_WARNF("Missing model: \"%s\"", s);
return;
}
- profile(sprintf("precache_model(\"%s\")", s));
+ //profile(sprintf("precache_model(\"%s\")", s));
precache_model(s);
strcpy(this.model_str_, s);
}
player.OffhandMageTeleport_key_pressed = key_pressed;
}
ENDCLASS(OffhandMageTeleport)
-OffhandMageTeleport OFFHAND_MAGE_TELEPORT; STATIC_INIT(OFFHAND_MAGE_TELEPORT) { OFFHAND_MAGE_TELEPORT = NEW(OffhandMageTeleport); }
+OffhandMageTeleport OFFHAND_MAGE_TELEPORT;
+STATIC_INIT(OFFHAND_MAGE_TELEPORT) { OFFHAND_MAGE_TELEPORT = NEW(OffhandMageTeleport); }
float autocvar_g_monster_mage_health;
float autocvar_g_monster_mage_damageforcescale = 0.5;
#include <common/items/_mod.qh>
CLASS(MageSpike, PortoLaunch)
-/* flags */ ATTRIB(MageSpike, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(MageSpike, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(MageSpike, impulse, int, 9);
/* refname */ ATTRIB(MageSpike, netname, string, "magespike");
/* wepname */ ATTRIB(MageSpike, m_name, string, _("Mage spike"));
#include <common/weapons/_all.qh>
CLASS(SpiderAttack, PortoLaunch)
-/* flags */ ATTRIB(SpiderAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(SpiderAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(SpiderAttack, impulse, int, 9);
/* refname */ ATTRIB(SpiderAttack, netname, string, "spider");
/* wepname */ ATTRIB(SpiderAttack, m_name, string, _("Spider attack"));
#include <common/weapons/_all.qh>
CLASS(WyvernAttack, PortoLaunch)
-/* flags */ ATTRIB(WyvernAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(WyvernAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(WyvernAttack, impulse, int, 9);
/* refname */ ATTRIB(WyvernAttack, netname, string, "wyvern");
/* wepname */ ATTRIB(WyvernAttack, m_name, string, _("Wyvern attack"));
if(trace_ent && IS_MONSTER(trace_ent))
reverse = true;
- // TODO: fix this... tracing is broken if the floor is thin
- /*
- if(!allow_jumpoff)
+ if(!allow_jumpoff && IS_ONGROUND(this))
{
- a = b - '0 0 32';
- traceline(b, a, MOVE_WORLDONLY, this);
+ traceline(b, b - '0 0 32', MOVE_NORMAL, this);
if(trace_fraction == 1.0)
reverse = true;
- } */
+ }
if(reverse)
{
if(!autocvar_g_monsters) { Monster_Remove(this); return false; }
- if(!(this.spawnflags & MONSTERFLAG_RESPAWNED))
+ if(!(this.spawnflags & MONSTERFLAG_RESPAWNED) && !(this.flags & FL_MONSTER))
{
IL_PUSH(g_monsters, this);
if(this.mdl && this.mdl != "")
e.noalign = this.noalign;
e.angles = this.angles;
e.monster_skill = this.monster_skill;
+ e.skin = this.skin;
e = spawnmonster(e, this.spawnmob, 0, this, this, this.origin, false, true, this.monster_moveflags);
}
bool mutator_log = false;
.bool m_added;
-#define MUTATOR_IS_ENABLED(this) MUTATOR_##this.mutatorcheck()
+#define _MUTATOR_IS_ENABLED(this) this.mutatorcheck()
+#define MUTATOR_IS_ENABLED(this) _MUTATOR_IS_ENABLED(MUTATOR_##this)
#ifdef GAMEQC
/** server mutators activate corresponding client mutators for all clients */
}
STATIC_INIT_LATE(Mutators) {
- FOREACH(Mutators, it.mutatorcheck(), Mutator_Add(it));
+ FOREACH(Mutators, _MUTATOR_IS_ENABLED(it), Mutator_Add(it));
}
#define MUTATOR_ONADD if (mode == MUTATOR_ADDING)
#include <common/teams.qh>
#include <common/util.qh>
+#ifdef GAMEQC
+#include <common/mutators/mutator/waypoints/all.qh>
+#endif
+
#ifdef GAMEQC
REGISTER_WAYPOINT(Buff, _("Buff"), "", '1 0.5 0', 1);
REGISTER_RADARICON(Buff, 1);
ENDCLASS(Buff)
STATIC_INIT(REGISTER_BUFFS) {
- FOREACH(Buffs, true, {
- it.m_itemid = BIT(it.m_id - 1); \
- it.m_sprite = strzone(strcat("buff-", it.netname)); \
- });
+ FOREACH(Buffs, true, {
+ it.m_itemid = BIT(it.m_id - 1);
+ it.m_sprite = strzone(strcat("buff-", it.netname));
+ });
}
#ifdef SVQC
#pragma once
#include "buffs.qh"
+
+float cvar_cl_buffs_autoreplace;
+REPLICATE(cvar_cl_buffs_autoreplace, bool, "cl_buffs_autoreplace");
{
if (CS(toucher).cvar_cl_buffs_autoreplace && STAT(BUFFS, toucher) != STAT(BUFFS, this))
{
+ // TODO: lost-gained notification for this case
int buffid = buff_FirstFromFlags(STAT(BUFFS, toucher)).m_id;
- //Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_DROP, STAT(BUFFS, toucher));
- Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+ Send_Notification(NOTIF_ONE, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(toucher))
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF_LOST, toucher.netname, buffid);
STAT(BUFFS, toucher) = 0;
//sound(toucher, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
this.owner = toucher;
this.buff_active = false;
this.lifetime = 0;
- int buffid = buff_FirstFromFlags(STAT(BUFFS, this)).m_id;
- Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, buffid);
+ entity thebuff = buff_FirstFromFlags(STAT(BUFFS, this));
+ Send_Notification(NOTIF_ONE, toucher, MSG_MULTI, ITEM_BUFF_GOT, thebuff.m_id);
+ if(!IS_INDEPENDENT_PLAYER(toucher))
+ Send_Notification(NOTIF_ALL_EXCEPT, toucher, MSG_INFO, INFO_ITEM_BUFF, toucher.netname, thebuff.m_id);
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
sound(toucher, CH_TRIGGER, SND_SHIELD_RESPAWN, VOL_BASE, ATTN_NORM);
STAT(BUFFS, toucher) |= (STAT(BUFFS, this));
+ float bufftime = ((this.count) ? this.count : thebuff.m_time(thebuff));
+ if(bufftime)
+ STAT(BUFF_TIME, toucher) = min(time + bufftime, max(STAT(BUFF_TIME, toucher), time) + bufftime);
}
float buff_Available(entity buff)
return true;
}
+void buff_Delete(entity this)
+{
+ WaypointSprite_Kill(this.buff_waypoint);
+ delete_fn(this);
+}
+
void buff_Init(entity this)
{
if(!cvar("g_buffs")) { delete(this); return; }
buff_SetCooldown(this, autocvar_g_buffs_cooldown_activate + max(0, game_starttime - time));
this.buff_active = !this.buff_activetime;
this.pflags = PFLAGS_FULLDYNAMIC;
+ this.dtor = buff_Delete;
if(this.spawnflags & 1)
this.noalign = true;
{
entity player = M_ARGV(0, entity);
- STAT(BUFFS, player) = 0;
- STAT(BUFF_TIME, player) = 0;
+ player.oldbuffs = 0;
PS(player).buff_shield = time + 0.5; // prevent picking up buffs immediately
// reset timers here to prevent them continuing after re-spawn
player.buff_disability_time = 0;
if(STAT(BUFFS, frag_target))
{
int buffid = buff_FirstFromFlags(STAT(BUFFS, frag_target)).m_id;
- Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(frag_target))
+ Send_Notification(NOTIF_ALL_EXCEPT, frag_target, MSG_INFO, INFO_ITEM_BUFF_LOST, frag_target.netname, buffid);
STAT(BUFFS, frag_target) = 0;
+ STAT(BUFF_TIME, frag_target) = 0;
if(frag_target.buff_model)
{
{
int buffid = buff_FirstFromFlags(STAT(BUFFS, player)).m_id;
Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid);
- Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
+ if(!IS_INDEPENDENT_PLAYER(player))
+ Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
STAT(BUFFS, player) = 0;
+ STAT(BUFF_TIME, player) = 0;
PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay);
- //STAT(BUFF_TIME, player) = 0; // already notified
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
return true;
}
Send_Notification(NOTIF_ONE, player, MSG_MULTI, ITEM_BUFF_DROP, buffid); // TODO: special timeout message?
sound(player, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
}
- else
+ else if(!IS_INDEPENDENT_PLAYER(player))
Send_Notification(NOTIF_ALL_EXCEPT, player, MSG_INFO, INFO_ITEM_BUFF_LOST, player.netname, buffid);
STAT(BUFFS, player) = 0;
PS(player).buff_shield = time + max(0, autocvar_g_buffs_pickup_delay); // always put in a delay, even if small
{
entity buff = buff_FirstFromFlags(STAT(BUFFS, player));
float bufftime = buff != BUFF_Null ? buff.m_time(buff) : 0;
- STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
+ if(STAT(BUFF_TIME, player) <= time) // if the player still has a buff countdown, don't reset it!
+ STAT(BUFF_TIME, player) = (bufftime) ? time + bufftime : 0;
BUFF_ONADD(BUFF_AMMO)
{
// generated file; do not modify
+#ifdef CSQC
+ #include <common/mutators/mutator/dodging/cl_dodging.qc>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/dodging/sv_dodging.qc>
#endif
// generated file; do not modify
+#ifdef CSQC
+ #include <common/mutators/mutator/dodging/cl_dodging.qh>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/dodging/sv_dodging.qh>
#endif
--- /dev/null
+#include "cl_dodging.qh"
--- /dev/null
+#pragma once
+
+float cvar_cl_dodging_timeout;
+REPLICATE(cvar_cl_dodging_timeout, float, "cl_dodging_timeout");
#endif
#ifdef CSQC
+ float cvar_cl_dodging_timeout;
#define PHYS_DODGING_FRAMETIME (1 / (frametime <= 0 ? 60 : frametime))
#define PHYS_DODGING_TIMEOUT(s) STAT(DODGING_TIMEOUT)
#define PHYS_DODGING_PRESSED_KEYS(s) (s).pressedkeys
#elif defined(SVQC)
+ .float cvar_cl_dodging_timeout;
#define PHYS_DODGING_FRAMETIME sys_frametime
#define PHYS_DODGING_TIMEOUT(s) CS(s).cvar_cl_dodging_timeout
#define PHYS_DODGING_PRESSED_KEYS(s) CS(s).pressedkeys
#include <common/animdecide.qh>
#include <common/physics/player.qh>
-.float cvar_cl_dodging_timeout;
-
REGISTER_MUTATOR(dodging, cvar("g_dodging"))
{
// this just turns on the cvar.
float autocvar_g_instagib_speed_highspeed;
IntrusiveList g_instagib_items;
-STATIC_INIT()
+STATIC_INIT(instagib)
{
g_instagib_items = IL_NEW();
IL_PUSH(g_instagib_items, ITEM_VaporizerCells);
#endif
#ifdef CSQC
-void Item_ItemsTime_Init()
-{
- FOREACH(Items, true, {
- ItemsTime_time[it.m_id] = -1;
- });
- ItemsTime_time[Items_MAX] = -1;
-}
STATIC_INIT(ItemsTime_Init) {
- Item_ItemsTime_Init();
+ FOREACH(Items, true, {
+ ItemsTime_time[it.m_id] = -1;
+ });
+ ItemsTime_time[Items_MAX] = -1;
}
int autocvar_hud_panel_itemstime = 2;
// reserve one more spot for superweapons time
float it_times[Items_MAX + 1];
-void Item_ItemsTime_Init()
-{
- FOREACH(Items, Item_ItemsTime_Allow(it), {
- it_times[it.m_id] = -1;
- });
- it_times[Items_MAX] = -1;
-}
-
STATIC_INIT(ItemsTime_Init) {
- // items time
- Item_ItemsTime_Init();
+ FOREACH(Items, Item_ItemsTime_Allow(it), {
+ it_times[it.m_id] = -1;
+ });
+ it_times[Items_MAX] = -1;
}
void Item_ItemsTime_ResetTimes()
.bool multijump_ready;
#ifdef CSQC
+bool cvar_cl_multijump;
bool autocvar_cl_multijump = true;
#define PHYS_MULTIJUMP_CLIENT(s) autocvar_cl_multijump
}
}
-#ifdef SVQC
-
REPLICATE(cvar_cl_multijump, bool, "cl_multijump");
+#ifdef SVQC
+
MUTATOR_HOOKFUNCTION(multijump, BuildMutatorsString)
{
M_ARGV(0, string) = strcat(M_ARGV(0, string), ":multijump");
REGISTER_STAT(NADES_SMALL, int, autocvar_g_nades_nade_small)
#ifdef GAMEQC
+REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
+REPLICATE(cvar_cl_pokenade_type, string, "cl_pokenade_type");
+
entity Nade_TrailEffect(int proj, int nade_team)
{
switch (proj)
damage = this.max_health * 0.1;
else if(DEATH_ISWEAPON(deathtype, WEP_SHOCKWAVE) || DEATH_ISWEAPON(deathtype, WEP_SHOTGUN)) // WEAPONTODO
{
- if(deathtype & HITTYPE_SECONDARY)
- {
- damage = this.max_health * 0.1;
- force *= 10;
- }
- else
+ if(!(deathtype & HITTYPE_SECONDARY))
damage = this.max_health * 1.15;
}
+ // melee slaps
+ entity death_weapon = DEATH_WEAPONOF(deathtype);
+ if(((deathtype & HITTYPE_SECONDARY) ? (death_weapon.spawnflags & WEP_TYPE_MELEE_SEC) : (death_weapon.spawnflags & WEP_TYPE_MELEE_PRI)))
+ {
+ damage = this.max_health * 0.1;
+ force *= 10;
+ }
+
this.velocity += force;
UpdateCSQCProjectile(this);
if ( STAT(NADE_BONUS_SCORE, player) >= 1 )
{
Send_Notification(NOTIF_ONE, player, MSG_CENTER, CENTER_NADE_BONUS);
- play2(player, SND(KH_ALARM));
+ play2(player, SND(NADE_BONUS));
STAT(NADE_BONUS, player)++;
STAT(NADE_BONUS_SCORE, player) -= 1;
}
}
}
ENDCLASS(NadeOffhand)
-NadeOffhand OFFHAND_NADE; STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
+NadeOffhand OFFHAND_NADE;
+STATIC_INIT(OFFHAND_NADE) { OFFHAND_NADE = NEW(NadeOffhand); }
MUTATOR_HOOKFUNCTION(nades, ForbidThrowCurrentWeapon, CBC_ORDER_LAST)
{
if(IS_PLAYER(frag_attacker))
{
- float killcount_bonus = ((CS(frag_attacker).killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * CS(frag_attacker).killcount, autocvar_g_nades_bonus_score_medium) : autocvar_g_nades_bonus_score_minor);
+ float killcount_bonus = ((CS(frag_attacker).killcount >= 1) ? bound(0, autocvar_g_nades_bonus_score_minor * CS(frag_attacker).killcount, autocvar_g_nades_bonus_score_medium)
+ : autocvar_g_nades_bonus_score_minor);
if (SAME_TEAM(frag_attacker, frag_target) || frag_attacker == frag_target)
nades_RemoveBonus(frag_attacker);
STAT(VEIL_ORB_ALPHA, client) = STAT(VEIL_ORB_ALPHA, spectatee);
}
-REPLICATE(cvar_cl_nade_type, int, "cl_nade_type");
-REPLICATE(cvar_cl_pokenade_type, string, "cl_pokenade_type");
-
MUTATOR_HOOKFUNCTION(nades, BuildMutatorsString)
{
M_ARGV(0, string) = strcat(M_ARGV(0, string), ":Nades");
#endif
#ifdef CSQC
+float cvar_cl_nade_type;
+string cvar_cl_pokenade_type;
bool Projectile_isnade(int proj); // TODO: remove
void DrawAmmoNades(vector myPos, vector mySize, bool draw_expanding, float expand_time); // TODO: mutator
-> This will spawn as Rifle in this mutator ONLY, and as Vortex otherwise.
{
-"classname" "weapon_vortext"
+"classname" "weapon_vortex"
"new_toys" "vortex rifle"
}
-> This will spawn as either Vortex or Rifle in this mutator ONLY, and as Vortex otherwise.
/* spawnfunc */ ATTRIB(OverkillHeavyMachineGun, m_canonical_spawnfunc, string, "weapon_okhmg");
/* ammotype */ ATTRIB(OverkillHeavyMachineGun, ammo_type, int, RES_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);
+/* flags */ ATTRIB(OverkillHeavyMachineGun, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_RELOADABLE | WEP_TYPE_HITSCAN | WEP_FLAG_SUPERWEAPON | WEP_FLAG_PENETRATEWALLS);
/* rating */ ATTRIB(OverkillHeavyMachineGun, bot_pickupbasevalue, float, 10000);
/* color */ ATTRIB(OverkillHeavyMachineGun, wpcolor, vector, '0.5 0.5 0');
/* modelname */ ATTRIB(OverkillHeavyMachineGun, mdl, string, "ok_hmg");
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
/* spawnfunc */ ATTRIB(OverkillRocketPropelledChainsaw, m_canonical_spawnfunc, string, "weapon_okrpc");
/* ammotype */ ATTRIB(OverkillRocketPropelledChainsaw, ammo_type, int, RES_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);
+/* flags */ ATTRIB(OverkillRocketPropelledChainsaw, spawnflags, int, WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | 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");
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
.Weapon ok_lastwep[MAX_WEAPONSLOTS];
IntrusiveList g_overkill_items;
-STATIC_INIT()
+STATIC_INIT(overkill)
{
g_overkill_items = IL_NEW();
IL_PUSH(g_overkill_items, ITEM_HealthMega);
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;
}
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_armormedium = true;
+bool autocvar_g_overkill_filter_armorbig = true;
bool autocvar_g_overkill_filter_armormega;
.float ok_item;
// generated file; do not modify
+#ifdef CSQC
+ #include <common/mutators/mutator/spawn_near_teammate/cl_spawn_near_teammate.qc>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qc>
#endif
// generated file; do not modify
+#ifdef CSQC
+ #include <common/mutators/mutator/spawn_near_teammate/cl_spawn_near_teammate.qh>
+#endif
#ifdef SVQC
#include <common/mutators/mutator/spawn_near_teammate/sv_spawn_near_teammate.qh>
#endif
--- /dev/null
+#include "cl_spawn_near_teammate.qh"
--- /dev/null
+#pragma once
+
+float cvar_cl_spawn_near_teammate;
+REPLICATE(cvar_cl_spawn_near_teammate, bool, "cl_spawn_near_teammate");
if (autocvar_cl_hidewaypoints >= 2)
return;
- if (this.hideflags & 1 && autocvar_cl_hidewaypoints)
+ if ((this.hideflags & 1) && autocvar_cl_hidewaypoints)
return; // fixed waypoint
InterpolateOrigin_Do(this);
bool autocvar_g_waypointsprite_turrets = true;
float autocvar_g_waypointsprite_turrets_maxdist = 5000;
bool autocvar_g_waypointsprite_turrets_text = false;
+bool autocvar_g_waypointsprite_turrets_onlyhurt = false;
bool autocvar_g_waypointsprite_uppercase;
bool autocvar_g_waypointsprite_text;
float autocvar_g_waypointsprite_iconsize = 32;
#define N_GNTLOFF 1
#define N__ALWAYS 2
-#define MULTITEAM_ANNCE2(prefix, default, sound, channel, volume, position) \
- MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, default, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position) \
- MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, default, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position)
-#define MULTITEAM_ANNCE3(prefix, default, sound, channel, volume, position) \
- MULTITEAM_ANNCE2(prefix, default, sound, channel, volume, position) \
- MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, default, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position)
-#define MULTITEAM_ANNCE4(prefix, default, sound, channel, volume, position) \
- MULTITEAM_ANNCE3(prefix, default, sound, channel, volume, position) \
- MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, default, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position)
-#define MULTITEAM_ANNCE(prefix, teams, default, sound, channel, volume, position) \
- NOTIF_ADD_AUTOCVAR(ANNCE_##prefix, default) \
- MULTITEAM_ANNCE##teams(prefix, default, sound, channel, volume, position)
+#define MULTITEAM_ANNCE(prefix, defaultvalue, sound, channel, volume, position) \
+ NOTIF_ADD_AUTOCVAR(ANNCE_##prefix, defaultvalue) \
+ MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_1)), channel, volume, position) \
+ MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_2)), channel, volume, position) \
+ MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_3)), channel, volume, position) \
+ MSG_ANNCE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, sprintf(sound, strtolower(STATIC_NAME_TEAM_4)), channel, volume, position)
// MSG_ANNCE_NOTIFICATIONS
MSG_ANNCE_NOTIF(ACHIEVEMENT_AIRSHOT, N_GNTLOFF, "airshot", CH_INFO, VOL_BASEVOICE, ATTEN_NONE)
#define N_CONSOLE 1
#define N_CHATCON 2
-#define MULTITEAM_INFO2(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- MSG_INFO_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, default, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_1)), TCR(normal, type, 1), TCR(gentle, type, 1)) \
- MSG_INFO_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, default, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_2)), TCR(normal, type, 2), TCR(gentle, type, 2))
-#define MULTITEAM_INFO3(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- MULTITEAM_INFO2(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- MSG_INFO_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, default, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_3)), TCR(normal, type, 3), TCR(gentle, type, 3))
-#define MULTITEAM_INFO4(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- MULTITEAM_INFO3(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- MSG_INFO_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, default, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_4)), TCR(normal, type, 4), TCR(gentle, type, 4))
-#define MULTITEAM_INFO(prefix, teams, default, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
- NOTIF_ADD_AUTOCVAR(INFO_##prefix, default) \
- MULTITEAM_INFO##teams(prefix, default, strnum, flnum, args, hudargs, icon, normal, gentle, type)
+#define MULTITEAM_INFO(prefix, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle, type) \
+ NOTIF_ADD_AUTOCVAR(INFO_##prefix, defaultvalue) \
+ MSG_INFO_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_1)), TCR(normal, type, 1), TCR(gentle, type, 1)) \
+ MSG_INFO_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_2)), TCR(normal, type, 2), TCR(gentle, type, 2)) \
+ MSG_INFO_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_3)), TCR(normal, type, 3), TCR(gentle, type, 3)) \
+ MSG_INFO_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, strnum, flnum, args, hudargs, sprintf(icon, strtolower(STATIC_NAME_TEAM_4)), TCR(normal, type, 4), TCR(gentle, type, 4))
// MSG_INFO_NOTIFICATIONS
MSG_INFO_NOTIF(CHAT_NOSPECTATORS, N_CHATCON, 0, 0, "", "", "", _("^F4NOTE: ^BGSpectator chat is not sent to players during the match"), "")
- MULTITEAM_INFO(CTF_CAPTURE, 4, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag"), "", FLAG)
- MULTITEAM_INFO(CTF_CAPTURE_BROKEN, 4, N_CONSOLE, 2, 2, "s1 f1dtime s2 f2dtime", "s1", "notify_%s_captured", _("^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"), "", FLAG)
+ MULTITEAM_INFO(CTF_CAPTURE, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag"), "", FLAG)
+ MULTITEAM_INFO(CTF_CAPTURE_BROKEN, N_CONSOLE, 2, 2, "s1 f1dtime s2 f2dtime", "s1", "notify_%s_captured", _("^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"), "", FLAG)
MSG_INFO_NOTIF(CTF_CAPTURE_NEUTRAL, N_CONSOLE, 1, 0, "s1", "s1", "notify_neutral_captured", _("^BG%s^BG captured the flag"), "")
- MULTITEAM_INFO(CTF_CAPTURE_TIME, 4, N_CONSOLE, 1, 1, "s1 f1dtime", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "", FLAG)
- MULTITEAM_INFO(CTF_CAPTURE_UNBROKEN, 4, N_CONSOLE, 2, 2, "s1 f1dtime s2 f2dtime", "s1", "notify_%s_captured", _("^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"), "", FLAG)
- MULTITEAM_INFO(CTF_FLAGRETURN_ABORTRUN, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "", FLAG)
+ MULTITEAM_INFO(CTF_CAPTURE_TIME, N_CONSOLE, 1, 1, "s1 f1dtime", "s1", "notify_%s_captured", _("^BG%s^BG captured the ^TC^TT^BG flag in ^F1%s^BG seconds"), "", FLAG)
+ MULTITEAM_INFO(CTF_CAPTURE_UNBROKEN, N_CONSOLE, 2, 2, "s1 f1dtime s2 f2dtime", "s1", "notify_%s_captured", _("^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"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_ABORTRUN, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was returned to base by its owner"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_ABORTRUN_NEUTRAL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe flag was returned by its owner"), "")
- MULTITEAM_INFO(CTF_FLAGRETURN_DAMAGED, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_DAMAGED, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was destroyed and returned to base"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_DAMAGED_NEUTRAL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe flag was destroyed and returned to base"), "")
- MULTITEAM_INFO(CTF_FLAGRETURN_DROPPED, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_DROPPED, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag was dropped in the base and returned itself"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_DROPPED_NEUTRAL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe flag was dropped in the base and returned itself"), "")
- MULTITEAM_INFO(CTF_FLAGRETURN_NEEDKILL, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_NEEDKILL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag fell somewhere it couldn't be reached and returned to base"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_NEEDKILL_NEUTRAL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe flag fell somewhere it couldn't be reached and returned to base"), "")
- MULTITEAM_INFO(CTF_FLAGRETURN_SPEEDRUN, 4, N_CONSOLE, 0, 1, "f1dtime", "", "", _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_SPEEDRUN, N_CONSOLE, 0, 1, "f1dtime", "", "", _("^BGThe ^TC^TT^BG flag became impatient after ^F1%.2f^BG seconds and returned itself"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_SPEEDRUN_NEUTRAL, N_CONSOLE, 0, 1, "f1dtime", "", "", _("^BGThe flag became impatient after ^F1%.2f^BG seconds and returned itself"), "")
- MULTITEAM_INFO(CTF_FLAGRETURN_TIMEOUT, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag has returned to the base"), "", FLAG)
+ MULTITEAM_INFO(CTF_FLAGRETURN_TIMEOUT, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG flag has returned to the base"), "", FLAG)
MSG_INFO_NOTIF(CTF_FLAGRETURN_TIMEOUT_NEUTRAL, N_CONSOLE, 0, 0, "", "", "", _("^BGThe flag has returned to the base"), "")
- MULTITEAM_INFO(CTF_LOST, 4, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag"), "", FLAG)
+ MULTITEAM_INFO(CTF_LOST, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_lost", _("^BG%s^BG lost the ^TC^TT^BG flag"), "", FLAG)
MSG_INFO_NOTIF(CTF_LOST_NEUTRAL, N_CONSOLE, 1, 0, "s1", "s1", "notify_neutral_lost", _("^BG%s^BG lost the flag"), "")
- MULTITEAM_INFO(CTF_PICKUP, 4, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag"), "", FLAG)
+ MULTITEAM_INFO(CTF_PICKUP, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_taken", _("^BG%s^BG got the ^TC^TT^BG flag"), "", FLAG)
MSG_INFO_NOTIF(CTF_PICKUP_NEUTRAL, N_CONSOLE, 1, 0, "s1", "s1", "notify_neutral_taken", _("^BG%s^BG got the flag"), "")
- MULTITEAM_INFO(CTF_RETURN, 4, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag"), "", FLAG)
- MULTITEAM_INFO(CTF_RETURN_MONSTER, 4, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag"), "", FLAG)
+ MULTITEAM_INFO(CTF_RETURN, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag"), "", FLAG)
+ MULTITEAM_INFO(CTF_RETURN_MONSTER, N_CONSOLE, 1, 0, "s1", "s1", "notify_%s_returned", _("^BG%s^BG returned the ^TC^TT^BG flag"), "", FLAG)
MSG_INFO_NOTIF(COINTOSS, N_CHATCON, 1, 0, "s1", "", "", _("^F2Throwing coin... Result: %s^F2!"), "")
MSG_INFO_NOTIF(DEATH_SELF_VH_WAKI_ROCKET, N_CONSOLE, 2, 1, "s1 s2loc spree_lost", "s1", "notify_death", _("^BG%s^K1 couldn't find shelter from a Racer rocket%s%s"), "")
MSG_INFO_NOTIF(DEATH_SELF_VOID, N_CONSOLE, 3, 1, "s1 s2 s2loc spree_lost", "s1", "notify_void", "^BG%s^K1 %s^K1%s%s", "")
- MULTITEAM_INFO(DEATH_TEAMKILL, 4, N_CONSOLE, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "", NAME)
+ MULTITEAM_INFO(DEATH_TEAMKILL, N_CONSOLE, 3, 1, "s1 s2 s3loc spree_end", "s2 s1", "notify_teamkill_%s", _("^BG%s^K1 was betrayed by ^BG%s^K1%s%s"), "", NAME)
MSG_INFO_NOTIF(DOMINATION_CAPTURE_TIME, N_CONSOLE, 2, 2, "s1 s2 f1 f1points f2", "", "", _("^BG%s^BG%s^BG (%s %s every %s seconds)"), "")
MSG_INFO_NOTIF(FREEZETAG_AUTO_REVIVED, N_CONSOLE, 1, 1, "s1 f1", "", "", _("^BG%s^K3 was automatically revived after %s second(s)"), "")
MSG_INFO_NOTIF(FREEZETAG_SELF, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^K1 froze themself"), "")
- MULTITEAM_INFO(ROUND_TEAM_WIN, 4, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG team wins the round"), "", NAME)
+ MULTITEAM_INFO(ROUND_TEAM_WIN, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG team wins the round"), "", NAME)
MSG_INFO_NOTIF(ROUND_PLAYER_WIN, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG wins the round"), "")
MSG_INFO_NOTIF(ROUND_TIED, N_CONSOLE, 0, 0, "", "", "", _("^BGRound tied"), "")
MSG_INFO_NOTIF(ROUND_OVER, N_CONSOLE, 0, 0, "", "", "", _("^BGRound over, there's no winner"), "")
MSG_INFO_NOTIF(CONNECTING, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG is connecting..."), "")
MSG_INFO_NOTIF(JOIN_CONNECT, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 connected"), "")
MSG_INFO_NOTIF(JOIN_PLAY, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 is now playing"), "")
- MULTITEAM_INFO(JOIN_PLAY_TEAM, 4, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 is now playing on the ^TC^TT team"), "", NAME)
+ MULTITEAM_INFO(JOIN_PLAY_TEAM, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 is now playing on the ^TC^TT team"), "", NAME)
MSG_INFO_NOTIF(KEEPAWAY_DROPPED, N_CONSOLE, 1, 0, "s1", "s1", "notify_balldropped", _("^BG%s^BG has dropped the ball!"), "")
MSG_INFO_NOTIF(KEEPAWAY_PICKUP, N_CONSOLE, 1, 0, "s1", "s1", "notify_ballpickedup", _("^BG%s^BG has picked up the ball!"), "")
- MULTITEAM_INFO(KEYHUNT_CAPTURE, 4, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG captured the keys for the ^TC^TT team"), "", NAME)
- MULTITEAM_INFO(KEYHUNT_DROP, 4, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG dropped the ^TC^TT Key"), "", KEY)
- MULTITEAM_INFO(KEYHUNT_LOST, 4, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG lost the ^TC^TT Key"), "", KEY)
- MULTITEAM_INFO(KEYHUNT_PUSHED, 4, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^BG%s^BG pushed %s^BG causing the ^TC^TT Key ^BGdestruction"), "", KEY)
- MULTITEAM_INFO(KEYHUNT_DESTROYED, 4, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG destroyed the ^TC^TT Key"), "", KEY)
- MULTITEAM_INFO(KEYHUNT_PICKUP, 4, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG picked up the ^TC^TT Key"), "", KEY)
+ MULTITEAM_INFO(KEYHUNT_CAPTURE, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG captured the keys for the ^TC^TT team"), "", NAME)
+ MULTITEAM_INFO(KEYHUNT_DROP, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG dropped the ^TC^TT Key"), "", KEY)
+ MULTITEAM_INFO(KEYHUNT_LOST, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG lost the ^TC^TT Key"), "", KEY)
+ MULTITEAM_INFO(KEYHUNT_PUSHED, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^BG%s^BG pushed %s^BG causing the ^TC^TT Key ^BGdestruction"), "", KEY)
+ MULTITEAM_INFO(KEYHUNT_DESTROYED, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG destroyed the ^TC^TT Key"), "", KEY)
+ MULTITEAM_INFO(KEYHUNT_PICKUP, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^BG picked up the ^TC^TT Key"), "", KEY)
MSG_INFO_NOTIF(LMS_FORFEIT, N_CHATCON, 1, 0, "s1", "", "", _("^BG%s^F3 forfeited"), "")
MSG_INFO_NOTIF(LMS_NOLIVES, N_CONSOLE, 1, 0, "s1", "", "", _("^BG%s^F3 has no more lives left"), "")
MSG_INFO_NOTIF(MONSTERS_DISABLED, N_CONSOLE, 0, 0, "", "", "", _("^BGMonsters are currently disabled"), "")
- MULTITEAM_INFO(NEXBALL_RETURN_HELD, 4, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG team held the ball for too long"), "", NAME)
+ MULTITEAM_INFO(NEXBALL_RETURN_HELD, N_CONSOLE, 0, 0, "", "", "", _("^BGThe ^TC^TT^BG team held the ball for too long"), "", NAME)
MSG_INFO_NOTIF(ONSLAUGHT_CAPTURE, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^BG%s^BG captured %s^BG control point"), "")
- MULTITEAM_INFO(ONSLAUGHT_CPDESTROYED, 4, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^TC^TT^BG team %s^BG control point has been destroyed by %s"), "", NAME)
- MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED, 4, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator has been destroyed"), "", GENERATOR)
- MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED_OVERTIME, 4, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator spontaneously combusted due to overtime!"), "", GENERATOR)
+ MULTITEAM_INFO(ONSLAUGHT_CPDESTROYED, N_CONSOLE, 2, 0, "s1 s2", "", "", _("^TC^TT^BG team %s^BG control point has been destroyed by %s"), "", NAME)
+ MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator has been destroyed"), "", GENERATOR)
+ MULTITEAM_INFO(ONSLAUGHT_GENDESTROYED_OVERTIME, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT^BG generator spontaneously combusted due to overtime!"), "", GENERATOR)
MSG_INFO_NOTIF(POWERUP_INVISIBILITY, N_CONSOLE, 1, 0, "s1", "s1", "strength", _("^BG%s^K1 picked up Invisibility"), "")
MSG_INFO_NOTIF(POWERUP_SHIELD, N_CONSOLE, 1, 0, "s1", "s1", "shield", _("^BG%s^K1 picked up Shield"), "")
MULTIICON_INFO(MINIGAME_INVITE, N_CONSOLE, 2, 0, "s2 minigame1_name s1", "s2", "minigame1_d", "minigames/%s/icon_notif", _("^F4You have been invited by ^BG%s^F4 to join their game of ^F2%s^F4 (^F1%s^F4)"), "")
- MULTITEAM_INFO(SCORES, 4, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT ^BGteam scores!"), "", NAME)
+ MULTITEAM_INFO(SCORES, N_CONSOLE, 0, 0, "", "", "", _("^TC^TT ^BGteam scores!"), "", NAME)
MSG_INFO_NOTIF(SPECTATE_WARNING, N_CONSOLE, 0, 1, "f1secs", "", "", _("^F2You have to become a player within the next %s, otherwise you will be kicked, because spectating isn't allowed at this time!"), "")
#define N_DISABL 0
#define N_ENABLE 1
-#define MULTITEAM_CENTER2(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- MSG_CENTER_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, default, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 1), TCR(gentle, type, 1)) \
- MSG_CENTER_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, default, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 2), TCR(gentle, type, 2))
-#define MULTITEAM_CENTER3(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- MULTITEAM_CENTER2(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- MSG_CENTER_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, default, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 3), TCR(gentle, type, 3))
-#define MULTITEAM_CENTER4(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- MULTITEAM_CENTER3(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- MSG_CENTER_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, default, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 4), TCR(gentle, type, 4))
-#define MULTITEAM_CENTER(prefix, teams, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
- NOTIF_ADD_AUTOCVAR(CENTER_##prefix, default) \
- MULTITEAM_CENTER##teams(prefix, default, strnum, flnum, args, cpid, durcnt, normal, gentle, type)
+#define MULTITEAM_CENTER(prefix, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle, type) \
+ NOTIF_ADD_AUTOCVAR(CENTER_##prefix, defaultvalue) \
+ MSG_CENTER_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 1), TCR(gentle, type, 1)) \
+ MSG_CENTER_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 2), TCR(gentle, type, 2)) \
+ MSG_CENTER_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 3), TCR(gentle, type, 3)) \
+ MSG_CENTER_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, strnum, flnum, args, cpid, durcnt, TCR(normal, type, 4), TCR(gentle, type, 4))
// MSG_CENTER_NOTIFICATIONS
MSG_CENTER_NOTIF(ALONE, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^F4You are now alone!"), "")
MSG_CENTER_NOTIF(CTF_CAPTURESHIELD_FREE, N_ENABLE, 0, 0, "", CPID_CTF_CAPSHIELD, "0 0", _("^BGYou are now free.\n^BGFeel free to ^F2try to capture^BG the flag again\n^BGif you think you will succeed."), "")
MSG_CENTER_NOTIF(CTF_CAPTURESHIELD_INACTIVE, N_ENABLE, 0, 0, "", CPID_CTF_CAPSHIELD, "0 0", _("^BGThis flag is currently inactive"), "")
MSG_CENTER_NOTIF(CTF_CAPTURESHIELD_SHIELDED, N_ENABLE, 0, 0, "", CPID_CTF_CAPSHIELD, "0 0", _("^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."), "")
- MULTITEAM_CENTER(CTF_CAPTURE, 4, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "", FLAG)
+ MULTITEAM_CENTER(CTF_CAPTURE, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou captured the ^TC^TT^BG flag!"), "", FLAG)
MSG_CENTER_NOTIF(CTF_CAPTURE_NEUTRAL, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou captured the flag!"), "")
MSG_CENTER_NOTIF(CTF_FLAG_THROW_PUNISH, N_ENABLE, 0, 1, "f1secs", CPID_CTF_LOWPRIO, "0 0", _("^BGToo many flag throws! Throwing disabled for %s."), "")
- MULTITEAM_CENTER(CTF_PASS_OTHER, 4, N_ENABLE, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PASS_OTHER, N_ENABLE, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the ^TC^TT^BG flag to %s"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PASS_OTHER_NEUTRAL, N_ENABLE, 2, 0, "s1 s2", CPID_CTF_PASS, "0 0", _("^BG%s^BG passed the flag to %s"), "")
- MULTITEAM_CENTER(CTF_PASS_RECEIVED, 4, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PASS_RECEIVED, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the ^TC^TT^BG flag from %s"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PASS_RECEIVED_NEUTRAL, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou received the flag from %s"), "")
MSG_CENTER_NOTIF(CTF_PASS_REQUESTED, N_ENABLE, 1, 0, "pass_key s1", CPID_CTF_PASS, "0 0", _("^BGPress ^F2%s^BG to receive the flag from %s^BG"), "")
MSG_CENTER_NOTIF(CTF_PASS_REQUESTING, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGRequesting %s^BG to pass you the flag"), "")
- MULTITEAM_CENTER(CTF_PASS_SENT, 4, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PASS_SENT, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the ^TC^TT^BG flag to %s"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PASS_SENT_NEUTRAL, N_ENABLE, 1, 0, "s1", CPID_CTF_PASS, "0 0", _("^BGYou passed the flag to %s"), "")
- MULTITEAM_CENTER(CTF_PICKUP, 4, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PICKUP, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got the ^TC^TT^BG flag!"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PICKUP_NEUTRAL, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got the flag!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_RETURN, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got your %steam^BG's flag, return it!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_RETURN_ENEMY, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYou got the %senemy^BG's flag, return it!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE, N_ENABLE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGThe %senemy (^BG%s%s)^BG got the flag! Retrieve it!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_ENEMY_TEAM, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGThe %senemy^BG got their flag! Retrieve it!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_ENEMY_TEAM_VERBOSE, N_ENABLE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGThe %senemy (^BG%s%s)^BG got their flag! Retrieve it!"), "")
- MULTITEAM_CENTER(CTF_PICKUP_TEAM, 4, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"), "", FLAG)
- MULTITEAM_CENTER(CTF_PICKUP_TEAM_VERBOSE, 4, N_ENABLE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PICKUP_TEAM, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate^BG got the ^TC^TT^BG flag! Protect them!"), "", FLAG)
+ MULTITEAM_CENTER(CTF_PICKUP_TEAM_VERBOSE, N_ENABLE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the ^TC^TT^BG flag! Protect them!"), "", FLAG)
MSG_CENTER_NOTIF(CTF_PICKUP_TEAM_NEUTRAL, N_ENABLE, 1, 0, "s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate^BG got the flag! Protect them!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_TEAM_VERBOSE_NEUTRAL, N_ENABLE, 2, 0, "s1 s2 s1", CPID_CTF_LOWPRIO, "0 0", _("^BGYour %steam mate (^BG%s%s)^BG got the flag! Protect them!"), "")
MSG_CENTER_NOTIF(CTF_PICKUP_VISIBLE, N_ENABLE, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGEnemies can now see you on radar!"), "")
- MULTITEAM_CENTER(CTF_RETURN, 4, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "", FLAG)
+ MULTITEAM_CENTER(CTF_RETURN, N_ENABLE, 0, 0, "", CPID_CTF_LOWPRIO, "0 0", _("^BGYou returned the ^TC^TT^BG flag!"), "", FLAG)
MSG_CENTER_NOTIF(CTF_STALEMATE_CARRIER, N_ENABLE, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Enemies can now see you on radar!"), "")
MSG_CENTER_NOTIF(CTF_STALEMATE_OTHER, N_ENABLE, 0, 0, "", CPID_STALEMATE, "0 0", _("^BGStalemate! Flag carriers can now be seen by enemies on radar!"), "")
MSG_CENTER_NOTIF(GENERATOR_UNDERATTACK, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^BGThe generator is under attack!"), "")
- MULTITEAM_CENTER(ROUND_TEAM_LOSS, 4, N_ENABLE, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team loses the round"), "", NAME)
- MULTITEAM_CENTER(ROUND_TEAM_WIN, 4, N_ENABLE, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "", NAME)
+ MULTITEAM_CENTER(ROUND_TEAM_LOSS, N_ENABLE, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team loses the round"), "", NAME)
+ MULTITEAM_CENTER(ROUND_TEAM_WIN, N_ENABLE, 0, 0, "", CPID_ROUND, "0 0", _("^TC^TT^BG team wins the round"), "", NAME)
MSG_CENTER_NOTIF(ROUND_PLAYER_WIN, N_ENABLE, 1, 0, "s1", CPID_ROUND, "0 0", _("^BG%s^BG wins the round"), "")
MSG_CENTER_NOTIF(FREEZETAG_SELF, N_ENABLE, 0, 0, "", CPID_Null, "0 0", _("^K1You froze yourself"), "")
MSG_CENTER_NOTIF(KEEPAWAY_WARN, N_ENABLE, 0, 0, "", CPID_KEEPAWAY_WARN, "0 0", _("^BGKilling people while you don't have the ball gives no points!"), "")
MSG_CENTER_NOTIF(KEYHUNT_HELP, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nHelp the key carriers to meet!"), "")
- MULTITEAM_CENTER(KEYHUNT_INTERFERE, 4, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in ^TC^TT team^BG's hands!\nInterfere ^F4NOW^BG!"), "", NAME)
+ MULTITEAM_CENTER(KEYHUNT_INTERFERE, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in ^TC^TT team^BG's hands!\nInterfere ^F4NOW^BG!"), "", NAME)
MSG_CENTER_NOTIF(KEYHUNT_MEET, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGAll keys are in your team's hands!\nMeet the other key carriers ^F4NOW^BG!"), "")
MSG_CENTER_NOTIF(KEYHUNT_ROUNDSTART, N_ENABLE, 0, 1, "", CPID_KEYHUNT_OTHER, "1 f1", _("^F4Round will start in ^COUNT"), "")
MSG_CENTER_NOTIF(KEYHUNT_SCAN, N_ENABLE, 0, 1, "", CPID_KEYHUNT_OTHER, "f1 0", _("^BGScanning frequency range..."), "")
- MULTITEAM_CENTER(KEYHUNT_START, 4, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "", KEY)
+ MULTITEAM_CENTER(KEYHUNT_START, N_ENABLE, 0, 0, "", CPID_KEYHUNT, "0 0", _("^BGYou are starting with the ^TC^TT Key"), "", KEY)
MSG_CENTER_NOTIF(LMS_NOLIVES, N_ENABLE, 0, 0, "", CPID_LMS, "0 0", _("^BGYou have no lives left, you must wait until the next match"), "")
MSG_CENTER_NOTIF(NIX_NEWWEAPON, N_ENABLE, 0, 1, "item_wepname", CPID_NIX, "0 0", _("^F2Active weapon: ^F1%s"), "")
MSG_CENTER_NOTIF(ONS_CAPTURE, N_ENABLE, 1, 0, "s1", CPID_ONSLAUGHT, "0 0", _("^BGYou captured %s^BG control point"), "")
- MULTITEAM_CENTER(ONS_CAPTURE_TEAM, 4, N_ENABLE, 1, 0, "s1", CPID_ONSLAUGHT, "0 0", _("^TC^TT^BG team captured %s^BG control point"), "", NAME)
+ MULTITEAM_CENTER(ONS_CAPTURE_TEAM, N_ENABLE, 1, 0, "s1", CPID_ONSLAUGHT, "0 0", _("^TC^TT^BG team captured %s^BG control point"), "", NAME)
MSG_CENTER_NOTIF(ONS_CONTROLPOINT_SHIELDED, N_ENABLE, 0, 0, "", CPID_ONS_CAPSHIELD, "0 0", _("^BGThis control point currently cannot be captured"), "")
MSG_CENTER_NOTIF(ONS_GENERATOR_SHIELDED, N_ENABLE, 0, 0, "", CPID_ONS_CAPSHIELD, "0 0", _("^BGThe enemy generator cannot be destroyed yet\n^F2Capture some control points to unshield it"), "")
- MULTITEAM_CENTER(ONS_NOTSHIELDED, 4, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "", NAME)
+ MULTITEAM_CENTER(ONS_NOTSHIELDED, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^BGThe ^TCenemy^BG generator is no longer shielded!"), "", NAME)
MSG_CENTER_NOTIF(ONS_NOTSHIELDED_TEAM, N_ENABLE, 0, 0, "", CPID_ONSLAUGHT, "0 0", _("^K1Your generator is NOT shielded!\n^BGRe-capture control points to shield it!"), "")
MSG_CENTER_NOTIF(ONS_TELEPORT, N_ENABLE, 0, 0, "pass_key", CPID_ONSLAUGHT, "0 0", _("^BGPress ^F2%s^BG to teleport"), "")
MSG_CENTER_NOTIF(ONS_TELEPORT_ANTISPAM, N_ENABLE, 0, 1, "f1secs", CPID_ONSLAUGHT, "0 0", _("^BGTeleporting disabled for %s"), "")
MSG_CENTER_NOTIF(SUPERWEAPON_LOST, N_ENABLE, 0, 0, "", CPID_POWERUP, "0 0", _("^F2Superweapons have been lost"), "")
MSG_CENTER_NOTIF(SUPERWEAPON_PICKUP, N_ENABLE, 0, 0, "", CPID_POWERUP, "0 0", _("^F2You now have a superweapon"), "")
- MULTITEAM_CENTER(TEAMCHANGE, 4, N_ENABLE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing to ^TC^TT^K1 in ^COUNT"), "", NAME)
+ MULTITEAM_CENTER(TEAMCHANGE, N_ENABLE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing to ^TC^TT^K1 in ^COUNT"), "", NAME)
MSG_CENTER_NOTIF(TEAMCHANGE_AUTO, N_ENABLE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Changing team in ^COUNT"), "")
MSG_CENTER_NOTIF(TEAMCHANGE_SPECTATE, N_ENABLE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Spectating in ^COUNT"), "")
MSG_CENTER_NOTIF(TEAMCHANGE_SUICIDE, N_ENABLE, 0, 1, "", CPID_TEAMCHANGE, "1 f1", _("^K1Suicide in ^COUNT"), "")
#define N_DISABL 0
#define N_ENABLE 1
-#define MULTITEAM_MULTI2(prefix, default, anncepre, infopre, centerpre) \
- MSG_MULTI_NOTIF(prefix##_RED, default, anncepre##_RED, infopre##_RED, centerpre##_RED) \
- MSG_MULTI_NOTIF(prefix##_BLUE, default, anncepre##_BLUE, infopre##_BLUE, centerpre##_BLUE)
-#define MULTITEAM_MULTI3(prefix, default, anncepre, infopre, centerpre) \
- MULTITEAM_MULTI2(prefix, default, anncepre, infopre, centerpre) \
- MSG_MULTI_NOTIF(prefix##_YELLOW, default, anncepre##YELLOW, infopre##YELLOW, centerpre##YELLOW)
-#define MULTITEAM_MULTI4(prefix, default, anncepre, infopre, centerpre) \
- MULTITEAM_MULTI3(prefix, default, anncepre, infopre, centerpre) \
- MSG_MULTI_NOTIF(prefix##_PINK, default, anncepre##PINK, infopre##PINK, centerpre##PINK)
-#define MULTITEAM_MULTI(prefix, teams, default, anncepre, infopre, centerpre) \
- MULTITEAM_MULTI##teams(prefix, default, anncepre, infopre, centerpre)
+#define MULTITEAM_MULTI(prefix, defaultvalue, anncepre, infopre, centerpre) \
+ MSG_MULTI_NOTIF(prefix##_RED, defaultvalue, anncepre##_RED, infopre##_RED, centerpre##_RED) \
+ MSG_MULTI_NOTIF(prefix##_BLUE, defaultvalue, anncepre##_BLUE, infopre##_BLUE, centerpre##_BLUE) \
+ MSG_MULTI_NOTIF(prefix##_YELLOW, defaultvalue, anncepre##YELLOW, infopre##YELLOW, centerpre##YELLOW) \
+ MSG_MULTI_NOTIF(prefix##_PINK, defaultvalue, anncepre##PINK, infopre##PINK, centerpre##PINK)
// MSG_MULTI_NOTIFICATIONS
MSG_MULTI_NOTIF(DEATH_MURDER_BUFF, N_ENABLE, NULL, INFO_DEATH_MURDER_BUFF, NULL)
MSG_MULTI_NOTIF(WEAPON_VAPORIZER_MURDER, N_ENABLE, NULL, INFO_WEAPON_VAPORIZER_MURDER, NULL)
MSG_MULTI_NOTIF(WEAPON_VORTEX_MURDER, N_ENABLE, NULL, INFO_WEAPON_VORTEX_MURDER, NULL)
-#define MULTITEAM_CHOICE2(prefix, default, challow, chtype, optiona, optionb) \
- MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, default, challow, chtype, optiona##_RED, optionb##_RED) \
- MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, default, challow, chtype, optiona##_BLUE, optionb##_BLUE)
-#define MULTITEAM_CHOICE3(prefix, default, challow, chtype, optiona, optionb) \
- MULTITEAM_CHOICE2(prefix, default, challow, chtype, optiona, optionb) \
- MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, default, challow, chtype, optiona##_YELLOW, optionb##_YELLOW)
-#define MULTITEAM_CHOICE4(prefix, default, challow, chtype, optiona, optionb) \
- MULTITEAM_CHOICE3(prefix, default, challow, chtype, optiona, optionb) \
- MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, default, challow, chtype, optiona##_PINK, optionb##_PINK)
-#define MULTITEAM_CHOICE(prefix, teams, default, challow, chtype, optiona, optionb) \
- NOTIF_ADD_AUTOCVAR(CHOICE_##prefix, default) \
+#define MULTITEAM_CHOICE(prefix, defaultvalue, challow, chtype, optiona, optionb) \
+ NOTIF_ADD_AUTOCVAR(CHOICE_##prefix, defaultvalue) \
NOTIF_ADD_AUTOCVAR(CHOICE_##prefix##_ALLOWED, challow) \
- MULTITEAM_CHOICE##teams(prefix, default, challow, chtype, optiona, optionb)
+ MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_1, prefix##_RED, prefix, defaultvalue, challow, chtype, optiona##_RED, optionb##_RED) \
+ MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_2, prefix##_BLUE, prefix, defaultvalue, challow, chtype, optiona##_BLUE, optionb##_BLUE) \
+ MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_3, prefix##_YELLOW, prefix, defaultvalue, challow, chtype, optiona##_YELLOW, optionb##_YELLOW) \
+ MSG_CHOICE_NOTIF_TEAM(NUM_TEAM_4, prefix##_PINK, prefix, defaultvalue, challow, chtype, optiona##_PINK, optionb##_PINK)
#undef N_DISABL
#undef N_ENABLE
#define A_ALWAYS 2
// MSG_CHOICE_NOTIFICATIONS
- MULTITEAM_CHOICE(CTF_CAPTURE_BROKEN, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_BROKEN)
- MULTITEAM_CHOICE(CTF_CAPTURE_TIME, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_TIME)
- MULTITEAM_CHOICE(CTF_CAPTURE_UNBROKEN, 4, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_UNBROKEN)
- MULTITEAM_CHOICE(CTF_PICKUP_TEAM, 4, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_TEAM, CENTER_CTF_PICKUP_TEAM_VERBOSE)
+ MULTITEAM_CHOICE(CTF_CAPTURE_BROKEN, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_BROKEN)
+ MULTITEAM_CHOICE(CTF_CAPTURE_TIME, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_TIME)
+ MULTITEAM_CHOICE(CTF_CAPTURE_UNBROKEN, N_VERBOSE, A_ALWAYS, MSG_INFO, INFO_CTF_CAPTURE, INFO_CTF_CAPTURE_UNBROKEN)
+ MULTITEAM_CHOICE(CTF_PICKUP_TEAM, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_TEAM, CENTER_CTF_PICKUP_TEAM_VERBOSE)
MSG_CHOICE_NOTIF(CTF_PICKUP_TEAM_NEUTRAL, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_TEAM_NEUTRAL, CENTER_CTF_PICKUP_TEAM_VERBOSE_NEUTRAL)
MSG_CHOICE_NOTIF(CTF_PICKUP_ENEMY, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY, CENTER_CTF_PICKUP_ENEMY_VERBOSE)
MSG_CHOICE_NOTIF(CTF_PICKUP_ENEMY_NEUTRAL, N__NORMAL, A_ALWAYS, MSG_CENTER, CENTER_CTF_PICKUP_ENEMY_NEUTRAL, CENTER_CTF_PICKUP_ENEMY_NEUTRAL_VERBOSE)
// MAKE SURE THIS IS ALWAYS SYNCHRONIZED WITH THE DUMP
// NOTIFICATIONS FUNCTION IN THE .QC FILE!
-#define NOTIF_ADD_AUTOCVAR(name,default) float autocvar_notification_##name = default;
+#define NOTIF_ADD_AUTOCVAR(name,defaultvalue) float autocvar_notification_##name = defaultvalue;
float autocvar_notification_show_location = false;
string autocvar_notification_show_location_string = ""; //_(" at the %s");
return it;
}
-#define MSG_ANNCE_NOTIF_TEAM(teamnum, name, cvarname, default, sound, channel, volume, position) \
- MSG_ANNCE_NOTIF_(teamnum, ANNCE_##name, ANNCE_##cvarname, default, sound, channel, volume, position)
+#define MSG_ANNCE_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position) \
+ MSG_ANNCE_NOTIF_(teamnum, ANNCE_##name, ANNCE_##cvarname, defaultvalue, sound, channel, volume, position)
-#define MSG_ANNCE_NOTIF(name, default, sound, channel, volume, position) \
- NOTIF_ADD_AUTOCVAR(ANNCE_##name, default) \
- MSG_ANNCE_NOTIF_(0, ANNCE_##name, ANNCE_##name, default, sound, channel, volume, position)
+#define MSG_ANNCE_NOTIF(name, defaultvalue, sound, channel, volume, position) \
+ NOTIF_ADD_AUTOCVAR(ANNCE_##name, defaultvalue) \
+ MSG_ANNCE_NOTIF_(0, ANNCE_##name, ANNCE_##name, defaultvalue, sound, channel, volume, position)
-#define MSG_ANNCE_NOTIF_(teamnum, name, cvarname, default, sound, channel, volume, position) \
+#define MSG_ANNCE_NOTIF_(teamnum, name, cvarname, defaultvalue, sound, channel, volume, position) \
REGISTER(Notifications, name, m_id, new_pure(msg_annce_notification)) { \
- Create_Notification_Entity (this, default, ACVNN(cvarname), MSG_ANNCE, strtoupper(#name), teamnum); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(cvarname), MSG_ANNCE, strtoupper(#name), teamnum); \
Create_Notification_Entity_Annce(this, ACVNN(cvarname), strtoupper(#name), \
channel, /* channel */ \
sound, /* snd */ \
position); /* position */ \
}
-#define MSG_INFO_NOTIF_TEAM(teamnum, name, cvarname, default, strnum, flnum, args, hudargs, icon, normal, gentle) \
- MSG_INFO_NOTIF_(teamnum, INFO_##name, INFO_##cvarname, default, strnum, flnum, args, hudargs, icon, normal, gentle)
+#define MSG_INFO_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle) \
+ MSG_INFO_NOTIF_(teamnum, INFO_##name, INFO_##cvarname, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle)
-#define MSG_INFO_NOTIF(name, default, strnum, flnum, args, hudargs, icon, normal, gentle) \
- NOTIF_ADD_AUTOCVAR(INFO_##name, default) \
- MSG_INFO_NOTIF_(0, INFO_##name, INFO_##name, default, strnum, flnum, args, hudargs, icon, normal, gentle)
+#define MSG_INFO_NOTIF(name, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle) \
+ NOTIF_ADD_AUTOCVAR(INFO_##name, defaultvalue) \
+ MSG_INFO_NOTIF_(0, INFO_##name, INFO_##name, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle)
-#define MSG_INFO_NOTIF_(teamnum, name, cvarname, default, strnum, flnum, args, hudargs, icon, normal, gentle) \
+#define MSG_INFO_NOTIF_(teamnum, name, cvarname, defaultvalue, strnum, flnum, args, hudargs, icon, normal, gentle) \
REGISTER(Notifications, name, m_id, new_pure(msg_info_notification)) { \
- Create_Notification_Entity (this, default, ACVNN(cvarname), MSG_INFO, strtoupper(#name), teamnum); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(cvarname), MSG_INFO, strtoupper(#name), teamnum); \
Create_Notification_Entity_InfoCenter(this, ACVNN(cvarname), strtoupper(#name), strnum, flnum, \
args, /* args */ \
hudargs, /* hudargs */ \
}
.string nent_iconargs;
-#define MULTIICON_INFO(name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
- MULTIICON_INFO_(INFO_##name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle)
-#define MULTIICON_INFO_(name, default, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
- NOTIF_ADD_AUTOCVAR(name, default) \
+#define MULTIICON_INFO(name, defaultvalue, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
+ MULTIICON_INFO_(INFO_##name, defaultvalue, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle)
+#define MULTIICON_INFO_(name, defaultvalue, strnum, flnum, args, hudargs, iconargs, icon, normal, gentle) \
+ NOTIF_ADD_AUTOCVAR(name, defaultvalue) \
REGISTER(Notifications, name, m_id, new_pure(msg_info_notification)) { \
- Create_Notification_Entity (this, default, ACVNN(name), MSG_INFO, strtoupper(#name), 0); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(name), MSG_INFO, strtoupper(#name), 0); \
Create_Notification_Entity_InfoCenter(this, ACVNN(name), strtoupper(#name), strnum, flnum, \
args, /* args */ \
hudargs, /* hudargs */ \
this.nent_iconargs = iconargs; \
}
-#define MSG_CENTER_NOTIF_TEAM(teamnum, name, cvarname, default, strnum, flnum, args, cpid, durcnt, normal, gentle) \
- MSG_CENTER_NOTIF_(teamnum, CENTER_##name, CENTER_##cvarname, default, strnum, flnum, args, cpid, durcnt, normal, gentle)
+#define MSG_CENTER_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle) \
+ MSG_CENTER_NOTIF_(teamnum, CENTER_##name, CENTER_##cvarname, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle)
-#define MSG_CENTER_NOTIF(name, default, strnum, flnum, args, cpid, durcnt, normal, gentle) \
- NOTIF_ADD_AUTOCVAR(CENTER_##name, default) \
- MSG_CENTER_NOTIF_(0, CENTER_##name, CENTER_##name, default, strnum, flnum, args, cpid, durcnt, normal, gentle)
+#define MSG_CENTER_NOTIF(name, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle) \
+ NOTIF_ADD_AUTOCVAR(CENTER_##name, defaultvalue) \
+ MSG_CENTER_NOTIF_(0, CENTER_##name, CENTER_##name, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle)
-#define MSG_CENTER_NOTIF_(teamnum, name, cvarname, default, strnum, flnum, args, cpid, durcnt, normal, gentle) \
+#define MSG_CENTER_NOTIF_(teamnum, name, cvarname, defaultvalue, strnum, flnum, args, cpid, durcnt, normal, gentle) \
REGISTER(Notifications, name, m_id, new_pure(msg_center_notification)) { \
- Create_Notification_Entity (this, default, ACVNN(cvarname), MSG_CENTER, strtoupper(#name), teamnum); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(cvarname), MSG_CENTER, strtoupper(#name), teamnum); \
Create_Notification_Entity_InfoCenter(this, ACVNN(cvarname), strtoupper(#name), strnum, flnum, \
args, /* args */ \
"", /* hudargs */ \
gentle); /* gentle */ \
}
-#define MSG_MULTI_NOTIF(name, default, anncename, infoname, centername) \
- NOTIF_ADD_AUTOCVAR(name, default) \
+#define MSG_MULTI_NOTIF(name, defaultvalue, anncename, infoname, centername) \
+ NOTIF_ADD_AUTOCVAR(name, defaultvalue) \
REGISTER(Notifications, name, m_id, new_pure(msg_multi_notification)) { \
- Create_Notification_Entity (this, default, ACVNN(name), MSG_MULTI, strtoupper(#name), 0); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(name), MSG_MULTI, strtoupper(#name), 0); \
Create_Notification_Entity_Multi(this, ACVNN(name), strtoupper(#name), \
anncename, /* anncename */ \
infoname, /* infoname */ \
centername); /* centername */ \
}
-#define MSG_CHOICE_NOTIF_TEAM(teamnum, name, cvarname, default, challow, chtype, optiona, optionb) \
- MSG_CHOICE_NOTIF_(teamnum, CHOICE_##name, CHOICE_##cvarname, default, challow, chtype, optiona, optionb)
+#define MSG_CHOICE_NOTIF_TEAM(teamnum, name, cvarname, defaultvalue, challow, chtype, optiona, optionb) \
+ MSG_CHOICE_NOTIF_(teamnum, CHOICE_##name, CHOICE_##cvarname, defaultvalue, challow, chtype, optiona, optionb)
-#define MSG_CHOICE_NOTIF(name, default, challow, chtype, optiona, optionb) \
- NOTIF_ADD_AUTOCVAR(CHOICE_##name, default) \
+#define MSG_CHOICE_NOTIF(name, defaultvalue, challow, chtype, optiona, optionb) \
+ NOTIF_ADD_AUTOCVAR(CHOICE_##name, defaultvalue) \
NOTIF_ADD_AUTOCVAR(CHOICE_##name##_ALLOWED, challow) \
- MSG_CHOICE_NOTIF_(0, CHOICE_##name, CHOICE_##name, default, challow, chtype, optiona, optionb)
+ MSG_CHOICE_NOTIF_(0, CHOICE_##name, CHOICE_##name, defaultvalue, challow, chtype, optiona, optionb)
-#define MSG_CHOICE_NOTIF_(teamnum, name, cvarname, default, challow, chtype, optiona, optionb) \
+#define MSG_CHOICE_NOTIF_(teamnum, name, cvarname, defaultvalue, challow, chtype, optiona, optionb) \
REGISTER(Notifications, name, m_id, new_pure(msg_choice_notification)) { \
this.nent_choice_idx = nent_choice_count; \
if (!teamnum || teamnum == NUM_TEAM_4) \
nent_choice_count++; \
- Create_Notification_Entity (this, default, ACVNN(cvarname), MSG_CHOICE, strtoupper(#name), teamnum); \
+ Create_Notification_Entity (this, defaultvalue, ACVNN(cvarname), MSG_CHOICE, strtoupper(#name), teamnum); \
Create_Notification_Entity_Choice(this, ACVNN(cvarname), strtoupper(#name), \
challow, /* challow_def */ \
autocvar_notification_##cvarname##_ALLOWED, /* challow_var */ \
LOG_SEVERE("Notification initialization failed! Read above and fix the errors!");
}
+#ifdef CSQC
+.int cvar_value;
+void ReplicateVars(bool would_destroy)
+{
+ if (!would_destroy)
+ FOREACH(Notifications, it.nent_type == MSG_CHOICE, {
+ string cvarname = sprintf("notification_%s", Get_Notif_CvarName(it));
+ // NOTE: REPLICATE_SIMPLE can return;
+ REPLICATE_SIMPLE(it.cvar_value, cvarname);
+ });
+}
+#endif
+
#include "all.inc"
trace_plane_normal = '0 0 1';
trace_plane_dist = 0;
trace_ent = this;
+ trace_dpstartcontents = 0;
+ trace_dphitcontents = 0;
+ trace_dphitq3surfaceflags = 0;
+ trace_dphittexturename = string_null;
gettouch(it)(it, this);
}
{
_Movetype_PushEntityTrace(this, push);
+ // NOTE: this is a workaround for the QC's lack of a worldstartsolid trace parameter
if(trace_startsolid && failonstartsolid)
{
int oldtype = this.move_nomonsters;
- this.move_nomonsters = MOVE_NOMONSTERS;
+ this.move_nomonsters = MOVE_WORLDONLY;
_Movetype_PushEntityTrace(this, push);
this.move_nomonsters = oldtype;
if(trace_startsolid)
_Movetype_LinkEdict(this, true);
if(trace_fraction < 1)
- if(this.solid >= SOLID_TRIGGER && (!IS_ONGROUND(this) || (this.groundentity != trace_ent)))
+ if(this.solid >= SOLID_TRIGGER && trace_ent && (!IS_ONGROUND(this) || (this.groundentity != trace_ent)))
_Movetype_Impact(this, trace_ent);
return (this.origin == last_origin); // false if teleported by touch
if(latency)
PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
}
+
+ db_put(PS_GR_OUT_DB, sprintf("%s:_ranked", p.playerstats_id), ftos(CS(p).cvar_cl_allow_uidranking));
}
strfree(p.playerstats_id);
url_fputs(fh, sprintf("t %s\n", tt));
}
+ // elo ranking enabled
+ nn = db_get(PS_GR_OUT_DB, sprintf("%s:_ranked", p));
+ if(nn != "") { url_fputs(fh, sprintf("r %s\n", nn)); }
+
// output player events
for(e = PS_GR_OUT_EVL; (en = db_get(PS_GR_OUT_DB, sprintf("*:%s", e))) != ""; e = en)
{
SOUND(ONS_CONTROLPOINT_UNDERATTACK, "onslaught/controlpoint_underattack");
SOUND(ONS_DAMAGEBLOCKEDBYSHIELD, "onslaught/damageblockedbyshield");
SOUND(ONS_ELECTRICITY_EXPLODE, "onslaught/electricity_explode");
+SOUND(ONS_GENERATOR_ALARM, "kh/alarm"); // FIXME: unique sound
SOUND(ONS_GENERATOR_DECAY, "onslaught/generator_decay");
SOUND(ONS_GENERATOR_UNDERATTACK, "onslaught/generator_underattack");
SOUND(ONS_HIT1, "onslaught/ons_hit1");
SOUND(VEH_SPIDERBOT_WALK, "vehicles/spiderbot_walk");
SOUND(NADE_BEEP, "overkill/grenadebip");
+SOUND(NADE_BONUS, "kh/alarm"); // FIXME: unique sound
SOUND(BUFF_LOST, "relics/relic_effect");
const float ATTEN_NONE = 0;
const float ATTEN_MIN = 0.015625;
+const float ATTEN_LOW = 0.2;
const float ATTEN_NORM = 0.5;
const float ATTEN_LARGE = 1;
const float ATTEN_IDLE = 2;
TC(Sound, this);
string s = _Sound_fixpath(this.sound_str());
if (!s) return;
- profile(sprintf("precache_sound(\"%s\")", s));
+ //profile(sprintf("precache_sound(\"%s\")", s));
precache_sound(s);
strcpy(this.sound_str_, s);
}
void PlayerState_attach(entity this)
{
+ if (PS(this))
+ return;
+
this._ps = NEW(PlayerState, this);
Inventory_new(PS(this));
{
this._cs = NEW(ClientState, this);
- GetCvars(this, CS(this), 0); // get other cvars from player
-
// TODO: fold all of these into ClientState
DecodeLevelParms(this);
#endif
#ifdef SVQC
+/// all the weapons actually spawned in the map, does not include filtered items
vector weaponsInMap;
+/// all the weapons placed by the mapper (weaponreplace applied), ignores most filters
+vector weaponsInMapAll;
#endif
+
REGISTER_STAT(WEAPONS, vectori)
REGISTER_STAT(WEAPONSINMAP, vectori, weaponsInMap)
#endif
#ifdef SVQC
.int cvar_cl_gunalign;
-REPLICATE(cvar_cl_gunalign, int, "cl_gunalign");
#endif
+
REGISTER_STAT(GUNALIGN, int)
#ifdef SVQC
SPECTATE_COPYFIELD(_STAT(GUNALIGN))
{
WriteShort(MSG_ENTITY, this.colormap);
WriteByte(MSG_ENTITY, this.glowmod.x * 255.0);
- WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
- WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
+ WriteByte(MSG_ENTITY, this.glowmod.y * 255.0);
+ WriteByte(MSG_ENTITY, this.glowmod.z * 255.0);
}
if(sf & ISF_DROP)
return true;
}
-void Item_Show (entity e, int mode)
+void Item_Show(entity e, int mode)
{
e.effects &= ~(EF_ADDITIVE | EF_STARDUST | EF_FULLBRIGHT | EF_NODEPTHTEST);
e.ItemStatus &= ~ITS_STAYWEP;
void Item_ItemsTime_SetTime(entity e, float t);
void Item_ItemsTime_SetTimesForAllPlayers();
-void Item_Respawn (entity this)
+void Item_Respawn(entity this)
{
Item_Show(this, 1);
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) || (STAT(WEAPONS, this) & 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);
Send_Effect(EFFECT_ITEM_RESPAWN, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
}
-void Item_RespawnCountdown (entity this)
+void Item_RespawnCountdown(entity this)
{
if(this.item_respawncounter >= ITEM_RESPAWN_TICKS)
{
}
}
TeamBalance_Destroy(balance);
-
+
if (players >= 2) {
return normal_respawntime * (r / (players + o) + l);
} else {
LABEL(pickup)
+ if(this.target && this.target != "" && this.target != "###item###") // defrag support
+ SUB_UseTargets(this, toucher, NULL);
+
STAT(LAST_PICKUP, toucher) = time;
Send_Effect(EFFECT_ITEM_PICKUP, CENTER_OR_VIEWOFS(this), '0 0 0', 1);
});
e = RandomSelection_chosen_ent;
- e.state = 0;
- Item_Show(e, 1);
+ if (!e)
+ return;
IL_EACH(g_items, it.team == this.team,
{
Item_Show(it, -1);
it.state = 1; // state 1 = initially hidden item, apparently
}
+ else
+ Item_Reset(it);
it.effects &= ~EF_NODRAW;
}
});
-
- Item_Reset(this);
}
}
{
string itemname = def.m_name;
Model itemmodel = def.m_model;
- Sound pickupsound = def.m_sound;
+ Sound pickupsound = def.m_sound;
float(entity player, entity item) pickupevalfunc = def.m_pickupevalfunc;
float pickupbasevalue = def.m_botvalue;
int itemflags = def.m_itemflags;
startitem_failed = false;
this.item_model_ent = itemmodel;
- this.item_pickupsound_ent = pickupsound;
+ this.item_pickupsound_ent = pickupsound;
- if(def.m_iteminit)
- def.m_iteminit(def, this);
+ if(def.m_iteminit)
+ def.m_iteminit(def, this);
if(!this.respawntime) // both need to be set
{
|| (def.instanceOfHealth && def != ITEM_HealthSmall)
|| (def.instanceOfArmor && def != ITEM_ArmorSmall)
|| (itemid & (IT_KEY1 | IT_KEY2))
- ) this.target = "###item###"; // for finding the nearest item using findnearest
+ )
+ {
+ if(!this.target || this.target == "")
+ this.target = "###item###"; // for finding the nearest item using findnearest
+ }
Item_ItemsTime_SetTime(this, 0);
}
}
this.state = 0;
- if(this.team) // broken, no idea why.
+ if(this.team)
{
if(!this.cnt)
this.cnt = 1; // item probability weight
FOREACH(Buffs, it != BUFF_Null,
{
s = Buff_UndeprecateName(argv(j));
- if(s == it.m_name)
+ if(s == it.netname)
{
STAT(BUFFS, this) |= (it.m_itemid);
+ if(!STAT(BUFF_TIME, this))
+ STAT(BUFF_TIME, this) = it.m_time(it);
break;
}
});
if(GetResource(this, RES_FUEL) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_FUEL)), "fuel");
if(GetResource(this, RES_HEALTH) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_HEALTH)), "health");
if(GetResource(this, RES_ARMOR) != 0) this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, GetResource(this, RES_ARMOR)), "armor");
- FOREACH(Buffs, it != BUFF_Null, this.netname = sprintf("%s %s%d %s", this.netname, itemprefix, !!(STAT(BUFFS, this) & (it.m_itemid)), it.m_name));
+ FOREACH(Buffs, it != BUFF_Null && (STAT(BUFFS, this) & it.m_itemid), this.netname = sprintf("%s %s%d %s", this.netname, valueprefix, max(0, STAT(BUFF_TIME, this)), 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);
for(int j = 0; j < n; ++j)
{
FOREACH(Weapons, it != WEP_Null && W_UndeprecateName(argv(j)) == it.netname, {
- it.wr_init(it);
- break;
+ it.wr_init(it);
+ break;
});
}
}
bool GiveBuff(entity e, Buff thebuff, int op, int val)
{
bool had_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
- switch(op)
+ switch (op)
{
case OP_SET:
- if(val > 0)
- STAT(BUFFS, e) |= thebuff.m_itemid;
- else
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = val;
break;
case OP_MIN:
- case OP_PLUS:
- if(val > 0)
- STAT(BUFFS, e) |= thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = max(STAT(BUFF_TIME, e), val);
break;
case OP_MAX:
- if(val <= 0)
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) = min(STAT(BUFF_TIME, e), val);
+ break;
+ case OP_PLUS:
+ STAT(BUFF_TIME, e) += val;
break;
case OP_MINUS:
- if(val > 0)
- STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ STAT(BUFF_TIME, e) -= val;
break;
}
+ if(STAT(BUFF_TIME, e) <= 0)
+ STAT(BUFFS, e) &= ~thebuff.m_itemid;
+ else
+ STAT(BUFFS, e) = thebuff.m_itemid; // NOTE: replaces any existing buffs on the player!
bool have_buff = (STAT(BUFFS, e) & thebuff.m_itemid);
return (had_buff != have_buff);
}
e.strength_finished = max(0, e.strength_finished - time);
e.invincible_finished = max(0, e.invincible_finished - time);
e.superweapons_finished = max(0, e.superweapons_finished - time);
+ STAT(BUFF_TIME, e) = max(0, STAT(BUFF_TIME, e) - time);
PREGIVE(e, items);
PREGIVE_WEAPONS(e);
got += GiveResourceValue(e, RES_HEALTH, op, val);
got += GiveResourceValue(e, RES_ARMOR, op, val);
case "allweapons":
- FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & WEP_FLAG_MUTATORBLOCKED), got += GiveWeapon(e, it.m_id, op, val));
+ FOREACH(Weapons, it != WEP_Null && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)), got += GiveWeapon(e, it.m_id, op, val));
//case "allbuffs": // all buffs makes a player god, do not want!
//FOREACH(Buffs, it != BUFF_Null, got += GiveBuff(e, it.m_itemid, op, val));
case "allammo":
got += GiveResourceValue(e, RES_FUEL, op, val);
break;
default:
- FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.m_name,
+ FOREACH(Buffs, it != BUFF_Null && Buff_UndeprecateName(cmd) == it.netname,
{
got += GiveBuff(e, it, op, val);
break;
POSTGIVE_RES_ROT(e, RES_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(!g_weaponarena && STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS)
+ if(!g_weaponarena && (STAT(WEAPONS, e) & WEPSET_SUPERWEAPONS))
e.superweapons_finished = autocvar_g_balance_superweapons_time;
if(e.strength_finished <= 0)
e.superweapons_finished = 0;
else
e.superweapons_finished += time;
+ if(STAT(BUFF_TIME, e) <= 0)
+ STAT(BUFF_TIME, e) = 0;
+ else
+ STAT(BUFF_TIME, e) += time;
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
#ifdef SVQC
-/**
- turret_checkpoint
-**/
-
-
-//.entity checkpoint_target;
-
-/*
-#define checkpoint_cache_who flagcarried
-#define checkpoint_cache_from lastrocket
-#define checkpoint_cache_to selected_player
-*/
-
-/*
-entity path_makeorcache(entity forwho,entity start, entity end)
-{
- entity pth;
-
- //pth = pathlib_makepath(forwho, start.origin,end.origin,PFL_GROUNDSNAP,500,1.5,PT_QUICKSTAR);
-
- return pth;
-}
-*/
-
-void turret_checkpoint_use()
-{
-}
-
-#if 0
-void turret_checkpoint_think(entity this)
-{
- if(this.enemy)
- te_lightning1(this,this.origin, this.enemy.origin);
-
- this.nextthink = time + 0.25;
-}
-#endif
/*QUAKED turret_checkpoint (1 0 1) (-32 -32 -32) (32 32 32)
-----------KEYS------------
target: .targetname of next waypoint in chain.
-----------SPAWNFLAGS-----------
---------NOTES----------
If a loop is of targets are formed, any unit entering this loop will patrol it indefinitly.
-If the checkpoint chain in not looped, the unit will go "Roaming" when the last point is reached.
+If the checkpoint chain is not looped, the unit will go "Roaming" when the last point is reached.
*/
-//float tc_acum;
void turret_checkpoint_init(entity this)
{
traceline(this.origin + '0 0 16', this.origin - '0 0 1024', MOVE_WORLDONLY, this);
setorigin(this, trace_endpos + '0 0 32');
- if(this.target != "")
+ if(this.target && this.target != "")
{
this.enemy = find(NULL, targetname, this.target);
- if(this.enemy == NULL)
- LOG_TRACE("A turret_checkpoint faild to find its target!");
+ if(!this.enemy)
+ LOG_TRACE("A turret_checkpoint failed to find its target!");
}
- //setthink(this, turret_checkpoint_think);
- //this.nextthink = time + tc_acum + 0.25;
- //tc_acum += 0.25;
}
spawnfunc(turret_checkpoint)
{
setorigin(this, this.origin);
- setthink(this, turret_checkpoint_init);
- this.nextthink = time + 0.2;
+ InitializeEntity(this, turret_checkpoint_init, INITPRIO_FINDTARGET);
}
// Compat.
t = t * (1 - (1 - waypointsprite_crosshairfadescale) * (1 - bound(0, crosshairdistance/waypointsprite_crosshairfadedistance, 1)));
}
- o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
- if(autocvar_g_waypointsprite_turrets_text)
+ bool draw_healthbar = ((this.helpme && time < this.helpme) || !autocvar_g_waypointsprite_turrets_onlyhurt || hud != HUD_NORMAL);
+ bool draw_text = autocvar_g_waypointsprite_turrets_text;
+
+ if(draw_healthbar || draw_text) // make sure it's actually being drawn
+ {
+ o = drawspritearrow(o, M_PI, rgb, a, SPRITE_ARROW_SCALE * t);
+ }
+ if(draw_text)
{
o = drawsprite_TextOrIcon(true, o, M_PI, (SPRITE_HEALTHBAR_WIDTH + 2 * SPRITE_HEALTHBAR_BORDER) * t, rgb, a, waypointsprite_fontsize * '1 1 0', txt);
}
- drawhealthbar(
- o,
- 0,
- GetResource(this, RES_HEALTH) / 255,
- '0 0 0',
- '0 0 0',
- 0.5 * SPRITE_HEALTHBAR_WIDTH * t,
- 0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
- SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
- SPRITE_HEALTHBAR_BORDER * t,
- 0,
- rgb,
- a * SPRITE_HEALTHBAR_BORDERALPHA,
- rgb,
- a * SPRITE_HEALTHBAR_HEALTHALPHA,
- DRAWFLAG_NORMAL
- );
+ if(draw_healthbar)
+ {
+ drawhealthbar(
+ o,
+ 0,
+ GetResource(this, RES_HEALTH) / 255,
+ '0 0 0',
+ '0 0 0',
+ 0.5 * SPRITE_HEALTHBAR_WIDTH * t,
+ 0.5 * SPRITE_HEALTHBAR_HEIGHT * t,
+ SPRITE_HEALTHBAR_MARGIN * t + 0.5 * waypointsprite_fontsize,
+ SPRITE_HEALTHBAR_BORDER * t,
+ 0,
+ rgb,
+ a * SPRITE_HEALTHBAR_BORDERALPHA,
+ rgb,
+ a * SPRITE_HEALTHBAR_HEALTHALPHA,
+ DRAWFLAG_NORMAL
+ );
+ }
}
void turret_construct(entity this, bool isnew)
tvt_thadv = angleofs3(e_turret.tur_head.origin, e_turret.angles + e_turret.tur_head.angles, e_target.origin);
tvt_tadv = shortangle_vxy(angleofs(e_turret, e_target), e_turret.angles);
tvt_thadf = vlen(tvt_thadv);
- tvt_tadf = vlen(tvt_tadv);
/*
if(validate_flags & TFL_TARGETSELECT_FOV)
vector tvt_thadv; // turret head angle diff vector, updated by a successful call to turret_validate_target
vector tvt_tadv; // turret angle diff vector, updated by a successful call to turret_validate_target
float tvt_thadf; // turret head angle diff float, updated by a successful call to turret_validate_target
-float tvt_tadf; // turret angle diff float, updated by a successful call to turret_validate_target
float tvt_dist; // turret distance, updated by a successful call to turret_validate_target
#pragma once
CLASS(EWheelAttack, PortoLaunch)
-/* flags */ ATTRIB(EWheelAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(EWheelAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(EWheelAttack, impulse, int, 5);
/* refname */ ATTRIB(EWheelAttack, netname, string, "turret_ewheel");
/* wepname */ ATTRIB(EWheelAttack, m_name, string, _("eWheel"));
#pragma once
-// TODO: WEP_TYPE_OTHER?
-
CLASS(FlacAttack, PortoLaunch)
-/* flags */ ATTRIB(FlacAttack, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(FlacAttack, spawnflags, int, WEP_FLAG_SPECIALATTACK | WEP_FLAG_HIDDEN);
/* impulse */ ATTRIB(FlacAttack, impulse, int, 5);
/* refname */ ATTRIB(FlacAttack, netname, string, "turret_flac");
/* wepname */ ATTRIB(FlacAttack, m_name, string, _("FLAC"));
#pragma once
CLASS(HellionAttack, PortoLaunch)
-/* flags */ ATTRIB(HellionAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(HellionAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(HellionAttack, impulse, int, 9);
/* refname */ ATTRIB(HellionAttack, netname, string, "turret_hellion");
/* wepname */ ATTRIB(HellionAttack, m_name, string, _("Hellion"));
#pragma once
CLASS(HunterKillerAttack, PortoLaunch)
-/* flags */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(HunterKillerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(HunterKillerAttack, impulse, int, 9);
/* refname */ ATTRIB(HunterKillerAttack, netname, string, "turret_hk");
/* wepname */ ATTRIB(HunterKillerAttack, m_name, string, _("Hunter-Killer"));
#pragma once
CLASS(MachineGunTurretAttack, PortoLaunch)
-/* flags */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(MachineGunTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(MachineGunTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(MachineGunTurretAttack, netname, string, "turret_machinegun");
/* wepname */ ATTRIB(MachineGunTurretAttack, m_name, string, _("Machinegun"));
#pragma once
CLASS(MLRSTurretAttack, PortoLaunch)
-/* flags */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(MLRSTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(MLRSTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(MLRSTurretAttack, netname, string, "turret_mlrs");
/* wepname */ ATTRIB(MLRSTurretAttack, m_name, string, _("MLRS"));
#pragma once
CLASS(PhaserTurretAttack, PortoLaunch)
-/* flags */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(PhaserTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(PhaserTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(PhaserTurretAttack, netname, string, "turret_phaser");
/* wepname */ ATTRIB(PhaserTurretAttack, m_name, string, _("Phaser"));
#include "plasma_weapon.qh"
CLASS(PlasmaDualAttack, PlasmaAttack)
-/* flags */ ATTRIB(PlasmaDualAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(PlasmaDualAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* refname */ ATTRIB(PlasmaDualAttack, netname, string, "turret_plasma_dual");
/* wepname */ ATTRIB(PlasmaDualAttack, m_name, string, _("Dual plasma"));
ENDCLASS(PlasmaDualAttack)
#pragma once
CLASS(PlasmaAttack, PortoLaunch)
-/* flags */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(PlasmaAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(PlasmaAttack, impulse, int, 5);
/* refname */ ATTRIB(PlasmaAttack, netname, string, "turret_plasma");
/* wepname */ ATTRIB(PlasmaAttack, m_name, string, _("Plasma"));
#pragma once
CLASS(TeslaCoilTurretAttack, PortoLaunch)
-/* flags */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(TeslaCoilTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(TeslaCoilTurretAttack, impulse, int, 9);
/* refname */ ATTRIB(TeslaCoilTurretAttack, netname, string, "turret_tesla");
/* wepname */ ATTRIB(TeslaCoilTurretAttack, m_name, string, _("Tesla Coil"));
#pragma once
CLASS(WalkerTurretAttack, PortoLaunch)
-/* flags */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(WalkerTurretAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(WalkerTurretAttack, impulse, int, 5);
/* refname */ ATTRIB(WalkerTurretAttack, netname, string, "turret_walker");
/* wepname */ ATTRIB(WalkerTurretAttack, m_name, string, _("Walker"));
for(w = to; w >= from; --w)
{
int wflags = Weapons_from(w).spawnflags;
- if((wflags & WEP_FLAG_HIDDEN) && (wflags & WEP_FLAG_MUTATORBLOCKED) && !(wflags & WEP_FLAG_NORMAL))
+ if(wflags & WEP_FLAG_SPECIALATTACK)
continue;
for(i = 0; i < n; ++i)
if(stof(argv(i)) == w)
#include <common/weapons/_all.qh>
CLASS(RacerAttack, PortoLaunch)
-/* flags */ ATTRIB(RacerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(RacerAttack, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(RacerAttack, impulse, int, 3);
/* refname */ ATTRIB(RacerAttack, netname, string, "racercannon");
/* wepname */ ATTRIB(RacerAttack, m_name, string, _("Racer cannon"));
#include <common/weapons/_all.qh>
CLASS(RaptorCannon, PortoLaunch)
-/* flags */ ATTRIB(RaptorCannon, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(RaptorCannon, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(RaptorCannon, impulse, int, 3);
/* refname */ ATTRIB(RaptorCannon, netname, string, "raptorcannon");
/* wepname */ ATTRIB(RaptorCannon, m_name, string, _("Raptor cannon"));
REGISTER_WEAPON(RAPTOR, NEW(RaptorCannon));
CLASS(RaptorBomb, PortoLaunch)
-/* flags */ ATTRIB(RaptorBomb, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(RaptorBomb, spawnflags, int, WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(RaptorBomb, impulse, int, 3);
/* refname */ ATTRIB(RaptorBomb, netname, string, "raptorbomb");
/* wepname */ ATTRIB(RaptorBomb, m_name, string, _("Raptor bomb"));
REGISTER_WEAPON(RAPTOR_BOMB, NEW(RaptorBomb));
CLASS(RaptorFlare, PortoLaunch)
-/* flags */ ATTRIB(RaptorFlare, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_MUTATORBLOCKED);
+/* flags */ ATTRIB(RaptorFlare, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK);
/* impulse */ ATTRIB(RaptorFlare, impulse, int, 3);
/* refname */ ATTRIB(RaptorFlare, netname, string, "raptorflare");
/* wepname */ ATTRIB(RaptorFlare, m_name, string, _("Raptor flare"));
FOREACH(Weapons, true, {
WepSet set = it.m_wepset = _WepSet_FromWeapon(it.m_id = i);
WEPSET_ALL |= set;
- if ((it.spawnflags) & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= set;
+ if (it.spawnflags & WEP_FLAG_SUPERWEAPON) WEPSET_SUPERWEAPONS |= 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 CSQC
+bool cvar_cl_accuracy_data_share;
+REPLICATE(cvar_cl_accuracy_data_share, bool, "cl_accuracy_data_share");
+bool cvar_cl_accuracy_data_receive;
+REPLICATE(cvar_cl_accuracy_data_receive, bool, "cl_accuracy_data_receive");
+#endif
+
#ifdef SVQC
void wframe_send(entity actor, entity weaponentity, vector a, bool restartanim);
#endif
int wepcount = 1;
#define WEP_CONFIG_WRITETOFILE(str) write_String_To_File(wep_config_file, str, wep_config_alsoprint)
FOREACH(Weapons, it != WEP_Null, {
- if((it.spawnflags & WEP_FLAG_HIDDEN) && (it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_NORMAL))
+ if(it.spawnflags & WEP_FLAG_SPECIALATTACK)
continue; // never include the attacks
// step 1: clear the queue
WEP_CONFIG_COUNT = 0;
const int WEP_FLAG_NODUAL = BIT(12); // weapon doesn't work well with dual wielding (fireball etc just explode on fire), doesn't currently prevent anything
const int WEP_FLAG_PENETRATEWALLS = BIT(13); // weapon has high calibur bullets that can penetrate thick walls (WEAPONTODO)
const int WEP_FLAG_BLEED = BIT(14); // weapon pierces and causes bleeding (used for damage effects)
+const int WEP_FLAG_NOTRUEAIM = BIT(15); // weapon doesn't aim directly at targets
+const int WEP_FLAG_SPECIALATTACK = BIT(16); // marked as a special attack (not a true weapon), hidden from most weapon lists
// variables:
string weaponorder_byid;
this.event_damage = func_null;
- RadiusDamage(
+ RadiusDamageForSource(
this,
+ (this.origin + (this.mins + this.maxs) * 0.5),
+ this.velocity,
this.realowner,
this.blaster_damage,
this.blaster_edgedamage,
this.blaster_radius,
NULL,
NULL,
+ false,
this.blaster_force,
+ this.blaster_force_zscale,
this.projectiledeathtype,
this.weaponentity_fld,
toucher
float atk_edgedamage,
float atk_radius,
float atk_force,
+ float atk_force_zscale,
float atk_speed,
float atk_spread,
float atk_delay,
missile.blaster_edgedamage = atk_edgedamage;
missile.blaster_radius = atk_radius;
missile.blaster_force = atk_force;
+ missile.blaster_force_zscale = atk_force_zscale;
missile.blaster_lifetime = atk_lifetime;
setorigin(missile, w_shotorg);
WEP_CVAR_PRI(blaster, edgedamage),
WEP_CVAR_PRI(blaster, radius),
WEP_CVAR_PRI(blaster, force),
+ WEP_CVAR_PRI(blaster, force_zscale),
WEP_CVAR_PRI(blaster, speed),
WEP_CVAR_PRI(blaster, spread),
WEP_CVAR_PRI(blaster, delay),
WEP_CVAR_SEC(blaster, edgedamage),
WEP_CVAR_SEC(blaster, radius),
WEP_CVAR_SEC(blaster, force),
+ WEP_CVAR_SEC(blaster, force_zscale),
WEP_CVAR_SEC(blaster, speed),
WEP_CVAR_SEC(blaster, spread),
WEP_CVAR_SEC(blaster, delay),
CLASS(OffhandBlaster, OffhandWeapon)
ENDCLASS(OffhandBlaster)
-OffhandBlaster OFFHAND_BLASTER; STATIC_INIT(OFFHAND_BLASTER) { OFFHAND_BLASTER = NEW(OffhandBlaster); }
+OffhandBlaster OFFHAND_BLASTER;
+STATIC_INIT(OFFHAND_BLASTER) { OFFHAND_BLASTER = NEW(OffhandBlaster); }
#ifdef SVQC
.float blaster_damage;
.float blaster_edgedamage;
.float blaster_radius;
.float blaster_force;
+.float blaster_force_zscale;
.float blaster_lifetime;
// Will be demacroed after WEP_CVAR macros are also demacroed.
WEP_CVAR_SEC(weapon_name, edgedamage), \
WEP_CVAR_SEC(weapon_name, radius), \
WEP_CVAR_SEC(weapon_name, force), \
+ WEP_CVAR_SEC(weapon_name, force_zscale), \
WEP_CVAR_SEC(weapon_name, speed), \
WEP_CVAR_SEC(weapon_name, spread), \
WEP_CVAR_SEC(weapon_name, delay), \
/* spawnfunc */ ATTRIB(Hook, m_canonical_spawnfunc, string, "weapon_hook");
/* ammotype */ ATTRIB(Hook, ammo_type, int, RES_FUEL);
/* impulse */ ATTRIB(Hook, impulse, int, 0);
-/* flags */ ATTRIB(Hook, spawnflags, int, WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
+/* flags */ ATTRIB(Hook, spawnflags, int, WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NOTRUEAIM);
/* rating */ ATTRIB(Hook, bot_pickupbasevalue, float, 0);
/* color */ ATTRIB(Hook, wpcolor, vector, '0 0.5 0');
/* modelname */ ATTRIB(Hook, mdl, string, "hookgun");
}
#endif
ENDCLASS(OffhandHook)
-OffhandHook OFFHAND_HOOK; STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(OffhandHook); }
+OffhandHook OFFHAND_HOOK;
+STATIC_INIT(OFFHAND_HOOK) { OFFHAND_HOOK = NEW(OffhandHook); }
#ifdef SVQC
actor.punchangle_y = random() - 0.5;
}
- fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_speed), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), thiswep.m_id, EFFECT_BULLET);
+ fireBullet(actor, weaponentity, w_shotorg, w_shotdir, WEP_CVAR(machinegun, burst_spread), WEP_CVAR(machinegun, solidpenetration), WEP_CVAR(machinegun, sustained_damage), WEP_CVAR(machinegun, sustained_force), thiswep.m_id, EFFECT_BULLET);
Send_Effect(EFFECT_MACHINEGUN_MUZZLEFLASH, w_shotorg, w_shotdir * 1000, 1);
P(class, prefix, burst_animtime, float, NONE) \
P(class, prefix, burst_refire2, float, NONE) \
P(class, prefix, burst_refire, float, NONE) \
- P(class, prefix, burst_speed, float, NONE) \
+ P(class, prefix, burst_spread, float, NONE) \
P(class, prefix, first, float, NONE) \
P(class, prefix, first_ammo, float, NONE) \
P(class, prefix, first_damage, float, NONE) \
/* spawnfunc */ ATTRIB(Mortar, m_canonical_spawnfunc, string, "weapon_mortar");
/* ammotype */ ATTRIB(Mortar, ammo_type, int, RES_ROCKETS);
/* impulse */ ATTRIB(Mortar, impulse, int, 4);
-/* flags */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH);
+/* flags */ ATTRIB(Mortar, spawnflags, int, WEP_FLAG_NORMAL | WEP_FLAG_RELOADABLE | WEP_FLAG_CANCLIMB | WEP_TYPE_SPLASH | WEP_FLAG_NOTRUEAIM);
/* 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 CSQC
+STATIC_INIT(Porto)
+{
+ entity e = new_pure(porto);
+ e.draw = Porto_Draw;
+ IL_PUSH(g_drawables, e);
+ e.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP;
+}
+
+const int polyline_length = 16;
+.vector polyline[polyline_length];
+void Porto_Draw(entity this)
+{
+ if (spectatee_status || intermission == 1 || intermission == 2 || STAT(HEALTH) <= 0 || WEP_CVAR(porto, secondary)) return;
+
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ {
+ entity wepent = viewmodels[slot];
+
+ if (wepent.activeweapon != WEP_PORTO) continue;
+
+ vector pos = view_origin;
+ vector dir = view_forward;
+ makevectors(((autocvar_chase_active) ? warpzone_save_view_angles : view_angles));
+ pos += v_right * -wepent.movedir.y
+ + v_up * wepent.movedir.z;
+
+ if (wepent.angles_held_status)
+ {
+ makevectors(wepent.angles_held);
+ dir = v_forward;
+ }
+
+ wepent.polyline[0] = pos;
+
+ int portal_number = 0, portal1_idx = 1, portal_max = 2;
+ int n = 1 + 2; // 2 lines == 3 points
+ for (int idx = 0; idx < n && idx < polyline_length - 1; )
+ {
+ traceline(pos, pos + 65536 * dir, true, this);
+ dir = reflect(dir, trace_plane_normal);
+ pos = trace_endpos;
+ wepent.polyline[++idx] = pos;
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_SLICK || trace_dphitcontents & DPCONTENTS_PLAYERCLIP)
+ {
+ n += 1;
+ continue;
+ }
+ if (trace_dphitq3surfaceflags & Q3SURFACEFLAG_NOIMPACT)
+ {
+ n = max(2, idx);
+ break;
+ }
+ // check size
+ {
+ vector ang = vectoangles2(trace_plane_normal, dir);
+ ang.x = -ang.x;
+ makevectors(ang);
+ if (!CheckWireframeBox(this, pos - 48 * v_right - 48 * v_up + 16 * v_forward, 96 * v_right, 96 * v_up, 96 * v_forward))
+ {
+ n = max(2, idx);
+ break;
+ }
+ }
+ portal_number += 1;
+ if (portal_number >= portal_max) break;
+ if (portal_number == 1) portal1_idx = idx;
+ }
+ for (int idx = 0; idx < n - 1; ++idx)
+ {
+ vector p = wepent.polyline[idx], q = wepent.polyline[idx + 1];
+ if (idx == 0) p -= view_up * 16; // line from player
+ vector rgb = (idx < portal1_idx) ? '1 0 0' : '0 0 1';
+ Draw_CylindricLine(p, q, 4, "", 1, 0, rgb, 0.5, DRAWFLAG_NORMAL, view_origin);
+ }
+ }
+}
+#endif
+
#ifdef SVQC
#include <common/mapobjects/trigger/jumppads.qh>
#include <server/weapons/throwing.qh>
/* spawnfunc */ ATTRIB(PortoLaunch, m_canonical_spawnfunc, string, "weapon_porto");
/* ammotype */ ATTRIB(PortoLaunch, ammo_type, int, RES_NONE);
/* impulse */ ATTRIB(PortoLaunch, impulse, int, 0);
-/* flags */ ATTRIB(PortoLaunch, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON | WEP_FLAG_NODUAL);
+/* flags */ ATTRIB(PortoLaunch, spawnflags, int, WEP_TYPE_OTHER | WEP_FLAG_SUPERWEAPON | WEP_FLAG_NODUAL | WEP_FLAG_NOTRUEAIM);
/* rating */ ATTRIB(PortoLaunch, bot_pickupbasevalue, float, 0);
/* color */ ATTRIB(PortoLaunch, wpcolor, vector, '0.5 0.5 0.5');
/* modelname */ ATTRIB(PortoLaunch, mdl, string, "porto");
SPAWNFUNC_WEAPON(weapon_porto, WEP_PORTO)
+#ifdef CSQC
+void Porto_Draw(entity this);
+#endif
+
#ifdef SVQC
.entity porto_current;
.vector porto_v_angle; // holds "held" view angles
/* spawnfunc */ ATTRIB(Shockwave, m_canonical_spawnfunc, string, "weapon_shockwave");
/* ammotype */ //ATTRIB(Shockwave, ammo_type, int, RES_NONE);
/* impulse */ ATTRIB(Shockwave, impulse, int, 2);
-/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
+/* flags */ ATTRIB(Shockwave, spawnflags, int, WEP_FLAG_HIDDEN | WEP_TYPE_HITSCAN | WEP_FLAG_CANCLIMB | WEP_TYPE_MELEE_SEC);
/* rating */ ATTRIB(Shockwave, bot_pickupbasevalue, float, 3000);
/* color */ ATTRIB(Shockwave, wpcolor, vector, '0.5 0.25 0');
/* modelname */ ATTRIB(Shockwave, mdl, string, "shotgun");
vector o;
float n = W_Tuba_GetNote(actor, hittype);
- hittype = 0;
+ hittype = HITTYPE_SOUND;
if(actor.(weaponentity).tuba_instrument & 1)
hittype |= HITTYPE_SECONDARY;
if(actor.(weaponentity).tuba_instrument & 2)
CLASS(Tuba, Weapon)
/* spawnfunc */ ATTRIB(Tuba, m_canonical_spawnfunc, string, "weapon_tuba");
/* impulse */ ATTRIB(Tuba, impulse, int, 1);
-/* flags */ ATTRIB(Tuba, spawnflags, int, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL);
+/* flags */ ATTRIB(Tuba, spawnflags, int, WEP_FLAG_HIDDEN | WEP_TYPE_SPLASH | WEP_FLAG_NODUAL | WEP_FLAG_NOTRUEAIM);
/* rating */ ATTRIB(Tuba, bot_pickupbasevalue, float, 2000);
/* color */ ATTRIB(Tuba, wpcolor, vector, '0 1 0');
/* modelname */ ATTRIB(Tuba, mdl, string, "tuba");
classfield(Tuba) .float tuba_volume_initial;
classfield(Tuba) .int tuba_instrument;
#endif
+
+#ifdef SVQC
+bool W_Tuba_HasPlayed(entity pl, .entity weaponentity, string melody, int instrument, bool ignorepitch, float mintempo, float maxtempo);
+#endif
P(class, prefix, delay, float, SEC) \
P(class, prefix, edgedamage, float, SEC) \
P(class, prefix, force, float, SEC) \
+ P(class, prefix, force_zscale, float, SEC) \
P(class, prefix, lifetime, float, SEC) \
P(class, prefix, radius, float, SEC) \
P(class, prefix, refire, float, SEC) \
.float vortex_chargepool_pauseregen_finished;
+void W_Vortex_Charge(entity actor, .entity weaponentity, float dt)
+{
+ if(WEP_CVAR(vortex, charge) && actor.(weaponentity).vortex_charge < WEP_CVAR(vortex, charge_limit))
+ actor.(weaponentity).vortex_charge = min(1, actor.(weaponentity).vortex_charge + WEP_CVAR(vortex, charge_rate) * dt / W_TICSPERFRAME);
+}
+
METHOD(Vortex, wr_aim, void(entity thiswep, entity actor, .entity weaponentity))
{
if(bot_aim(actor, weaponentity, 1000000, 0, 1, false))
}
METHOD(Vortex, wr_think, void(entity thiswep, entity actor, .entity weaponentity, int fire))
{
- if(WEP_CVAR(vortex, charge) && actor.(weaponentity).vortex_charge < WEP_CVAR(vortex, charge_limit))
- actor.(weaponentity).vortex_charge = min(1, actor.(weaponentity).vortex_charge + WEP_CVAR(vortex, charge_rate) * frametime / W_TICSPERFRAME);
+ if(!WEP_CVAR(vortex, charge_always))
+ W_Vortex_Charge(actor, weaponentity, frametime);
if(WEP_CVAR_SEC(vortex, chargepool))
if(actor.(weaponentity).vortex_chargepool_ammo < 1)
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_always, float, NONE) \
P(class, prefix, charge_animlimit, float, NONE) \
P(class, prefix, charge_limit, float, NONE) \
P(class, prefix, charge_maxspeed, float, NONE) \
#ifdef SVQC
.float vortex_lasthit;
+
+void W_Vortex_Charge(entity actor, .entity weaponentity, float dt);
#endif
\
PROP(false, porto_v_angle_held, WEPENT_SET_NORMAL, \
{ WriteByte(chan, this.porto_v_angle_held); if(this.porto_v_angle_held) { \
- WriteAngle(chan, this.porto_v_angle.x); WriteAngle(chan, this.porto_v_angle.y); \
+ WriteAngle(chan, this.owner.porto_v_angle.x); WriteAngle(chan, this.owner.porto_v_angle.y); \
} }, \
{ (viewmodels[this.m_wepent_slot]).angles_held_status = ReadByte(); if((viewmodels[this.m_wepent_slot]).angles_held_status) { \
- (viewmodels[this.m_wepent_slot]).angles_held_x = ReadAngle(); (viewmodels[this.m_wepent_slot]).angles_held_y = ReadAngle(); (viewmodels[this.m_wepent_slot]).angles_held_z = 0; } \
+ (viewmodels[this.m_wepent_slot]).angles_held = vec2(ReadAngle(), ReadAngle()); } \
else { (viewmodels[this.m_wepent_slot]).angles_held = '0 0 0'; } }) \
\
PROP(false, tuba_instrument, WEPENT_SET_NORMAL, \
PROP(false, clip_size, WEPENT_SET_NORMAL, \
{ WriteShort(chan, this.clip_size); }, \
{ (viewmodels[this.m_wepent_slot]).clip_size = ReadShort(); }) \
+ \
+ PROP(false, skin, WEPENT_SET_NORMAL, \
+ { WriteShort(chan, this.skin); }, \
+ { (viewmodels[this.m_wepent_slot]).m_skin = ReadShort(); }) \
\
/**/
.float m_alpha;
+ .int m_skin;
+
// only for Porto
.bool angles_held_status;
.vector angles_held;
_("CI_THI^%d seconds"), /* third */ \
_("CI_MUL^%d seconds")) /* multi */
+// returns 1st, 2nd, 3rd, nth ordinal number from a cardinal number (integer)
ERASEABLE
string count_ordinal(int interval)
{
// to accomodate all languages unless we do a specific function for each one...
// and since that's not technically feasible/practical, this is all we've got folks.
- // Basically, it just allows you to represent a number or count in different ways
- // depending on the number... like, with count_ordinal you can provide integers
- // and retrieve 1st, 2nd, 3rd, nth ordinal numbers in a clean and simple way.
- if (floor((interval % 100) / 10) * 10 != 10) // examples: 12th, 111th, 213th will not execute this block
+ int last2digits = interval % 100;
+
+ // numbers ending with 11, 12 and 13 don't follow the standard pattern
+ if (last2digits < 4 || last2digits > 20)
{
- // otherwise, check normally for 1st,2nd,3rd insertions
- switch (interval % 10)
+ switch (last2digits % 10)
{
case 1: return sprintf(_("%dst"), interval);
case 2: return sprintf(_("%dnd"), interval);
case 3: return sprintf(_("%drd"), interval);
- default: return sprintf(_("%dth"), interval);
}
}
- else { return sprintf(_("%dth"), interval); }
- return "";
+ return sprintf(_("%dth"), interval);
}
ERASEABLE
this.csqcmodel_teleported = 1;
}
+ if(sf & BIT(3))
+ this.alpha = this.m_alpha;
+
if(sf & BIT(14))
viewloc_SetTags(this);
#define CSQCMODEL_ENDIF
#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
.t f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+ .t f;
ALLPROPERTIES
#undef CSQCMODEL_PROPERTY_SCALED
#undef CSQCMODEL_PROPERTY
{ \
w(MSG_ENTITY, this.csqcmodel_##f); \
}
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+ if(sf & flag) \
+ { \
+ w(MSG_ENTITY, this.csqcmodel_##f); \
+ }
ALLPROPERTIES
#undef CSQCMODEL_PROPERTY_SCALED
#undef CSQCMODEL_PROPERTY
#define CSQCMODEL_PROPERTY(flag,t,r,w,f) \
.t f; \
.t csqcmodel_##f;
-#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) CSQCMODEL_PROPERTY(flag,t,r,w,f)
+#define CSQCMODEL_PROPERTY_SCALED(flag,t,r,w,f,s,mi,ma) \
+ .t f; \
+ .t csqcmodel_##f;
ALLPROPERTIES
#undef CSQCMODEL_PROPERTY_SCALED
#undef CSQCMODEL_PROPERTY
#define REGISTRY_HASH(id) Registry_hash_##id
ERASEABLE
-ACCUMULATE void Registry_check(string r, string server) { }
+ACCUMULATE void Registry_check(string r, string sv) { }
ERASEABLE
ACCUMULATE void Registry_send_all() { }
STATIC_INIT(Registry_check_##id) \
{ \
/* Note: SHA256 isn't always available, use MD4 instead */ \
- string s = "", join = ":"; \
- FOREACH(id, true, s = strcat(s, join, it.registered_id)); \
- s = substring(s, strlen(join), -1); \
+ string s = ""; \
+ FOREACH(id, true, s = strcat(s, ":", it.registered_id)); \
+ s = substring(s, 1, -1); /* remove initial ":" */ \
string h = REGISTRY_HASH(id) = strzone(digest_hex("MD4", s)); \
LOG_DEBUGF(#id ": %s\n[%s]", h, s); \
} \
#define REPLICATE(...) EVAL_REPLICATE(OVERLOAD(REPLICATE, __VA_ARGS__))
#define EVAL_REPLICATE(...) __VA_ARGS__
+ #if defined(SVQC)
ACCUMULATE void ReplicateVars(entity this, entity store, string thisname, int i) {}
+ #elif defined(CSQC)
+ ACCUMULATE void ReplicateVars(bool would_destroy) {}
+ #endif
#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, , \
- { strcpy(field, it); }, \
- { strfree(field); }, \
- { \
- /* also initialize to the default value of func when requesting cvars */ \
- string s = func(field); \
- if (s != field) \
+ #if defined(SVQC)
+ #define REPLICATE_string(fld, var, func) \
+ REPLICATE_7(fld, string, var, , \
+ { strcpy(field, it); }, \
+ { strfree(field); }, \
{ \
- strcpy(field, s); \
- } \
- })
- #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func, { field = stof(it); }, , )
- #define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func, { field = boolean(stoi(it)); }, , )
- #define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func, { field = stoi(it); }, , )
+ /* also initialize to the default value of func when requesting cvars */ \
+ string s = func(field); \
+ if (s != field) \
+ { \
+ strcpy(field, s); \
+ } \
+ })
+ #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func, { field = stof(it); }, , )
+ #define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func, { field = boolean(stoi(it)); }, , )
+ #define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func, { field = stoi(it); }, , )
- #if defined(SVQC)
#define REPLICATE_7(fld, type, var, func, create, destroy, after) \
void ReplicateVars(entity this, entity store, string thisname, int i) \
{ \
} \
else \
{ \
- stuffcmd(this, "cl_cmd sendcvar " var "\n"); \
+ stuffcmd(this, strcat("cl_cmd sendcvar ", var, "\n")); \
} \
if (current) { after } \
} \
store.fld = field; \
}
#elif defined(CSQC)
- // TODO
- #define REPLICATE_7(fld, type, var, func, create, destroy, after)
+ float ReplicateVars_time;
+ #define ReplicateVars_NOT_SENDING() (time > ReplicateVars_time)
+ #define ReplicateVars_DELAY(t) ReplicateVars_time = time + t
+ #define ReplicateVars_DELAY_1FRAME() ReplicateVars_time = time
+ #define REPLICATE_string(fld, var, func) REPLICATE_7(fld, float, var, func, (fld != cvar_string(var)), { strcpy(fld, cvar_string(var)); }, { strfree(fld); })
+ #define REPLICATE_float(fld, var, func) REPLICATE_7(fld, float, var, func, (fld != cvar(var)), { fld = cvar(var); }, )
+ #define REPLICATE_bool(fld, var, func) REPLICATE_7(fld, bool, var, func, (fld != cvar(var)), { fld = cvar(var); }, )
+ #define REPLICATE_int(fld, var, func) REPLICATE_7(fld, int, var, func, (fld != cvar(var)), { fld = cvar(var); }, )
+
+ #define REPLICATE_7(fld, type, var, func, check, update, destroy) \
+ void ReplicateVars(bool would_destroy) \
+ { \
+ if (would_destroy) { destroy } \
+ else if (ReplicateVars_NOT_SENDING() && check) \
+ { \
+ localcmd(strcat("cl_cmd sendcvar ", var, "\n")); \
+ ReplicateVars_DELAY_1FRAME(); \
+ update \
+ return; \
+ } \
+ }
+
+ #define REPLICATE_SIMPLE(field, cvarname) MACRO_BEGIN \
+ if (ReplicateVars_NOT_SENDING() && field != cvar(cvarname)) \
+ { \
+ localcmd(strcat("cl_cmd sendcvar ", cvarname, "\n")); \
+ ReplicateVars_DELAY_1FRAME(); \
+ field = cvar(cvarname); \
+ return; \
+ } \
+ MACRO_END
#endif
#endif
FIELD_SCALAR(fld, health) \
FIELD_SCALAR(fld, height) \
FIELD_SCALAR(fld, impulse) \
+ FIELD_SCALAR(fld, item_pickupsound) \
FIELD_SCALAR(fld, killtarget) \
FIELD_SCALAR(fld, lerpfrac) \
FIELD_SCALAR(fld, light_lev) \
FIELD_SCALAR(fld, lip) \
FIELD_SCALAR(fld, loddistance1) \
FIELD_SCALAR(fld, lodmodel1) \
+ FIELD_SCALAR(fld, lodmodel2) \
FIELD_SCALAR(fld, ltime) \
FIELD_SCALAR(fld, map) \
FIELD_SCALAR(fld, max_health) \
FIELD_SCALAR(fld, target_range) \
FIELD_SCALAR(fld, team) \
FIELD_SCALAR(fld, trigger_reverse) \
+ FIELD_SCALAR(fld, turret_scale_aim) \
+ FIELD_SCALAR(fld, turret_scale_ammo) \
+ FIELD_SCALAR(fld, turret_scale_damage) \
FIELD_SCALAR(fld, turret_scale_health) \
FIELD_SCALAR(fld, turret_scale_range) \
+ FIELD_SCALAR(fld, turret_scale_refire) \
FIELD_SCALAR(fld, turret_scale_respawn) \
FIELD_SCALAR(fld, volume) \
FIELD_SCALAR(fld, wait) \
NET_HANDLE(ENT_CLIENT_WARPZONE, bool isnew)
{
if(!warpzone_warpzones_exist)
+ {
cvar_settemp("r_water", "1"); // HACK for DarkPlaces: always enable reflections when a map has warpzones
+ cvar_settemp("r_water_resolutionmultiplier", "1"); // HACK for DarkPlaces: enforce full quality so entities can be seen clearly through warpzones
+ }
warpzone_warpzones_exist = 1;
if (!this.enemy)
{
NET_HANDLE(ENT_CLIENT_WARPZONE_CAMERA, bool isnew)
{
if(!warpzone_cameras_exist)
+ {
cvar_settemp("r_water", "1"); // HACK for DarkPlaces: always enable reflections when a map has cameras
+ cvar_settemp("r_water_resolutionmultiplier", "1"); // HACK for DarkPlaces: enforce full quality so entities can be seen clearly through warpzones
+ }
warpzone_cameras_exist = 1;
this.classname = "func_warpzone_camera";
void WarpZoneLib_MoveOutOfSolid_Expand(entity e, vector by)
{
- float eps = 0.0625;
+ const float eps = 0.0625;
tracebox(e.origin, e.mins - '1 1 1' * eps, e.maxs + '1 1 1' * eps, e.origin + by, MOVE_WORLDONLY, e);
if (trace_startsolid)
return;
for(i = WEP_FIRST, j = 0; i <= WEP_LAST; ++i)
{
w = Weapons_from(i);
- if(w.spawnflags & WEP_FLAG_HIDDEN)
+ if (w.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK))
continue;
if ((j % 3) == 0)
{
me.gotoRC(me, 0, 3.1);
me.TD(me, 1, 1.9, e = makeXonoticCheckBoxEx(2, 1, "cl_autoscreenshot", _("Auto screenshot scoreboard")));
+ e.sendCvars = true;
me.TD(me, 1, 1, e = makeXonoticButton(_("Refresh"), '0 0 0'));
e.onClick = ScreenshotList_Refresh_Click;
e.onClickEntity = slist;
"name \"$_cl_name\";"
"playermodel $_cl_playermodel;"
"playerskin $_cl_playerskin;"
- "sendcvar cl_allow_uidtracking;"
- "sendcvar cl_allow_uid2name;"
, COMMANDBUTTON_APPLY);
profileApplyButton.disableOnClick = true;
me.TR(me);
me.TDempty(me, 0.25);
me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uidtracking", _("Allow player statistics to track your client")));
- e.applyButton = profileApplyButton;
+ e.sendCvars = true;
me.TR(me);
me.TDempty(me, 0.25);
me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uid2name", _("Allow player statistics to use your nickname")));
- e.applyButton = profileApplyButton;
+ e.sendCvars = true;
+ setDependent(e, "cl_allow_uidtracking", 1, 1);
+ me.TR(me);
+ me.TDempty(me, 0.25);
+ me.TD(me, 1, 2.5, e = makeXonoticCheckBox(0, "cl_allow_uidranking", _("Allow player statistics to rank you in leaderboards")));
+ e.sendCvars = true;
setDependent(e, "cl_allow_uidtracking", 1, 1);
- me.gotoRC(me, 4, 3.1); // TOP RIGHT
+ me.gotoRC(me, 4.5, 3.1); // TOP RIGHT
//me.gotoRC(me, 12.5, 3.1); // BOTTOM RIGHT
//me.gotoRC(me, 12.5, 0); // BOTTOM LEFT
me.TDempty(me, 0.25);
me.TR(me);
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_clippedspectating", _("Allow passing through walls while spectating")));
+ e.sendCvars = true;
me.gotoRC(me, 0, 3.2); me.setFirstColumn(me, me.currentColumn);
me.TD(me, 1, 1, e = makeXonoticTextLabel(0, _("Field of view:")));
{
entity e;
entity weaponsApplyButton = makeXonoticCommandButton(_("Apply immediately"), '0 0 0',
- "sendcvar cl_autoswitch;"
"sendcvar cl_weaponpriority;"
- "sendcvar cl_weaponimpulsemode;"
, COMMANDBUTTON_APPLY);
weaponsApplyButton.disableOnClick = true;
_("Make use of the list above when cycling through weapons with the mouse wheel")));
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticCheckBox(1, "cl_weaponimpulsemode", _("Cycle through only usable weapon selections")));
- e.applyButton = weaponsApplyButton;
+ e.sendCvars = true;
me.TR(me);
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticCheckBox_T(0, "cl_autoswitch", _("Auto switch weapons on pickup"),
_("Automatically switch to newly picked up weapons if they are better than what you are carrying")));
- e.applyButton = weaponsApplyButton;
+ e.sendCvars = true;
me.TR(me);
me.TD(me, 1, 3, e = makeXonoticCheckBox(0, "cl_unpress_attack_on_weapon_switch", _("Release attack buttons when you switch weapons")));
me.TR(me);
void XonoticUserSettingsTab_fill(entity me)
{
entity e, sk;
- entity userApplyButton = makeXonoticCommandButton(_("Apply immediately"), '0 0 0', "sendcvar cl_gentle;", COMMANDBUTTON_APPLY);
- userApplyButton.disableOnClick = true;
me.TR(me);
me.TDempty(me, 0.25);
me.gotoRC(me, 11.5, 3.25); me.setFirstColumn(me, me.currentColumn);
me.TD(me, 1, 2.5, e = makeXonoticCheckBox_T(0, "cl_gentle", _("Disable gore effects and harsh language"),
_("Replace blood and gibs with content that does not have any gore effects")));
- e.applyButton = userApplyButton;
-
- me.gotoRC(me, me.rows - 1, 0);
- me.TD(me, 1, 6, userApplyButton);
-
+ e.sendCvars = true;
}
for(int imp = 1; imp <= 9; ++imp)
{
string w_list = "";
- ADD_TO_W_LIST(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_HIDDEN) && !(it.spawnflags & WEP_FLAG_SUPERWEAPON));
+ ADD_TO_W_LIST(!(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK | WEP_FLAG_SUPERWEAPON)));
ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_SUPERWEAPON) && !(it.spawnflags & WEP_FLAG_HIDDEN));
- ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & WEP_FLAG_HIDDEN));
+ ADD_TO_W_LIST((it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && !(it.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK)));
if(w_list)
KEYBIND_DEF(strcat("weapon_group_", itos(imp)), substring(w_list, 0, -4));
if(imp == 0)
KEYBIND_DEF("kill" , _("respawn"));
KEYBIND_DEF("quickmenu" , _("quick menu"));
KEYBIND_DEF("menu_showsandboxtools" , _("sandbox menu"));
+ KEYBIND_DEF("wpeditor_menu" , _("waypoint editor menu"));
KEYBIND_DEF("+button8" , _("drag object"));
KEYBIND_EMPTY_LINE();
bool autocvar_g_maplist_votable_suggestions;
bool autocvar_g_maplist_votable_suggestions_override_mostrecent;
float autocvar_g_maplist_votable_timeout;
+bool autocvar_g_maplist_ignore_sizes;
int autocvar_g_maxplayers;
float autocvar_g_maxplayers_spectator_blocktime;
float autocvar_g_maxpushtime;
int autocvar_g_pickup_items;
float autocvar_g_player_alpha;
float autocvar_g_player_brightness;
+float autocvar_g_player_damageforcescale = 2;
bool autocvar_g_playerclip_collisions;
int autocvar_g_powerups;
int autocvar_g_projectiles_damage;
int autocvar_leadlimit_override;
int autocvar_minplayers;
int autocvar_minplayers_per_team;
-int autocvar_name_maxlength;
string autocvar_nextmap;
string autocvar_quit_and_redirect;
float autocvar_quit_and_redirect_timer;
float autocvar_sv_maxairspeed;
float autocvar_sv_maxspeed;
string autocvar_sv_motd;
+int autocvar_sv_name_maxlength = 64;
bool autocvar_sv_precacheplayermodels;
bool autocvar_sv_q3acompat_machineshotgunswap;
bool autocvar_sv_servermodelsonly;
const int WAYPOINTFLAG_GENERATED = BIT(23);
const int WAYPOINTFLAG_ITEM = BIT(22);
const int WAYPOINTFLAG_TELEPORT = BIT(21); // teleports, warpzones and jumppads
-const int WAYPOINTFLAG_NORELINK = BIT(20);
+//const int WAYPOINTFLAG_NORELINK = BIT(20); // deprecated, see explanation below. Do not recycle this bit.
const int WAYPOINTFLAG_PERSONAL = BIT(19);
const int WAYPOINTFLAG_PROTECTED = BIT(18); // Useless WP detection never kills these.
const int WAYPOINTFLAG_USEFUL = BIT(17); // Useless WP detection temporary flag.
const int WAYPOINTFLAG_DEAD_END = BIT(16); // Useless WP detection temporary flag.
const int WAYPOINTFLAG_LADDER = BIT(15);
const int WAYPOINTFLAG_JUMP = BIT(14);
+const int WAYPOINTFLAG_CUSTOM_JP = BIT(13); // jumppad with different destination waypoint (changed in the editor)
+const int WAYPOINTFLAG_CROUCH = BIT(12);
+const int WAYPOINTFLAG_SUPPORT = BIT(11);
-entity kh_worldkeylist;
-.entity kh_worldkeynext;
+// removed WAYPOINTFLAG_NORELINK since it breaks backward compatibility
+// e.g. support waypoints would have no outgoing links in old Xonotic versions
+// In general, old Xonotic versions should spawn a normal waypoint for each unknown waypoint type
+const int WAYPOINTFLAG_NORELINK__DEPRECATED = BIT(20);
+const int WPFLAGMASK_NORELINK = (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER | WAYPOINTFLAG_JUMP | WAYPOINTFLAG_CUSTOM_JP | WAYPOINTFLAG_SUPPORT);
float bot_custom_weapon;
float bot_weapons_close[Weapons_MAX];
.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
.float wpconsidered;
.float wpcost;
-.float wphardwired;
.int wpflags;
+.entity wphw00, wphw01, wphw02, wphw03, wphw04, wphw05, wphw06, wphw07;
bool bot_aim(entity this, .entity weaponentity, float shotspeed, float shotspeedupward, float maxshottime, float applygravity);
void bot_aim_reset(entity this);
void navigation_goalrating_timeout_force(entity this);
void navigation_goalrating_timeout_expire(entity this, float seconds);
bool navigation_goalrating_timeout(entity this);
+void navigation_goalrating_timeout_extend_if_needed(entity this, float seconds);
bool navigation_goalrating_timeout_can_be_anticipated(entity this);
void navigation_markroutes(entity this, entity fixed_source_waypoint);
void navigation_markroutes_inverted(entity fixed_source_waypoint);
void waypoint_spawnforitem_force(entity e, vector org);
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent);
void waypoint_spawnforteleporter_wz(entity e, entity tracetest_ent);
-void waypoint_spawn_fromeditor(entity pl);
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp);
entity waypoint_spawn(vector m1, vector m2, float f);
void waypoint_unreachable(entity pl);
+void waypoint_start_hardwiredlink(entity pl, bool at_crosshair);
+void waypoint_lock(entity pl);
void waypoint_getSymmetricalOrigin_cmd(entity caller, bool save, int arg_idx);
void waypoint_getSymmetricalAxis_cmd(entity caller, bool save, int arg_idx);
stepheightvec = autocvar_sv_stepheight * '0 0 1';
jumpheight_vec = (autocvar_sv_jumpvelocity ** 2) / (2 * autocvar_sv_gravity) * '0 0 1';
jumpstepheightvec = stepheightvec + jumpheight_vec * 0.85; // reduce it a bit to make the jumps easy
+ jumpheight_time = autocvar_sv_jumpvelocity / autocvar_sv_gravity;
}
bool bot_fixcount()
if(botframe_cachedwaypointlinks)
{
if(!botframe_loadedforcedlinks)
- waypoint_load_links_hardwired();
+ waypoint_load_hardwiredlinks();
}
else
{
#include "havocbot.qh"
+#include "roles.qh"
+
#include <server/defs.qh>
#include <server/miscfunctions.qh>
#include "../cvars.qh"
#include <lib/warpzone/common.qh>
-.float speed;
-
void havocbot_ai(entity this)
{
if(this.draggedby)
void havocbot_keyboard_movement(entity this, vector destorg)
{
- vector keyboard;
+ if(time <= this.havocbot_keyboardtime)
+ return;
- if (time > this.havocbot_keyboardtime)
+ float sk = skill + this.bot_moveskill;
+ this.havocbot_keyboardtime =
+ max(
+ this.havocbot_keyboardtime
+ + 0.05 / max(1, sk + this.havocbot_keyboardskill)
+ + random() * 0.025 / max(0.00025, skill + this.havocbot_keyboardskill)
+ , time);
+ vector keyboard = CS(this).movement / autocvar_sv_maxspeed;
+
+ float trigger = autocvar_bot_ai_keyboard_threshold;
+
+ // categorize forward movement
+ // at skill < 1.5 only forward
+ // at skill < 2.5 only individual directions
+ // at skill < 4.5 only individual directions, and forward diagonals
+ // at skill >= 4.5, all cases allowed
+ if (keyboard.x > trigger)
{
- float sk = skill + this.bot_moveskill;
- this.havocbot_keyboardtime =
- max(
- this.havocbot_keyboardtime
- + 0.05 / max(1, sk + this.havocbot_keyboardskill)
- + random() * 0.025 / max(0.00025, skill + this.havocbot_keyboardskill)
- , time);
- keyboard = CS(this).movement / autocvar_sv_maxspeed;
-
- float trigger = autocvar_bot_ai_keyboard_threshold;
-
- // categorize forward movement
- // at skill < 1.5 only forward
- // at skill < 2.5 only individual directions
- // at skill < 4.5 only individual directions, and forward diagonals
- // at skill >= 4.5, all cases allowed
- if (keyboard.x > trigger)
- {
- keyboard.x = 1;
- if (sk < 2.5)
- keyboard.y = 0;
- }
- else if (keyboard.x < -trigger && sk > 1.5)
- {
- keyboard.x = -1;
- if (sk < 4.5)
- keyboard.y = 0;
- }
- else
- {
- keyboard.x = 0;
- if (sk < 1.5)
- keyboard.y = 0;
- }
+ keyboard.x = 1;
+ if (sk < 2.5)
+ keyboard.y = 0;
+ }
+ else if (keyboard.x < -trigger && sk > 1.5)
+ {
+ keyboard.x = -1;
if (sk < 4.5)
- keyboard.z = 0;
-
- if (keyboard.y > trigger)
- keyboard.y = 1;
- else if (keyboard.y < -trigger)
- keyboard.y = -1;
- else
keyboard.y = 0;
+ }
+ else
+ {
+ keyboard.x = 0;
+ if (sk < 1.5)
+ keyboard.y = 0;
+ }
+ if (sk < 4.5)
+ keyboard.z = 0;
- if (keyboard.z > trigger)
- keyboard.z = 1;
- else if (keyboard.z < -trigger)
- keyboard.z = -1;
- else
- keyboard.z = 0;
+ if (keyboard.y > trigger)
+ keyboard.y = 1;
+ else if (keyboard.y < -trigger)
+ keyboard.y = -1;
+ else
+ keyboard.y = 0;
- // make sure bots don't get stuck if havocbot_keyboardtime is very high
- if (keyboard == '0 0 0')
- this.havocbot_keyboardtime = min(this.havocbot_keyboardtime, time + 0.2);
+ if (keyboard.z > trigger)
+ keyboard.z = 1;
+ else if (keyboard.z < -trigger)
+ keyboard.z = -1;
+ else
+ keyboard.z = 0;
- this.havocbot_keyboard = keyboard * autocvar_sv_maxspeed;
- if (this.havocbot_ducktime > time)
- PHYS_INPUT_BUTTON_CROUCH(this) = true;
+ // make sure bots don't get stuck if havocbot_keyboardtime is very high
+ if (keyboard == '0 0 0')
+ this.havocbot_keyboardtime = min(this.havocbot_keyboardtime, time + 0.2);
- keyboard = this.havocbot_keyboard;
- float blend = bound(0, vlen(destorg - this.origin) / autocvar_bot_ai_keyboard_distance, 1); // When getting close move with 360 degree
- //dprint("movement ", vtos(CS(this).movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
- CS(this).movement = CS(this).movement + (keyboard - CS(this).movement) * blend;
- }
+ this.havocbot_keyboard = keyboard * autocvar_sv_maxspeed;
+ if (this.havocbot_ducktime > time)
+ PHYS_INPUT_BUTTON_CROUCH(this) = true;
+
+ keyboard = this.havocbot_keyboard;
+ float blend = bound(0, vlen(destorg - this.origin) / autocvar_bot_ai_keyboard_distance, 1); // When getting close move with 360 degree
+ //dprint("movement ", vtos(CS(this).movement), " keyboard ", vtos(keyboard), " blend ", ftos(blend), "\n");
+ CS(this).movement = CS(this).movement + (keyboard - CS(this).movement) * blend;
}
void havocbot_bunnyhop(entity this, vector dir)
{
- float bunnyhopdistance;
- vector deviation;
- float maxspeed;
-
// Don't jump when attacking
if(this.aistatus & AI_STATUS_ATTACKING)
return;
if(IS_PLAYER(this.goalcurrent))
return;
- maxspeed = autocvar_sv_maxspeed;
-
- if(this.aistatus & AI_STATUS_RUNNING && vdist(this.velocity, <, autocvar_sv_maxspeed * 0.75)
- || this.aistatus & AI_STATUS_DANGER_AHEAD)
+ if((this.aistatus & AI_STATUS_RUNNING) && vdist(this.velocity, <, autocvar_sv_maxspeed * 0.75)
+ || (this.aistatus & AI_STATUS_DANGER_AHEAD))
{
this.aistatus &= ~AI_STATUS_RUNNING;
PHYS_INPUT_BUTTON_JUMP(this) = false;
return;
}
- if(this.waterlevel > WATERLEVEL_WETFEET)
+ if(this.waterlevel > WATERLEVEL_WETFEET || IS_DUCKED(this))
{
this.aistatus &= ~AI_STATUS_RUNNING;
return;
}
vector gco = get_closer_dest(this.goalcurrent, this.origin);
- bunnyhopdistance = vlen(this.origin - gco);
// Run only to visible goals
if(IS_ONGROUND(this))
- if(vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed)) // if -really- running
+ if(vdist(vec2(this.velocity), >=, autocvar_sv_maxspeed))
if(checkpvs(this.origin + this.view_ofs, this.goalcurrent))
{
- this.bot_lastseengoal = this.goalcurrent;
+ this.bot_lastseengoal = this.goalcurrent;
- // seen it before
- if(this.bot_timelastseengoal)
+ // seen it before
+ if(this.bot_timelastseengoal)
+ {
+ // for a period of time
+ if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
{
- // for a period of time
- if(time - this.bot_timelastseengoal > autocvar_bot_ai_bunnyhop_firstjumpdelay)
- {
- float checkdistance;
- checkdistance = true;
+ bool checkdistance = true;
- // don't run if it is too close
- if(this.bot_canruntogoal==0)
- {
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_startdistance)
- this.bot_canruntogoal = 1;
- else
- this.bot_canruntogoal = -1;
- }
+ // don't run if it is too close
+ if(this.bot_canruntogoal==0)
+ {
+ if(vdist(this.origin - gco, >, autocvar_bot_ai_bunnyhop_startdistance))
+ this.bot_canruntogoal = 1;
+ else
+ this.bot_canruntogoal = -1;
+ }
- if(this.bot_canruntogoal != 1)
- return;
+ if(this.bot_canruntogoal != 1)
+ return;
- if(this.aistatus & AI_STATUS_ROAMING)
- if(this.goalcurrent.classname=="waypoint")
- if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
- if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
- if(this.goalstack01 && !wasfreed(this.goalstack01))
+ if(this.aistatus & AI_STATUS_ROAMING)
+ if(this.goalcurrent.classname == "waypoint")
+ if (!(this.goalcurrent.wpflags & WAYPOINTFLAG_PERSONAL))
+ if(fabs(gco.z - this.origin.z) < this.maxs.z - this.mins.z)
+ if (this.goalstack01 && !wasfreed(this.goalstack01))
+ if (!(this.goalstack01.wpflags & WAYPOINTFLAG_JUMP))
+ {
+ vector gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
+ vector deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
+ while (deviation.y < -180) deviation.y = deviation.y + 360;
+ while (deviation.y > 180) deviation.y = deviation.y - 360;
+
+ if(fabs(deviation.y) < 20)
+ if(vlen2(this.origin - gco) < vlen2(this.origin - gno))
+ if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
{
- vector gno = (this.goalstack01.absmin + this.goalstack01.absmax) * 0.5;
- deviation = vectoangles(gno - this.origin) - vectoangles(gco - this.origin);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y) < 20)
- if(bunnyhopdistance < vlen(this.origin - gno))
- if(fabs(gno.z - gco.z) < this.maxs.z - this.mins.z)
+ if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
+ if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
{
- if(vdist(gco - gno, >, autocvar_bot_ai_bunnyhop_startdistance))
- if(checkpvs(this.origin + this.view_ofs, this.goalstack01))
- {
- checkdistance = false;
- }
+ checkdistance = false;
}
}
+ }
- if(checkdistance)
- {
- this.aistatus &= ~AI_STATUS_RUNNING;
- // increase stop distance in case the goal is on a slope or a lower platform
- if(bunnyhopdistance > autocvar_bot_ai_bunnyhop_stopdistance + (this.origin.z - gco.z))
- PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
- else
- {
- this.aistatus |= AI_STATUS_RUNNING;
+ if(checkdistance)
+ {
+ this.aistatus &= ~AI_STATUS_RUNNING;
+ // increase stop distance in case the goal is on a slope or a lower platform
+ if(vdist(this.origin - gco, >, autocvar_bot_ai_bunnyhop_stopdistance + (this.origin.z - gco.z)))
PHYS_INPUT_BUTTON_JUMP(this) = true;
- }
+ }
+ else
+ {
+ this.aistatus |= AI_STATUS_RUNNING;
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
}
}
- else
- {
- this.bot_timelastseengoal = time;
- }
+ }
+ else
+ {
+ this.bot_timelastseengoal = time;
+ }
}
else
{
this.bot_timelastseengoal = 0;
}
-
-#if 0
- // Release jump button
- if(!cvar("sv_pogostick"))
- if((IS_ONGROUND(this)) == 0)
- {
- if(this.velocity.z < 0 || vlen(this.velocity)<maxspeed)
- PHYS_INPUT_BUTTON_JUMP(this) = false;
-
- // Strafe
- if(this.aistatus & AI_STATUS_RUNNING)
- if(vlen(this.velocity)>maxspeed)
- {
- deviation = vectoangles(dir) - vectoangles(this.velocity);
- while (deviation.y < -180) deviation.y = deviation.y + 360;
- while (deviation.y > 180) deviation.y = deviation.y - 360;
-
- if(fabs(deviation.y)>10)
- CS(this).movement_x = 0;
-
- if(deviation.y>10)
- CS(this).movement_y = maxspeed * -1;
- else if(deviation.y<10)
- CS(this).movement_y = maxspeed;
-
- }
- }
-#endif
}
// return true when bot isn't getting closer to the current goal
bool havocbot_checkgoaldistance(entity this, vector gco)
{
+ if (this.bot_stop_moving_timeout > time)
+ return false;
float curr_dist_z = max(20, fabs(this.origin.z - gco.z));
float curr_dist_2d = max(20, vlen(vec2(this.origin - gco)));
float distance_time = this.goalcurrent_distance_time;
CS(this).movement = '0 0 0';
maxspeed = autocvar_sv_maxspeed;
+ PHYS_INPUT_BUTTON_CROUCH(this) = boolean(this.goalcurrent.wpflags & WAYPOINTFLAG_CROUCH);
+
PHYS_INPUT_BUTTON_JETPACK(this) = false;
// Jetpack navigation
if(this.navigation_jetpack_goal)
return;
}
- else if(!this.jumppadcount && !this.goalcurrent.wphardwired
+ else if(!this.jumppadcount && !waypoint_is_hardwiredlink(this.goalcurrent_prev, this.goalcurrent)
+ && !(this.goalcurrent_prev && this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP)
&& GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR) > ROCKETJUMP_DAMAGE())
{
if(this.velocity.z < 0)
vector flat_diff = vec2(diff);
offset = max(32, current_speed * cos(deviation.y * DEG2RAD) * 0.3) * flatdir;
vector actual_destorg = this.origin + offset;
- if (!this.goalstack01 || this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER))
+ if (this.goalcurrent_prev && (this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP))
+ {
+ if (time > this.bot_stop_moving_timeout
+ && fabs(deviation.y) > 20 && current_speed > maxspeed * 0.4
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), <, 50))
+ {
+ this.bot_stop_moving_timeout = time + 0.1;
+ }
+ if (current_speed > autocvar_sv_maxspeed * 0.9
+ && vlen2(flat_diff) < vlen2(vec2(this.goalcurrent_prev.origin - destorg))
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), >, 50)
+ && vdist(vec2(this.origin - this.goalcurrent_prev.origin), <, 150)
+ )
+ {
+ PHYS_INPUT_BUTTON_JUMP(this) = true;
+ // avoid changing route while bot is jumping a gap
+ navigation_goalrating_timeout_extend_if_needed(this, 1.5);
+ }
+ }
+ else if (!this.goalstack01 || (this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_LADDER)))
{
if (vlen2(flat_diff) < vlen2(offset))
{
turning = true;
}
- LABEL(jump_check);
+ LABEL(jumpobstacle_check);
dir = flatdir = normalize(actual_destorg - this.origin);
- if (turning || fabs(deviation.y) < 50) // don't even try to jump if deviation is too high
+ bool jump_forbidden = false;
+ if (!turning && fabs(deviation.y) > 50)
+ jump_forbidden = true;
+ else if (IS_DUCKED(this))
+ {
+ tracebox(this.origin, PL_MIN_CONST, PL_MAX_CONST, this.origin, false, this);
+ if (trace_startsolid)
+ jump_forbidden = true;
+ }
+
+ if (!jump_forbidden)
{
tracebox(this.origin, this.mins, this.maxs, actual_destorg, false, this);
if (trace_fraction < 1 && trace_plane_normal.z < 0.7)
actual_destorg = destorg;
turning = false;
this.bot_tracewalk_time = time + 0.25;
- goto jump_check;
+ goto jumpobstacle_check;
}
s = trace_fraction;
// don't artificially reduce max jump height in real-time
bool unreachable = false;
s = CONTENT_SOLID;
- if(trace_fraction == 1 && this.jumppadcount == 0 && !this.goalcurrent.wphardwired )
+ if (trace_fraction == 1 && !this.jumppadcount
+ && !waypoint_is_hardwiredlink(this.goalcurrent_prev, this.goalcurrent)
+ && !(this.goalcurrent_prev && (this.goalcurrent_prev.wpflags & WAYPOINTFLAG_JUMP)))
if((IS_ONGROUND(this)) || (this.aistatus & AI_STATUS_RUNNING) || (this.aistatus & AI_STATUS_ROAMING) || PHYS_INPUT_BUTTON_JUMP(this))
{
// Look downwards
}
// slow down if bot is in the air and goal is under it
- if (!this.goalcurrent.wphardwired
+ if (!waypoint_is_hardwiredlink(this.goalcurrent_prev, this.goalcurrent)
&& vdist(flat_diff, <, 250) && this.origin.z - destorg.z > 120
&& (!IS_ONGROUND(this) || vdist(vec2(this.velocity), >, maxspeed * 0.3)))
{
vector havocbot_dodge(entity this);
-.void(entity this) havocbot_role;
-.void(entity this) havocbot_previous_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;
#include "../bot.qh"
#include "../navigation.qh"
-.float bot_ratingscale;
-.float bot_ratingscale_time;
-.float max_armorvalue;
-.float havocbot_role_timeout;
-
-.void(entity this) havocbot_previous_role;
-.void(entity this) havocbot_role;
-
void havocbot_goalrating_waypoints(entity this, float ratingscale, vector org, float sradius)
{
// rate waypoints only if there's no alternative goal
if(!teamplay)
return true;
- // actually these variables hold the squared distances in order to optimize code
- float friend_distance = FLOAT_MAX;
- float enemy_distance = FLOAT_MAX;
- float dist;
+ // these variables hold squared distances in order to optimize code
+ float friend_dist2 = FLOAT_MAX;
+ float enemy_dist2 = FLOAT_MAX;
+ float dist2;
FOREACH_CLIENT(IS_PLAYER(it) && it != this && !(IS_DEAD(it) || STAT(FROZEN, it)),
{
if (!IS_REAL_CLIENT(it))
continue;
- dist = vlen2(it.origin - item_org);
- if(dist > friend_distance)
+ dist2 = vlen2(it.origin - item_org);
+ if (dist2 > friend_dist2)
continue;
if(havocbot_goalrating_item_can_be_left_to_teammate(this, it, item))
{
- friend_distance = dist;
+ friend_dist2 = dist2;
continue;
}
}
{
// If enemy only track distances
// TODO: track only if visible ?
- dist = vlen2(it.origin - item_org);
- if(dist < enemy_distance)
- enemy_distance = dist;
+ dist2 = vlen2(it.origin - item_org);
+ if (dist2 < enemy_dist2)
+ enemy_dist2 = dist2;
}
});
// Rate the item only if no one needs it, or if an enemy is closer to it
- dist = vlen2(item_org - org);
- if ((enemy_distance < friend_distance && dist < enemy_distance) ||
- (friend_distance > autocvar_bot_ai_friends_aware_pickup_radius ** 2) ||
- (dist < friend_distance && dist < 200 ** 2))
+ dist2 = vlen2(item_org - org);
+ if ((enemy_dist2 < friend_dist2 && dist2 < enemy_dist2)
+ || (friend_dist2 > autocvar_bot_ai_friends_aware_pickup_radius ** 2)
+ || (dist2 < friend_dist2 && dist2 < 200 ** 2))
return true;
return false;
};
void havocbot_goalrating_items(entity this, float ratingscale, vector org, float sradius)
{
- float rating;
- vector o;
ratingscale = ratingscale * 0.0001;
IL_EACH(g_items, it.bot_pickup,
it.bot_pickup_respawning = true;
}
- o = (it.absmin + it.absmax) * 0.5;
+ vector o = (it.absmin + it.absmax) * 0.5;
if(vdist(o - org, >, sradius) || (it == this.ignoregoal && time < this.ignoregoaltime) )
continue;
it.bot_ratingscale_time = time;
it.bot_ratingscale = ratingscale;
- rating = it.bot_pickupevalfunc(this, it);
+ float rating = it.bot_pickupevalfunc(this, it);
if(rating > 0)
navigation_routerating(this, it, rating * ratingscale, 2000);
});
}
-#define BOT_RATING_ENEMY 2500
void havocbot_goalrating_enemyplayers(entity this, float ratingscale, vector org, float sradius)
{
if (autocvar_bot_nofire)
return;
// don't chase players if we're under water
- if(this.waterlevel>WATERLEVEL_WETFEET)
+ if(this.waterlevel > WATERLEVEL_WETFEET)
return;
ratingscale = ratingscale * 0.0001;
- float t;
FOREACH_CLIENT(IS_PLAYER(it) && bot_shouldattack(this, it), {
// TODO: Merge this logic with the bot_shouldattack function
if(vdist(it.origin - org, <, 100) || vdist(it.origin - org, >, sradius))
continue;
*/
- t = ((GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR)) - (GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR))) / 150;
+ float t = ((GetResource(this, RES_HEALTH) + GetResource(this, RES_ARMOR)) - (GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR))) / 150;
t = bound(0, 1 + t, 3);
if (skill > 3)
{
#pragma once
+
+const float BOT_RATING_ENEMY = 2500;
+
+.float bot_ratingscale;
+.float bot_ratingscale_time;
+.float havocbot_role_timeout;
+
+.void(entity this) havocbot_previous_role;
+.void(entity this) havocbot_role;
return this.bot_strategytime < time;
}
+void navigation_goalrating_timeout_extend_if_needed(entity this, float seconds)
+{
+ this.bot_strategytime = max(this.bot_strategytime, time + seconds);
+}
+
#define MAX_CHASE_DISTANCE 700
bool navigation_goalrating_timeout_can_be_anticipated(entity this)
{
vector pm2 = ent.origin + ent.maxs;
// do two scans, because box test is cheaper
- IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+ IL_EACH(g_waypoints, it != ent && it != except && !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
{
if(boxesoverlap(pm1, pm2, it.absmin, it.absmax))
{
waypoint_clearlinks(ent); // initialize wpXXmincost fields
IL_EACH(g_waypoints, it != ent,
{
- if(walkfromwp && (it.wpflags & WAYPOINTFLAG_NORELINK))
+ if (walkfromwp && (it.wpflags & WPFLAGMASK_NORELINK))
continue;
set_tracewalk_dest(ent, it.origin, false);
// box check failed, try walk
IL_EACH(g_waypoints, it != ent,
{
- if(walkfromwp && (it.wpflags & WAYPOINTFLAG_NORELINK))
+ if (walkfromwp && (it.wpflags & WPFLAGMASK_NORELINK))
continue;
v = it.origin;
next = this.goalstack01;
// if for some reason the bot is closer to the next goal, pop the current one
- if (!IS_MOVABLE(next) // already checked in the previous case
+ if (!IS_MOVABLE(next) && !(this.goalcurrent.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP))
&& vlen2(this.goalcurrent.origin - next.origin) > vlen2(next.origin - this.origin)
&& checkpvs(this.origin + this.view_ofs, next))
{
if(vdist(wp.origin - this.origin, >, 50))
{
wp = NULL;
- IL_EACH(g_waypoints, !(it.wpflags & WAYPOINTFLAG_TELEPORT),
+ IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_TELEPORT | WAYPOINTFLAG_JUMP)),
{
if(vdist(it.origin - this.origin, <, 50))
{
vector jumpstepheightvec;
vector stepheightvec;
vector jumpheight_vec;
+float jumpheight_time;
entity navigation_bestgoal;
.float goalcurrent_distance_2d;
.float goalcurrent_distance_time;
+// final goal (item, object or player) is also saved in this field
+.entity goalentity;
.float goalentity_lock_timeout;
.bool goalentity_shouldbefrozen;
#include <common/constants.qh>
#include <common/debug.qh>
+#include <common/mapobjects/trigger/jumppads.qh>
#include <common/net_linked.qh>
#include <common/physics/player.qh>
return new_org;
}
+void crosshair_trace_waypoints(entity pl);
+void waypoint_lock(entity pl)
+{
+ crosshair_trace_waypoints(pl);
+ pl.wp_locked = trace_ent;
+}
+
+bool waypoint_has_hardwiredlinks(entity wp)
+{
+ if (!wp)
+ return false;
+ return (wp.wphw00 != NULL);
+}
+
+bool waypoint_is_hardwiredlink(entity wp_from, entity wp_to)
+{
+ if (!(wp_from && wp_to))
+ return false;
+
+ if (!wp_from.wphw00) return false; else if (wp_from.wphw00 == wp_to) return true;
+ if (!wp_from.wphw01) return false; else if (wp_from.wphw01 == wp_to) return true;
+ if (!wp_from.wphw02) return false; else if (wp_from.wphw02 == wp_to) return true;
+ if (!wp_from.wphw03) return false; else if (wp_from.wphw03 == wp_to) return true;
+ if (!wp_from.wphw04) return false; else if (wp_from.wphw04 == wp_to) return true;
+ if (!wp_from.wphw05) return false; else if (wp_from.wphw05 == wp_to) return true;
+ if (!wp_from.wphw06) return false; else if (wp_from.wphw06 == wp_to) return true;
+ if (!wp_from.wphw07) return false; else if (wp_from.wphw07 == wp_to) return true;
+
+ return false;
+}
+
+void waypoint_setupmodel(entity wp);
+void waypoint_mark_hardwiredlink(entity wp_from, entity wp_to)
+{
+ if (!(wp_from && wp_to))
+ return;
+
+ if (!wp_from.wphw00 || wp_from.wphw00 == wp_to) { wp_from.wphw00 = wp_to; waypoint_setupmodel(wp_from); return; }
+ if (!wp_from.wphw01 || wp_from.wphw01 == wp_to) { wp_from.wphw01 = wp_to; return; }
+ if (!wp_from.wphw02 || wp_from.wphw02 == wp_to) { wp_from.wphw02 = wp_to; return; }
+ if (!wp_from.wphw03 || wp_from.wphw03 == wp_to) { wp_from.wphw03 = wp_to; return; }
+ if (!wp_from.wphw04 || wp_from.wphw04 == wp_to) { wp_from.wphw04 = wp_to; return; }
+ if (!wp_from.wphw05 || wp_from.wphw05 == wp_to) { wp_from.wphw05 = wp_to; return; }
+ if (!wp_from.wphw06 || wp_from.wphw06 == wp_to) { wp_from.wphw06 = wp_to; return; }
+ if (!wp_from.wphw07 || wp_from.wphw07 == wp_to) { wp_from.wphw07 = wp_to; return; }
+
+ return;
+}
+
+void waypoint_unmark_hardwiredlink(entity wp_from, entity wp_to)
+{
+ if (!(wp_from && wp_to))
+ return;
+
+ int removed = -1;
+ if (removed < 0 && wp_from.wphw00 == wp_to) removed = 0;
+ if (removed < 0 && wp_from.wphw01 == wp_to) removed = 1;
+ if (removed < 0 && wp_from.wphw02 == wp_to) removed = 2;
+ if (removed < 0 && wp_from.wphw03 == wp_to) removed = 3;
+ if (removed < 0 && wp_from.wphw04 == wp_to) removed = 4;
+ if (removed < 0 && wp_from.wphw05 == wp_to) removed = 5;
+ if (removed < 0 && wp_from.wphw06 == wp_to) removed = 6;
+ if (removed < 0 && wp_from.wphw07 == wp_to) removed = 7;
+
+ if (removed >= 0)
+ {
+ if (removed <= 0) wp_from.wphw00 = wp_from.wphw01;
+ if (removed <= 1) wp_from.wphw01 = wp_from.wphw02;
+ if (removed <= 2) wp_from.wphw02 = wp_from.wphw03;
+ if (removed <= 3) wp_from.wphw03 = wp_from.wphw04;
+ if (removed <= 4) wp_from.wphw04 = wp_from.wphw05;
+ if (removed <= 5) wp_from.wphw05 = wp_from.wphw06;
+ if (removed <= 6) wp_from.wphw06 = wp_from.wphw07;
+ if (removed <= 7) wp_from.wphw07 = NULL;
+ if (!wp_from.wphw00)
+ waypoint_setupmodel(wp_from);
+ }
+
+ return;
+}
+
void waypoint_setupmodel(entity wp)
{
if (autocvar_g_waypointeditor)
setsize(wp, m1, m2);
wp.effects = EF_LOWPRECISION;
if (wp.wpflags & WAYPOINTFLAG_ITEM)
- wp.colormod = '1 0 0';
+ wp.colormod = '1 0 0'; // red
else if (wp.wpflags & WAYPOINTFLAG_GENERATED)
- wp.colormod = '1 1 0';
- else if (wp.wphardwired)
- wp.colormod = '0.5 0 1';
+ wp.colormod = '1 1 0'; // yellow
+ else if (wp.wpflags & WAYPOINTFLAG_SUPPORT)
+ wp.colormod = '0 1 0'; // green
+ else if (wp.wpflags & WAYPOINTFLAG_CUSTOM_JP)
+ wp.colormod = '1 0.5 0'; // orange
+ else if (wp.wpflags & WAYPOINTFLAG_TELEPORT)
+ wp.colormod = '1 0.5 0'; // orange
+ else if (wp.wpflags & WAYPOINTFLAG_LADDER)
+ wp.colormod = '1 0.5 0'; // orange
+ else if (wp.wpflags & WAYPOINTFLAG_JUMP)
+ wp.colormod = '1 0.5 0'; // orange
+ else if (wp.wpflags & WAYPOINTFLAG_CROUCH)
+ wp.colormod = '0 1 1'; // cyan
+ else if (waypoint_has_hardwiredlinks(wp))
+ wp.colormod = '0.5 0 1'; // purple
else
wp.colormod = '1 1 1';
}
wp.model = "";
}
+string waypoint_get_type_name(entity wp)
+{
+ if (wp.wpflags & WAYPOINTFLAG_ITEM) return "^1Item waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_CROUCH) return "^5Crouch waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_JUMP) return "^xf80Jump waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_SUPPORT) return "^2Support waypoint";
+ else if (waypoint_has_hardwiredlinks(wp)) return "^x80fHardwired waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_LADDER) return "^3Ladder waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_TELEPORT)
+ {
+ if (!wp.wpisbox) return "^3Warpzone waypoint";
+ else if (wp.wpflags & WAYPOINTFLAG_CUSTOM_JP) return "^3Custom jumppad waypoint";
+ else
+ {
+ IL_EACH(g_jumppads, boxesoverlap(wp.absmin, wp.absmax, it.absmin, it.absmax),
+ { return "^3Jumppad waypoint"; });
+ return "^3Teleport waypoint";
+ }
+ }
+
+ return "^7Waypoint";
+}
+
+entity waypoint_get(vector m1, vector m2)
+{
+ if (m1 == m2)
+ {
+ m1 -= '8 8 8';
+ m2 += '8 8 8';
+ }
+ IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax), { return it; });
+
+ return NULL;
+}
+
+.float createdtime;
entity waypoint_spawn(vector m1, vector m2, float f)
{
if(!(f & (WAYPOINTFLAG_PERSONAL | WAYPOINTFLAG_GENERATED)) && m1 == m2)
{
- vector em1 = m1 - '8 8 8';
- vector em2 = m2 + '8 8 8';
- IL_EACH(g_waypoints, boxesoverlap(em1, em2, it.absmin, it.absmax),
- {
- return it;
- });
+ entity wp_found = waypoint_get(m1, m2);
+ if (wp_found)
+ return wp_found;
}
// 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 | WAYPOINTFLAG_PERSONAL)) && m1 == m2)
+ if((f & WAYPOINTFLAG_GENERATED) && !(f & (WPFLAGMASK_NORELINK | WAYPOINTFLAG_PERSONAL)) && m1 == m2)
{
IL_EACH(g_waypoints, boxesoverlap(m1, m2, it.absmin, it.absmax),
{
w.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_PLAYERCLIP | DPCONTENTS_BOTCLIP;
w.wpflags = f;
w.solid = SOLID_TRIGGER;
+ w.createdtime = time;
setorigin(w, (m1 + m2) * 0.5);
setsize(w, m1 - w.origin, m2 - w.origin);
if (w.size)
if(!w.wpisbox)
{
- setsize(w, PL_MIN_CONST - '1 1 0', PL_MAX_CONST + '1 1 0');
+ if (f & WAYPOINTFLAG_CROUCH)
+ setsize(w, PL_CROUCH_MIN_CONST - '1 1 0', PL_CROUCH_MAX_CONST + '1 1 0');
+ else
+ setsize(w, PL_MIN_CONST - '1 1 0', PL_MAX_CONST + '1 1 0');
if(!move_out_of_solid(w))
{
if(!(f & WAYPOINTFLAG_GENERATED))
return w;
}
-void waypoint_spawn_fromeditor(entity pl)
+float trigger_push_get_push_time(entity this, vector endpos);
+void waypoint_addlink_for_custom_jumppad(entity wp_from, entity wp_to)
{
- entity e;
+ entity jp = NULL;
+ IL_EACH(g_jumppads, boxesoverlap(wp_from.absmin, wp_from.absmax, it.absmin, it.absmax),
+ {
+ jp = it;
+ break;
+ });
+ if (!jp)
+ return;
+
+ float cost = trigger_push_get_push_time(jp, wp_to.origin);
+ wp_from.wp00 = wp_to;
+ wp_from.wp00mincost = cost;
+ jp.nearestwaypoint = wp_from;
+ jp.nearestwaypointtimeout = -1;
+}
+
+bool start_wp_is_spawned;
+vector start_wp_origin;
+bool start_wp_is_hardwired;
+bool start_wp_is_support;
+
+void waypoint_clear_start_wp_globals(entity pl, bool warn)
+{
+ start_wp_is_spawned = false;
+ start_wp_origin = '0 0 0';
+ pl.wp_locked = NULL;
+ start_wp_is_hardwired = false;
+ start_wp_is_support = false;
+ if (warn)
+ LOG_INFO("^xf80Start waypoint has been cleared.\n");
+}
+
+void waypoint_start_hardwiredlink(entity pl, bool at_crosshair)
+{
+ entity wp = pl.nearestwaypoint;
+ if (at_crosshair)
+ {
+ crosshair_trace_waypoints(pl);
+ wp = trace_ent;
+ }
+ string err = "";
+ if (start_wp_is_spawned && !start_wp_is_hardwired)
+ err = "can't hardwire while in the process of creating a special link";
+ else if (!wp)
+ {
+ if (at_crosshair)
+ err = "couldn't find any waypoint at crosshair";
+ else
+ err = "couldn't find any waypoint nearby";
+ }
+ else if (wp.wpflags & WPFLAGMASK_NORELINK)
+ err = "can't hardwire a waypoint with special links";
+
+ if (err == "")
+ {
+ start_wp_is_hardwired = true;
+ start_wp_is_spawned = true;
+ start_wp_origin = wp.origin;
+ pl.wp_locked = wp;
+ LOG_INFOF("^x80fWaypoint %s marked as hardwired link origin.\n", vtos(wp.origin));
+ }
+ else
+ {
+ start_wp_is_hardwired = false;
+ LOG_INFO("Error: ", err, "\n");
+ }
+}
+
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp)
+{
+ if (WAYPOINT_VERSION < waypoint_version_loaded)
+ {
+ LOG_INFOF("^1Editing waypoints with a higher version number (%f) is not allowed.\n"
+ "Update Xonotic to make them editable.", waypoint_version_loaded);
+ return;
+ }
+
+ entity e = NULL, jp = NULL;
vector org = pl.origin;
+ if (at_crosshair)
+ {
+ crosshair_trace_waypoints(pl);
+ org = trace_endpos;
+ if (!trace_ent)
+ org.z -= PL_MIN_CONST.z;
+ if (!(start_wp_is_hardwired || start_wp_is_support))
+ IL_EACH(g_jumppads, boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
+ {
+ jp = it;
+ break;
+ });
+ if (!jp && !start_wp_is_spawned && trace_ent)
+ {
+ if (trace_ent.wpflags & (WAYPOINTFLAG_JUMP))
+ is_jump_wp = true;
+ else if (trace_ent.wpflags & (WAYPOINTFLAG_SUPPORT))
+ is_support_wp = true;
+ }
+ }
+ if (jp || is_jump_wp || is_support_wp)
+ {
+ if (start_wp_is_spawned)
+ start_wp_is_spawned = false;
+ LOG_INFO("^xf80Spawning start waypoint...\n");
+ }
int ctf_flags = havocbot_symmetry_origin_order;
bool sym = ((autocvar_g_waypointeditor_symmetrical > 0 && ctf_flags >= 2)
|| (autocvar_g_waypointeditor_symmetrical < 0));
ctf_flags = 2;
int wp_num = ctf_flags;
- if(!PHYS_INPUT_BUTTON_CROUCH(pl))
+ if(!PHYS_INPUT_BUTTON_CROUCH(pl) && !at_crosshair && !is_jump_wp && !is_support_wp)
{
// snap waypoint to item's origin if close enough
IL_EACH(g_items, true,
});
}
+ vector start_org = '0 0 0';
+ if (start_wp_is_spawned)
+ {
+ if (!start_wp_is_hardwired)
+ LOG_INFO("^xf80Spawning destination waypoint...\n");
+ start_org = start_wp_origin;
+ }
+
+ // save org as it can be modified spawning symmetrycal waypoints
+ vector initial_origin = '0 0 0';
+ bool initial_origin_is_set = false;
+
LABEL(add_wp);
- e = waypoint_spawn(org, org, 0);
+
+ if (jp)
+ {
+ e = NULL;
+ IL_EACH(g_waypoints, (it.wpflags & WPFLAGMASK_NORELINK)
+ && boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
+ {
+ e = it; break;
+ });
+ if (!e)
+ e = waypoint_spawn(jp.absmin - PL_MAX_CONST + '1 1 1', jp.absmax - PL_MIN_CONST + '-1 -1 -1', WAYPOINTFLAG_TELEPORT);
+ if (!pl.wp_locked)
+ pl.wp_locked = e;
+ }
+ else if (is_jump_wp || is_support_wp)
+ {
+ int type_flag = (is_jump_wp) ? WAYPOINTFLAG_JUMP : WAYPOINTFLAG_SUPPORT;
+
+ entity wp_found = waypoint_get(org, org);
+ if (wp_found && !(wp_found.wpflags & type_flag))
+ {
+ LOG_INFOF("Error: can't spawn a %s waypoint over an existent waypoint of a different type\n", (is_jump_wp) ? "Jump" : "Support");
+ return;
+ }
+ e = waypoint_spawn(org, org, type_flag);
+ if (!pl.wp_locked)
+ pl.wp_locked = e;
+ }
+ else
+ e = waypoint_spawn(org, org, (is_crouch_wp) ? WAYPOINTFLAG_CROUCH : 0);
if(!e)
{
LOG_INFOF("Couldn't spawn waypoint at %v\n", org);
+ if (start_wp_is_spawned)
+ waypoint_clear_start_wp_globals(pl, true);
return;
}
- waypoint_schedulerelink(e);
- bprint(strcat("Waypoint spawned at ", vtos(e.origin), "\n"));
- if(sym)
+
+ if (!initial_origin_is_set)
+ {
+ initial_origin = e.origin;
+ initial_origin_is_set = true;
+ }
+
+ entity start_wp = NULL;
+ if (start_wp_is_spawned)
+ {
+ IL_EACH(g_waypoints, (start_wp_is_hardwired || (it.wpflags & WPFLAGMASK_NORELINK))
+ && boxesoverlap(start_org, start_org, it.absmin, it.absmax),
+ {
+ start_wp = it; break;
+ });
+ if(!start_wp)
+ {
+ // should not happen
+ LOG_INFOF("Couldn't find start waypoint at %v\n", start_org);
+ waypoint_clear_start_wp_globals(pl, true);
+ return;
+ }
+ if (start_wp_is_hardwired)
+ {
+ if (waypoint_is_hardwiredlink(start_wp, e))
+ {
+ waypoint_unmark_hardwiredlink(start_wp, e);
+ waypoint_removelink(start_wp, e);
+ string s = strcat(vtos(start_wp.origin), "*", vtos(e.origin));
+ LOG_INFOF("^x80fRemoved hardwired link %s.\n", s);
+ }
+ else
+ {
+ if (e.createdtime == time)
+ {
+ LOG_INFO("Error: hardwired links can be created only between 2 existing (and unconnected) waypoints.\n");
+ waypoint_remove(e);
+ waypoint_clear_start_wp_globals(pl, true);
+ waypoint_spawn_fromeditor(pl, at_crosshair, is_jump_wp, is_crouch_wp, is_support_wp);
+ return;
+ }
+ if (start_wp == e)
+ {
+ LOG_INFO("Error: start and destination waypoints coincide.\n");
+ waypoint_clear_start_wp_globals(pl, true);
+ return;
+ }
+ if (waypoint_islinked(start_wp, e))
+ {
+ LOG_INFO("Error: waypoints are already linked.\n");
+ waypoint_clear_start_wp_globals(pl, true);
+ return;
+ }
+ waypoint_addlink(start_wp, e);
+ waypoint_mark_hardwiredlink(start_wp, e);
+ string s = strcat(vtos(start_wp.origin), "*", vtos(e.origin));
+ LOG_INFOF("^x80fAdded hardwired link %s.\n", s);
+ }
+ }
+ else
+ {
+ if (start_wp_is_support)
+ {
+ if (e.SUPPORT_WP)
+ {
+ LOG_INFOF("Waypoint %v has already a support waypoint, delete it first.\n", e.origin);
+ waypoint_clear_start_wp_globals(pl, true);
+ return;
+ }
+ // clear all links to e
+ IL_EACH(g_waypoints, it != e,
+ {
+ if (waypoint_islinked(it, e) && !waypoint_is_hardwiredlink(it, e))
+ waypoint_removelink(it, e);
+ });
+ }
+ waypoint_addlink(start_wp, e);
+ }
+ }
+
+ if (!(jp || is_jump_wp || is_support_wp || start_wp_is_hardwired))
+ waypoint_schedulerelink(e);
+
+ string wp_type_str = waypoint_get_type_name(e);
+
+ bprint(strcat(wp_type_str, "^7 spawned at ", vtos(e.origin), "\n"));
+
+ if (start_wp_is_spawned)
+ {
+ pl.wp_locked = NULL;
+ if (!start_wp_is_hardwired)
+ waypoint_schedulerelink(start_wp);
+ if (start_wp.wpflags & WAYPOINTFLAG_TELEPORT)
+ {
+ if (start_wp.wp00_original == start_wp.wp00)
+ start_wp.wpflags &= ~WAYPOINTFLAG_CUSTOM_JP;
+ else
+ start_wp.wpflags |= WAYPOINTFLAG_CUSTOM_JP;
+ }
+ }
+
+ if (sym)
{
- org = waypoint_getSymmetricalPoint(e.origin, ctf_flags);
+ org = waypoint_getSymmetricalPoint(org, ctf_flags);
+ if (jp)
+ {
+ IL_EACH(g_jumppads, boxesoverlap(org + PL_MIN_CONST, org + PL_MAX_CONST, it.absmin, it.absmax),
+ {
+ jp = it; break;
+ });
+ }
+ if (start_wp_is_spawned)
+ start_org = waypoint_getSymmetricalPoint(start_org, ctf_flags);
if (vdist(org - pl.origin, >, 32))
{
if(wp_num > 2)
goto add_wp;
}
}
+ if (jp || is_jump_wp || is_support_wp)
+ {
+ if (!start_wp_is_spawned)
+ {
+ // we've just created a custom jumppad waypoint
+ // the next one created by the user will be the destination waypoint
+ start_wp_is_spawned = true;
+ start_wp_origin = initial_origin;
+ if (is_support_wp)
+ start_wp_is_support = true;
+ }
+ }
+ else if (start_wp_is_spawned)
+ {
+ waypoint_clear_start_wp_globals(pl, false);
+ }
}
void waypoint_remove(entity wp)
{
IL_EACH(g_waypoints, it != wp,
{
+ if (it.SUPPORT_WP == wp)
+ {
+ it.SUPPORT_WP = NULL;
+ waypoint_schedulerelink(it); // restore incoming links
+ }
if (waypoint_islinked(it, wp))
+ {
+ if (waypoint_is_hardwiredlink(it, wp))
+ waypoint_unmark_hardwiredlink(it, wp);
waypoint_removelink(it, wp);
+ }
});
delete(wp);
}
void waypoint_remove_fromeditor(entity pl)
{
+ if (WAYPOINT_VERSION < waypoint_version_loaded)
+ {
+ LOG_INFOF("^1Editing waypoints with a higher version number (%f) is not allowed.\n"
+ "Update Xonotic to make them editable.", waypoint_version_loaded);
+ return;
+ }
+
entity e = navigation_findnearestwaypoint(pl, false);
int ctf_flags = havocbot_symmetry_origin_order;
LABEL(remove_wp);
if (!e) return;
- if (e.wpflags & WAYPOINTFLAG_GENERATED) return;
- if (e.wphardwired)
+ if (e.wpflags & WAYPOINTFLAG_GENERATED)
{
- LOG_INFO("^1Warning: ^7Removal of hardwired waypoints is not allowed in the editor. Please remove links from/to this waypoint (", vtos(e.origin), ") by hand from maps/", mapname, ".waypoints.hardwired\n");
+ if (start_wp_is_spawned)
+ waypoint_clear_start_wp_globals(pl, true);
+ return;
+ }
+
+ if (waypoint_has_hardwiredlinks(e))
+ {
+ LOG_INFO("Can't remove a waypoint with hardwired links, remove links with \"wpeditor hardwire\" first\n");
return;
}
}
bprint(strcat("Waypoint removed at ", vtos(e.origin), "\n"));
+ te_explosion(e.origin);
waypoint_remove(e);
if (sym && wp_sym)
sym = false;
goto remove_wp;
}
+
+ if (start_wp_is_spawned)
+ waypoint_clear_start_wp_globals(pl, true);
}
void waypoint_removelink(entity from, entity to)
{
- if (from == to || (from.wpflags & WAYPOINTFLAG_NORELINK))
+ if (from == to || ((from.wpflags & WPFLAGMASK_NORELINK) && !(from.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT))))
return;
entity fromwp31_prev = from.wp31;
return dist / (autocvar_sv_maxspeed * 1.25);
return dist / autocvar_sv_maxspeed;
}
+
float waypoint_getlinearcost_underwater(float dist)
{
// NOTE: underwater speed factor is hardcoded in the engine too, see SV_WaterMove
return dist / (autocvar_sv_maxspeed * 0.7);
}
+float waypoint_getlinearcost_crouched(float dist)
+{
+ return dist / (autocvar_sv_maxspeed * 0.5);
+}
+
float waypoint_gettravelcost(vector from, vector to, entity from_ent, entity to_ent)
{
bool submerged_from = navigation_check_submerged_state(from_ent, from);
if (submerged_from && submerged_to)
return waypoint_getlinearcost_underwater(vlen(to - from));
+ if ((from_ent.wpflags & WAYPOINTFLAG_CROUCH) && (to_ent.wpflags & WAYPOINTFLAG_CROUCH))
+ return waypoint_getlinearcost_crouched(vlen(to - from));
+
float c = waypoint_getlinearcost(vlen(to - from));
float height = from.z - to.z;
if(height > jumpheight_vec.z && autocvar_sv_gravity > 0)
{
- float height_cost = sqrt(height / (autocvar_sv_gravity / 2));
+ float height_cost; // fall cost
+ if (from_ent.wpflags & WAYPOINTFLAG_JUMP)
+ height_cost = jumpheight_time + sqrt((height + jumpheight_vec.z) / (autocvar_sv_gravity / 2));
+ else
+ height_cost = sqrt(height / (autocvar_sv_gravity / 2));
c = waypoint_getlinearcost(vlen(vec2(to - from))); // xy distance cost
if(height_cost > c)
c = height_cost;
}
+ // consider half path underwater
if (submerged_from || submerged_to)
return (c + waypoint_getlinearcost_underwater(vlen(to - from))) / 2;
+
+ // consider half path crouched
+ if ((from_ent.wpflags & WAYPOINTFLAG_CROUCH) || (to_ent.wpflags & WAYPOINTFLAG_CROUCH))
+ return (c + waypoint_getlinearcost_crouched(vlen(to - from))) / 2;
+
return c;
}
{
if (from == to || waypoint_islinked(from, to))
return;
- if (c == -1 && (from.wpflags & WAYPOINTFLAG_NORELINK))
+ if (c == -1 && (from.wpflags & WPFLAGMASK_NORELINK) && !(from.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT)))
return;
if(c == -1)
void waypoint_addlink(entity from, entity to)
{
- waypoint_addlink_customcost(from, to, -1);
+ if ((from.wpflags & WPFLAGMASK_NORELINK) && !(from.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT)))
+ waypoint_addlink_for_custom_jumppad(from, to);
+ else
+ waypoint_addlink_customcost(from, to, -1);
+
+ if (from.wpflags & WAYPOINTFLAG_SUPPORT)
+ to.SUPPORT_WP = from;
}
// relink this spawnfunc_waypoint
{
if (boxesoverlap(this.absmin, this.absmax, it.absmin, it.absmax))
{
- waypoint_addlink(this, it);
- waypoint_addlink(it, this);
+ if (!(this.wpflags & WPFLAGMASK_NORELINK))
+ waypoint_addlink(this, it);
+ if (!(it.wpflags & WPFLAGMASK_NORELINK))
+ waypoint_addlink(it, this);
}
else
{
dv = ev - sv;
dv.z = 0;
- if(vdist(dv, >=, 1050)) // max search distance in XY
+ int maxdist = 1050;
+ vector m1 = PL_MIN_CONST;
+ vector m2 = PL_MAX_CONST;
+
+ if ((this.wpflags & WAYPOINTFLAG_CROUCH) || (it.wpflags & WAYPOINTFLAG_CROUCH))
+ {
+ m1 = PL_CROUCH_MIN_CONST;
+ m2 = PL_CROUCH_MAX_CONST;
+ // links from crouch wp to normal wp (and viceversa) are very short to avoid creating many links
+ // that would be wasted due to rough travel cost calculation (the longer link is, the higher cost is)
+ // links from crouch wp to crouch wp can be as long as normal links
+ if (!((this.wpflags & WAYPOINTFLAG_CROUCH) && (it.wpflags & WAYPOINTFLAG_CROUCH)))
+ maxdist = 100;
+ }
+
+ if (vdist(dv, >=, maxdist)) // max search distance in XY
{
++relink_lengthculled;
continue;
//traceline(this.origin, it.origin, false, NULL);
//if (trace_fraction == 1)
- if (this.wpisbox)
+ if (this.wpisbox || (this.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT)) // forbid outgoing links
+ || it.SUPPORT_WP) // forbid incoming links
+ {
relink_walkculled += 0.5;
+ }
else
{
- if (tracewalk(this, sv, PL_MIN_CONST, PL_MAX_CONST, ev2, ev2_height, MOVE_NOMONSTERS))
+ if (tracewalk(this, sv, m1, m2, ev2, ev2_height, MOVE_NOMONSTERS))
waypoint_addlink(this, it);
else
relink_walkculled += 0.5;
}
- if (it.wpisbox)
+ // reverse direction
+ if (it.wpisbox || (it.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT)) // forbid incoming links
+ || this.SUPPORT_WP) // forbid outgoing links
+ {
relink_walkculled += 0.5;
+ }
else
{
- if (tracewalk(this, ev, PL_MIN_CONST, PL_MAX_CONST, sv2, sv2_height, MOVE_NOMONSTERS))
+ if (tracewalk(this, ev, m1, m2, sv2, sv2_height, MOVE_NOMONSTERS))
waypoint_addlink(it, this);
else
relink_walkculled += 0.5;
navigation_testtracewalk = 0;
this.wplinked = true;
this.dphitcontentsmask = dphitcontentsmask_save;
+
+ setthink(this, func_null);
+ this.nextthink = 0;
}
void waypoint_clearlinks(entity wp)
wp.enemy = NULL;
if (!(wp.wpflags & WAYPOINTFLAG_PERSONAL))
wp.owner = NULL;
- if (!(wp.wpflags & WAYPOINTFLAG_NORELINK))
+ if (!(wp.wpflags & WPFLAGMASK_NORELINK))
waypoint_clearlinks(wp);
// schedule an actual relink on next frame
setthink(wp, waypoint_think);
{
waypoint_schedulerelink(it);
});
- waypoint_load_links_hardwired();
+ waypoint_load_hardwiredlinks();
}
#define GET_GAMETYPE_EXTENSION() ((g_race) ? ".race" : "")
++c;
waypoint_addlink(wp_from, wp_to);
+ if (wp_from.wp00_original && wp_from.wp00_original != wp_from.wp00)
+ wp_from.wpflags |= WAYPOINTFLAG_CUSTOM_JP;
}
fclose(file);
return true;
}
-void waypoint_load_or_remove_links_hardwired(bool removal_mode)
+void waypoint_load_hardwiredlinks()
{
string s;
float file, tokens, c = 0, found;
if (file < 0)
{
- if(!removal_mode)
- LOG_TRACE("waypoint links load from ", filename, " failed");
+ LOG_TRACE("waypoint links load from ", filename, " failed");
return;
}
+ bool is_special = false;
while ((s = fgets(file)))
{
if(substring(s, 0, 2)=="//")
if(substring(s, 0, 1)=="#")
continue;
+ // special links start with *, so old xonotic versions don't load them
+ is_special = false;
+ if (substring(s, 0, 1) == "*")
+ {
+ is_special = true;
+ s = substring(s, 1, -1);
+ }
+
tokens = tokenizebyseparator(s, "*");
if (tokens!=2)
if(!found)
{
- if(!removal_mode)
- LOG_INFO("NOTICE: Can not find origin waypoint for the hardwired link ", s, ". Path skipped");
+ s = strcat(((is_special) ? "special link " : "hardwired link "), s);
+ LOG_INFO("NOTICE: Can not find origin waypoint of the ", s, ". Path skipped");
continue;
}
}
if(!found)
{
- if(!removal_mode)
- LOG_INFO("NOTICE: Can not find destination waypoint for the hardwired link ", s, ". Path skipped");
+ s = strcat(((is_special) ? "special link " : "hardwired link "), s);
+ LOG_INFO("NOTICE: Can not find destination waypoint of the ", s, ". Path skipped");
continue;
}
++c;
- if(removal_mode)
+
+ if (!is_special)
{
- waypoint_removelink(wp_from, wp_to);
- continue;
+ waypoint_addlink(wp_from, wp_to);
+ waypoint_mark_hardwiredlink(wp_from, wp_to);
+ } else if (wp_from.wpflags & WPFLAGMASK_NORELINK
+ && ((wp_from.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT))
+ || (wp_from.wpisbox && wp_from.wpflags & WAYPOINTFLAG_TELEPORT)))
+ {
+ waypoint_addlink(wp_from, wp_to);
}
-
- waypoint_addlink(wp_from, wp_to);
- wp_from.wphardwired = true;
- wp_to.wphardwired = true;
- waypoint_setupmodel(wp_from);
- waypoint_setupmodel(wp_to);
}
fclose(file);
- LOG_TRACE(((removal_mode) ? "unloaded " : "loaded "),
- ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired");
+ LOG_TRACE("loaded ", ftos(c), " waypoint links from maps/", mapname, ".waypoints.hardwired");
}
entity waypoint_get_link(entity w, float i)
}
}
+// Save all hardwired waypoint links to a file
+void waypoint_save_hardwiredlinks()
+{
+ string gt_ext = GET_GAMETYPE_EXTENSION();
+
+ string filename = sprintf("maps/%s.waypoints.hardwired", strcat(mapname, gt_ext));
+ int file = fopen(filename, FILE_WRITE);
+ if (file < 0)
+ {
+ LOG_TRACE("waypoint hardwired links ", filename, " creation failed");
+ return;
+ }
+
+ // write hardwired links to file
+ int count = 0;
+ fputs(file, "// HARDWIRED LINKS\n");
+ IL_EACH(g_waypoints, waypoint_has_hardwiredlinks(it),
+ {
+ for (int j = 0; j < 32; ++j)
+ {
+ entity link = waypoint_get_link(it, j);
+ if (waypoint_is_hardwiredlink(it, link))
+ {
+ // NOTE: vtos rounds vector components to 1 decimal place
+ string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
+ fputs(file, s);
+ ++count;
+ }
+ }
+ });
+
+ // write special links to file
+ int count2 = 0;
+ fputs(file, "\n// SPECIAL LINKS\n");
+ IL_EACH(g_waypoints, it.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT | WAYPOINTFLAG_CUSTOM_JP),
+ {
+ for (int j = 0; j < 32; ++j)
+ {
+ entity link = waypoint_get_link(it, j);
+ if (link)
+ {
+ // NOTE: vtos rounds vector components to 1 decimal place
+ string s = strcat("*", vtos(it.origin), "*", vtos(link.origin), "\n");
+ fputs(file, s);
+ ++count2;
+ }
+ }
+ });
+
+ fclose(file);
+
+ LOG_INFOF("saved %d hardwired links and %d special links to %s", count, count2, filename);
+}
+
// Save all waypoint links to a file
void waypoint_save_links()
{
- // temporarily remove hardwired links so they don't get saved among normal links
- waypoint_remove_links_hardwired();
-
string gt_ext = GET_GAMETYPE_EXTENSION();
string filename = sprintf("maps/%s.waypoints.cache", strcat(mapname, gt_ext));
fputs(file, strcat("//", "WAYPOINT_TIME ", waypoint_time, "\n"));
int c = 0;
- IL_EACH(g_waypoints, true,
+ IL_EACH(g_waypoints, !(it.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT | WAYPOINTFLAG_CUSTOM_JP)),
{
for(int j = 0; j < 32; ++j)
{
entity link = waypoint_get_link(it, j);
- if(link)
+ if (link && !waypoint_is_hardwiredlink(it, link))
{
// NOTE: vtos rounds vector components to 1 decimal place
string s = strcat(vtos(it.origin), "*", vtos(link.origin), "\n");
botframe_cachedwaypointlinks = true;
LOG_INFOF("saved %d waypoint links to %s", c, filename);
-
- waypoint_load_links_hardwired();
}
// save waypoints to gamedir/data/maps/mapname.waypoints
void waypoint_saveall()
{
+ if (WAYPOINT_VERSION < waypoint_version_loaded)
+ {
+ LOG_INFOF("^1Overwriting waypoints with a higher version number (%f) is not allowed.\n"
+ "Update Xonotic to make them editable.", waypoint_version_loaded);
+ return;
+ }
string gt_ext = GET_GAMETYPE_EXTENSION();
string filename = sprintf("maps/%s.waypoints", strcat(mapname, gt_ext));
});
fclose(file);
waypoint_save_links();
+ waypoint_save_hardwiredlinks();
+
botframe_loadedforcedlinks = false;
+ waypoint_version_loaded = WAYPOINT_VERSION;
LOG_INFOF("saved %d waypoints to %s", c, filename);
}
float waypoint_loadall()
{
string s;
- float file, cwp, cwb, fl;
+ int file, cwp, cwb, fl;
vector m1, m2;
cwp = 0;
cwb = 0;
if (!s)
break;
fl = stof(s);
+ fl &= ~WAYPOINTFLAG_NORELINK__DEPRECATED;
waypoint_spawn(m1, m2, fl);
if (m1 == m2)
cwp = cwp + 1;
cwb = cwb + 1;
}
fclose(file);
+ waypoint_version_loaded = ver;
LOG_TRACE("loaded ", ftos(cwp), " waypoints and ", ftos(cwb), " wayboxes from maps/", mapname, ".waypoints");
if (autocvar_g_waypointeditor && autocvar_g_waypointeditor_symmetrical_allowload)
{
+ string sym_str = "";
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
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));
+ sym_str = strcat(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);
+ sym_str = strcat(ftos(sym), " with axis ", params);
}
else
- LOG_INFO("Waypoint editor: loaded symmetry ", ftos(sym));
+ sym_str = ftos(sym);
+ if (sym_str != "")
+ LOG_INFO("Waypoint editor: loaded symmetry ", sym_str);
LOG_INFO(strcat("g_waypointeditor_symmetrical", " has been set to ", cvar_string("g_waypointeditor_symmetrical")));
}
+ if (WAYPOINT_VERSION < waypoint_version_loaded)
+ LOG_INFOF("^1Editing waypoints with a higher version number (%f) is not allowed.\n"
+ "Update Xonotic to make them editable.", waypoint_version_loaded);
+
return cwp + cwb;
}
{
entity w;
entity dw;
- w = waypoint_spawn(org1, org2, WAYPOINTFLAG_GENERATED | teleport_flag | WAYPOINTFLAG_NORELINK);
+ w = waypoint_spawn(org1, org2, WAYPOINTFLAG_GENERATED | teleport_flag);
dw = waypoint_spawn(destination1, destination2, WAYPOINTFLAG_GENERATED);
// one way link to the destination
+ w.wp00_original = dw;
w.wp00 = dw;
w.wp00mincost = timetaken; // this is just for jump pads
// the teleporter's nearest spawnfunc_waypoint is this one
if (!(wp1 && wp2))
return;
- if (wp1.wphardwired && wp2.wphardwired)
+ if (waypoint_is_hardwiredlink(wp1, wp2) || (wp1.wpflags & (WAYPOINTFLAG_JUMP | WAYPOINTFLAG_SUPPORT | WAYPOINTFLAG_CUSTOM_JP)))
te_beam(NULL, wp1.origin, wp2.origin);
else if (display_type == 1)
te_lightning2(NULL, wp1.origin, wp2.origin);
void waypoint_showlinks_from(entity wp, int display_type)
{
- waypoint_showlink(wp.wp00, wp, display_type); waypoint_showlink(wp.wp16, wp, display_type);
- waypoint_showlink(wp.wp01, wp, display_type); waypoint_showlink(wp.wp17, wp, display_type);
- waypoint_showlink(wp.wp02, wp, display_type); waypoint_showlink(wp.wp18, wp, display_type);
- waypoint_showlink(wp.wp03, wp, display_type); waypoint_showlink(wp.wp19, wp, display_type);
- waypoint_showlink(wp.wp04, wp, display_type); waypoint_showlink(wp.wp20, wp, display_type);
- waypoint_showlink(wp.wp05, wp, display_type); waypoint_showlink(wp.wp21, wp, display_type);
- waypoint_showlink(wp.wp06, wp, display_type); waypoint_showlink(wp.wp22, wp, display_type);
- waypoint_showlink(wp.wp07, wp, display_type); waypoint_showlink(wp.wp23, wp, display_type);
- waypoint_showlink(wp.wp08, wp, display_type); waypoint_showlink(wp.wp24, wp, display_type);
- waypoint_showlink(wp.wp09, wp, display_type); waypoint_showlink(wp.wp25, wp, display_type);
- waypoint_showlink(wp.wp10, wp, display_type); waypoint_showlink(wp.wp26, wp, display_type);
- waypoint_showlink(wp.wp11, wp, display_type); waypoint_showlink(wp.wp27, wp, display_type);
- waypoint_showlink(wp.wp12, wp, display_type); waypoint_showlink(wp.wp28, wp, display_type);
- waypoint_showlink(wp.wp13, wp, display_type); waypoint_showlink(wp.wp29, wp, display_type);
- waypoint_showlink(wp.wp14, wp, display_type); waypoint_showlink(wp.wp30, wp, display_type);
- waypoint_showlink(wp.wp15, wp, display_type); waypoint_showlink(wp.wp31, wp, display_type);
+ waypoint_showlink(wp, wp.wp00, display_type); waypoint_showlink(wp, wp.wp16, display_type);
+ waypoint_showlink(wp, wp.wp01, display_type); waypoint_showlink(wp, wp.wp17, display_type);
+ waypoint_showlink(wp, wp.wp02, display_type); waypoint_showlink(wp, wp.wp18, display_type);
+ waypoint_showlink(wp, wp.wp03, display_type); waypoint_showlink(wp, wp.wp19, display_type);
+ waypoint_showlink(wp, wp.wp04, display_type); waypoint_showlink(wp, wp.wp20, display_type);
+ waypoint_showlink(wp, wp.wp05, display_type); waypoint_showlink(wp, wp.wp21, display_type);
+ waypoint_showlink(wp, wp.wp06, display_type); waypoint_showlink(wp, wp.wp22, display_type);
+ waypoint_showlink(wp, wp.wp07, display_type); waypoint_showlink(wp, wp.wp23, display_type);
+ waypoint_showlink(wp, wp.wp08, display_type); waypoint_showlink(wp, wp.wp24, display_type);
+ waypoint_showlink(wp, wp.wp09, display_type); waypoint_showlink(wp, wp.wp25, display_type);
+ waypoint_showlink(wp, wp.wp10, display_type); waypoint_showlink(wp, wp.wp26, display_type);
+ waypoint_showlink(wp, wp.wp11, display_type); waypoint_showlink(wp, wp.wp27, display_type);
+ waypoint_showlink(wp, wp.wp12, display_type); waypoint_showlink(wp, wp.wp28, display_type);
+ waypoint_showlink(wp, wp.wp13, display_type); waypoint_showlink(wp, wp.wp29, display_type);
+ waypoint_showlink(wp, wp.wp14, display_type); waypoint_showlink(wp, wp.wp30, display_type);
+ waypoint_showlink(wp, wp.wp15, display_type); waypoint_showlink(wp, wp.wp31, display_type);
}
void crosshair_trace_waypoints(entity pl)
setsize(it, '-16 -16 -16', '16 16 16');
});
- crosshair_trace(pl);
+ WarpZone_crosshair_trace(pl);
IL_EACH(g_waypoints, true, {
it.solid = SOLID_TRIGGER;
if (!it.wpisbox)
setsize(it, '0 0 0', '0 0 0');
});
+
if (trace_ent.classname != "waypoint")
trace_ent = NULL;
+ else if (!trace_ent.wpisbox)
+ trace_endpos = trace_ent.origin;
}
void botframe_showwaypointlinks()
it.wp_aimed = NULL;
if (wasfreed(it.wp_locked))
it.wp_locked = NULL;
- if (PHYS_INPUT_BUTTON_USE(it))
- it.wp_locked = it.wp_aimed;
entity head = it.wp_locked;
if (!head)
head = navigation_findnearestwaypoint(it, false);
it.nearestwaypointtimeout = time + 2; // while I'm at it...
if (IS_ONGROUND(it) || it.waterlevel > WATERLEVEL_NONE || it.wp_locked)
display_type = 1; // default
- else if(head && (head.wphardwired))
+ else if(waypoint_has_hardwiredlinks(head))
display_type = 2; // only hardwired
if (display_type)
wp = trace_ent;
if (wp != it.wp_aimed)
{
- str = sprintf("\necho ^2WP info^7: entity: %d, flags: %d, origin: '%s'\n", etof(wp), wp.wpflags, vtos(wp.origin));
+ string wp_type_str = waypoint_get_type_name(wp);
+ str = sprintf("\necho Entity %d: %s^7, flags: %d, origin: %s\n", etof(wp), wp_type_str, wp.wpflags, vtos(wp.origin));
if (wp.wpisbox)
- str = strcat(str, sprintf("echo \" absmin: '%s', absmax: '%s'\"\n", vtos(wp.absmin), vtos(wp.absmax)));
+ str = strcat(str, sprintf("echo \" absmin: %s, absmax: %s\"\n", vtos(wp.absmin), vtos(wp.absmax)));
stuffcmd(it, str);
- str = sprintf("entity: %d\nflags: %d\norigin: \'%s\'", etof(wp), wp.wpflags, vtos(wp.origin));
+ str = sprintf("Entity %d: %s^7\nflags: %d\norigin: %s", etof(wp), wp_type_str, wp.wpflags, vtos(wp.origin));
if (wp.wpisbox)
- str = strcat(str, sprintf(" \nabsmin: '%s'\nabsmax: '%s'", vtos(wp.absmin), vtos(wp.absmax)));
+ str = strcat(str, sprintf(" \nabsmin: %s\nabsmax: %s", vtos(wp.absmin), vtos(wp.absmax)));
debug_text_3d(wp.origin, str, 0, 7, '0 0 0');
}
}
}
float bestdist = maxdist;
- IL_EACH(g_waypoints, it != wp && !(it.wpflags & WAYPOINTFLAG_NORELINK),
+ IL_EACH(g_waypoints, it != wp && !(it.wpflags & WPFLAGMASK_NORELINK),
{
float d = vlen(wp.origin - it.origin) + vlen(it.origin - porg);
if(d < bestdist)
// 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
-const float WAYPOINT_VERSION = 1.02;
+const float WAYPOINT_VERSION = 1.04;
+float waypoint_version_loaded;
string waypoint_time;
// fields you can query using prvm_global server to get some statistics about waypoint linking culling
.entity wp00, wp01, wp02, wp03, wp04, wp05, wp06, wp07, wp08, wp09, wp10, wp11, wp12, wp13, wp14, wp15;
.entity wp16, wp17, wp18, wp19, wp20, wp21, wp22, wp23, wp24, wp25, wp26, wp27, wp28, wp29, wp30, wp31;
+// used by jumppads to store original destination wp, used in case it gets changed in the editor
+.entity wp00_original;
+
.float wp00mincost, wp01mincost, wp02mincost, wp03mincost, wp04mincost, wp05mincost, wp06mincost, wp07mincost;
.float wp08mincost, wp09mincost, wp10mincost, wp11mincost, wp12mincost, wp13mincost, wp14mincost, wp15mincost;
.float wp16mincost, wp17mincost, wp18mincost, wp19mincost, wp20mincost, wp21mincost, wp22mincost, wp23mincost;
.float wp24mincost, wp25mincost, wp26mincost, wp27mincost, wp28mincost, wp29mincost, wp30mincost, wp31mincost;
-.float wpfire, wpcost, wpconsidered, wpisbox, wplinked, wphardwired;
+// hardwired links are saved to the .wpXX fields among normal links
+// AND to the supporting .wphwXX fields to allow identifying them precisely
+// these links are not sorted, unlike normal links
+.entity wphw00, wphw01, wphw02, wphw03, wphw04, wphw05, wphw06, wphw07;
+
+.float wpcost;
+.int wpfire, wpconsidered, wpisbox, wplinked;
.int wpflags;
.entity wp_aimed;
.entity wp_locked;
.vector wpnearestpoint;
+// holds reference to the support waypoint, if any
+.entity goalentity;
+#define SUPPORT_WP goalentity
+
/*
* Functions
*/
spawnfunc(waypoint);
+
+bool waypoint_has_hardwiredlinks(entity wp);
+bool waypoint_is_hardwiredlink(entity wp_from, entity wp_to);
+void waypoint_mark_hardwiredlink(entity wp_from, entity wp_to);
+void waypoint_unmark_hardwiredlink(entity wp_from, entity wp_to);
+
void waypoint_removelink(entity from, entity to);
int waypoint_getlinknum(entity from, entity to);
bool waypoint_islinked(entity from, entity to);
float waypoint_loadall();
bool waypoint_load_links();
-#define waypoint_load_links_hardwired() waypoint_load_or_remove_links_hardwired(false)
-#define waypoint_remove_links_hardwired() waypoint_load_or_remove_links_hardwired(true)
-void waypoint_load_or_remove_links_hardwired(bool removal_mode);
+void waypoint_load_hardwiredlinks();
-void waypoint_spawn_fromeditor(entity pl);
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp);
entity waypoint_spawn(vector m1, vector m2, float f);
entity waypoint_spawnpersonal(entity this, vector position);
void waypoint_spawnforitem_force(entity e, vector org) { }
void waypoint_spawnforteleporter(entity e, vector destination, float timetaken, entity tracetest_ent) { }
void waypoint_spawnforteleporter_wz(entity e, entity tracetest_ent) { }
-void waypoint_spawn_fromeditor(entity pl) { }
+void waypoint_spawn_fromeditor(entity pl, bool at_crosshair, bool is_jump_wp, bool is_crouch_wp, bool is_support_wp) { }
entity waypoint_spawn(vector m1, vector m2, float f) { return NULL; }
#endif
SetResource(this.personal, RES_HEALTH, max(1, GetResource(this, RES_HEALTH)));
SetResource(this.personal, RES_ARMOR, GetResource(this, RES_ARMOR));
STAT(WEAPONS, this.personal) = STAT(WEAPONS, this);
+ STAT(BUFFS, this.personal) = STAT(BUFFS, this);
+ STAT(BUFF_TIME, this.personal) = STAT(BUFF_TIME, this);
this.personal.items = this.items;
this.personal.pauserotarmor_finished = this.pauserotarmor_finished;
this.personal.pauserothealth_finished = this.pauserothealth_finished;
SetResource(this, RES_HEALTH, GetResource(this.personal, RES_HEALTH));
SetResource(this, RES_ARMOR, GetResource(this.personal, RES_ARMOR));
STAT(WEAPONS, this) = STAT(WEAPONS, this.personal);
+ STAT(BUFFS, this) = STAT(BUFFS, this.personal);
+ STAT(BUFF_TIME, this) = STAT(BUFF_TIME, 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;
#include "../common/mapobjects/teleporters.qh"
#include "../common/mapobjects/target/spawnpoint.qh"
#include <common/mapobjects/trigger/counter.qh>
+#include <common/mapobjects/trigger/swamp.qh>
#include "../common/vehicles/all.qh"
this.pauseregen_finished += f;
}
- this.damageforcescale = 2;
+ this.damageforcescale = autocvar_g_player_damageforcescale;
this.death_time = 0;
this.respawn_flags = 0;
this.respawn_time = 0;
STAT(REVIVE_PROGRESS, this) = 0;
this.revival_time = 0;
+ // TODO: we can't set these in the PlayerSpawn hook since the target code is called before it!
+ STAT(BUFFS, this) = 0;
+ STAT(BUFF_TIME, this) = 0;
+
this.air_finished = time + 12;
this.waterlevel = WATERLEVEL_NONE;
this.watertype = CONTENT_EMPTY;
if(this.conveyor)
IL_REMOVE(g_conveyed, this);
this.conveyor = NULL; // prevent conveyors at the previous location from moving a freshly spawned player
+ if(this.swampslug)
+ delete(this.swampslug);
+ this.in_swamp = false;
STAT(HUD, this) = HUD_NORMAL;
this.event_damage = PlayerDamage;
string versionmessage = GetClientVersionMessage(this);
string s = strcat(versionmessage, "^8\n^8\nmatch type is ^1", gamemode_name, "^8\n");
- s = strcat(s, "^8\nCurrent map: ^2", GetMapname(), "^8\n");
if(modifications != "")
s = strcat(s, "^8\nactive modifications: ^3", modifications, "^8\n");
this.effects = spectatee.effects & EFMASK_CHEAP; // eat performance
SetResourceExplicit(this, RES_HEALTH, GetResource(spectatee, RES_HEALTH));
CS(this).impulse = 0;
+ this.disableclientprediction = 1; // no need to run prediction on a spectator
this.items = spectatee.items;
STAT(LAST_PICKUP, this) = STAT(LAST_PICKUP, spectatee);
STAT(HIT_TIME, this) = STAT(HIT_TIME, spectatee);
{
if(PHYS_INPUT_BUTTON_INFO(this)) // BUTTON_INFO hides initial MOTD
CS(this).motd_actived_time = -2; // wait until BUTTON_INFO gets released
- else if(CS(this).motd_actived_time == -2 || IS_PLAYER(this) || IS_SPEC(this))
+ else if (CS(this).motd_actived_time == -2)
{
// instantly hide MOTD
CS(this).motd_actived_time = 0;
Kill_Notification(NOTIF_ONE_ONLY, this, MSG_CENTER, CPID_MOTD);
}
+ else if (IS_PLAYER(this) || IS_SPEC(this))
+ {
+ // FIXME occasionally for some reason MOTD never goes away
+ // delay MOTD removal a little bit in the hope it fixes this bug
+ if (CS(this).motd_actived_time == -1) // MOTD marked to fade away as soon as client becomes player or spectator
+ CS(this).motd_actived_time = -(5 + floor(random() * 10)); // add small delay
+ else //if (CS(this).motd_actived_time < -2)
+ CS(this).motd_actived_time++;
+ }
}
}
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
.entity weaponentity = weaponentities[slot];
+ if(WEP_CVAR(vortex, charge_always))
+ W_Vortex_Charge(this, weaponentity, frametime);
W_WeaponFrame(this, weaponentity);
}
if (this.netname == "" || this.netname != CS(this).netname_previous)
{
bool assume_unchanged = (CS(this).netname_previous == "");
- if (autocvar_name_maxlength > 0 && strlennocol(this.netname) > autocvar_name_maxlength)
+ if (autocvar_sv_name_maxlength > 0 && strlennocol(this.netname) > autocvar_sv_name_maxlength)
{
- int new_length = textLengthUpToLength(this.netname, autocvar_name_maxlength, strlennocol);
+ int new_length = textLengthUpToLength(this.netname, autocvar_sv_name_maxlength, strlennocol);
this.netname = strzone(strcat(substring(this.netname, 0, new_length), "^7"));
- sprint(this, sprintf("Warning: your name is longer than %d characters, it has been truncated.\n", autocvar_name_maxlength));
+ sprint(this, sprintf("Warning: your name is longer than %d characters, it has been truncated.\n", autocvar_sv_name_maxlength));
assume_unchanged = false;
// stuffcmd(this, strcat("name ", this.netname, "\n")); // maybe?
}
ATTRIB(Client, cvar_cl_weaponimpulsemode, int, this.cvar_cl_weaponimpulsemode);
ATTRIB(Client, cvar_g_xonoticversion, string, this.cvar_g_xonoticversion);
ATTRIB(Client, autoswitch, bool, this.autoswitch);
+ ATTRIB(Client, cvar_cl_casings, bool, this.cvar_cl_casings);
ATTRIB(Client, cvar_cl_dodging_timeout, float, this.cvar_cl_dodging_timeout);
ATTRIB(Client, cvar_cl_multijump, bool, this.cvar_cl_multijump);
ATTRIB(Client, cvar_cl_accuracy_data_share, bool, this.cvar_cl_accuracy_data_share);
{
if (argv(1) == "spawn")
{
+ string s = argv(2);
if (!IS_PLAYER(caller))
sprint(caller, "ERROR: this command works only if you are player\n");
else
- waypoint_spawn_fromeditor(caller);
+ waypoint_spawn_fromeditor(caller, (s == "crosshair"), (s == "jump"), (s == "crouch"), (s == "support"));
return;
}
else if (argv(1) == "remove")
waypoint_remove_fromeditor(caller);
return;
}
+ else if (argv(1) == "hardwire")
+ {
+ string s = argv(2);
+ waypoint_start_hardwiredlink(caller, (s == "crosshair"));
+ return;
+ }
+ else if (argv(1) == "lock")
+ {
+ waypoint_lock(caller);
+ return;
+ }
else if (argv(1) == "unreachable")
{
if (!IS_PLAYER(caller))
case CMD_REQUEST_USAGE:
{
sprint(caller, "\nUsage:^3 cmd wpeditor action\n");
- sprint(caller, " Where 'action' can be: spawn, remove, unreachable, saveall, relinkall,\n");
- sprint(caller, " symorigin get|set\n");
- sprint(caller, " symorigin get|set p1 p2 ... pX\n");
- sprint(caller, " symaxis get|set p1 p2\n");
- sprint(caller, " where p1 p2 ... pX are positions \"x y z\" (z can be omitted)\n");
- sprint(caller, " symorigin and symaxis commands are useful to determine origin/axis of symmetry"
- " on maps without ctf flags or where flags aren't perfectly symmetrical\n");
+ sprint(caller, " Where 'action' can be:\n");
+ sprint(caller, " ^5spawn^7: spawns a waypoint at player's position\n");
+ sprint(caller, " ^5remove^7: removes player's nearest waypoint\n");
+ sprint(caller, " ^5unreachable^7: reveals waypoints and items unreachable from the current position and spawnpoints without a nearest waypoint\n");
+ sprint(caller, " ^5saveall^7: saves all waypoints and links to file\n");
+ sprint(caller, " ^5relinkall^7: relinks all waypoints as if they were respawned\n");
+ sprint(caller, " ^5spawn crosshair^7: spawns a waypoint at crosshair's position\n");
+ sprint(caller, " ^7 in general useful to create special and hardwired links with ease from existing waypoints\n");
+ sprint(caller, " ^7 in particular it's the only way to create custom jumppad waypoints (spawn another waypoint to create destination))\n");
+ sprint(caller, " ^5spawn jump^7: spawns a jump waypoint (place it at least 60 qu before jump start, spawn another waypoint to create destination)\n");
+ sprint(caller, " ^5spawn crouch^7: spawns a crouch waypoint (it links only to very close waypoints)\n");
+ sprint(caller, " ^5spawn support^7: spawns a support waypoint (spawn another waypoint to create destination from which all incoming links are removed)\n");
+ sprint(caller, " ^7 useful to replace links to problematic jumppad/teleport waypoints\n");
+ sprint(caller, " ^5hardwire^7: marks the nearest waypoint as origin of a new hardwired link (spawn another waypoint over an existing one to create destination)\n");
+ sprint(caller, " ^5hardwire crosshair^7: marks the waypoint at crosshair instead of the nearest waypoint\n");
+ sprint(caller, " ^5lock^7: locks link display of the aimed waypoint (unlocks if no waypoint is found at crosshair's position)\n");
+ sprint(caller, " ^5symorigin get|set\n");
+ sprint(caller, " ^5symorigin get|set p1 p2 ... pX\n");
+ sprint(caller, " ^5symaxis get|set p1 p2\n");
+ sprint(caller, " ^7 where p1 p2 ... pX are positions (\"x y z\", z can be omitted) that you know are perfectly symmetrical"
+ " so you can determine origin/axis of symmetry of maps without ctf flags or where flags aren't perfectly symmetrical\n");
+ sprint(caller, " See 'wpeditor_menu' for a selectable list of various commands and useful settings to edit waypoints.\n");
return;
}
}
if (Physics_Valid(command) || command == "default")
{
- stuffcmd(caller, strcat("\nseta cl_physics ", command, "\nsendcvar cl_physics\n"));
+ stuffcmd(caller, strcat("\nseta cl_physics ", command, "\n"));
sprint(caller, strcat("^2Physics set successfully changed to ^3", command, "\n"));
return;
}
case "prespawn": break; // handled by engine in host_cmd.c
case "sentcvar": break; // handled by server in this file
case "spawn": break; // handled by engine in host_cmd.c
+ case "color": case "topcolor": case "bottomcolor": if(teamplay) return; else break; // handled by engine in host_cmd.c
case "c2s": Net_ClientCommand(this, command); return; // handled by net.qh
default:
}
}
+void shuffleteams()
+{
+ if (!teamplay)
+ {
+ LOG_INFO("Can't shuffle teams when currently not playing a team game.");
+ return;
+ }
+
+ FOREACH_CLIENT(IS_PLAYER(it) || it.caplayer, {
+ if (Player_HasRealForcedTeam(it)) {
+ // we could theoretically assign forced players to their teams
+ // and shuffle the rest to fill the empty spots but in practise
+ // either all players or none are gonna have forced teams
+ LOG_INFO("Can't shuffle teams because at least one player has a forced team.");
+ return;
+ }
+ });
+
+ int number_of_teams = 0;
+ entity balance = TeamBalance_CheckAllowedTeams(NULL);
+ for (int i = 1; i <= NUM_TEAMS; ++i)
+ {
+ if (TeamBalance_IsTeamAllowed(balance, i))
+ {
+ number_of_teams = max(i, number_of_teams);
+ }
+ }
+ TeamBalance_Destroy(balance);
+
+ int team_index = 0;
+ FOREACH_CLIENT_RANDOM(IS_PLAYER(it) || it.caplayer, {
+ int target_team_index = team_index + 1;
+ if (Entity_GetTeamIndex(it) != target_team_index)
+ {
+ MoveToTeam(it, target_team_index, 6);
+ }
+ team_index = (team_index + 1) % number_of_teams;
+ });
+
+ bprint("Successfully shuffled the players around randomly.\n");
+}
+
void GameCommand_shuffleteams(int request)
{
switch (request)
{
case CMD_REQUEST_COMMAND:
{
- if (!teamplay)
+ if (shuffleteams_on_reset_map)
{
- LOG_INFO("Can't shuffle teams when currently not playing a team game.");
- return;
+ bprint("Players will be shuffled when this round is over.\n");
+ shuffleteams_on_reset_map = true;
}
-
- FOREACH_CLIENT(IS_PLAYER(it) || it.caplayer, {
- if (Player_HasRealForcedTeam(it)) {
- // we could theoretically assign forced players to their teams
- // and shuffle the rest to fill the empty spots but in practise
- // either all players or none are gonna have forced teams
- LOG_INFO("Can't shuffle teams because at least one player has a forced team.");
- return;
- }
- });
-
- int number_of_teams = 0;
- entity balance = TeamBalance_CheckAllowedTeams(NULL);
- for (int i = 1; i <= NUM_TEAMS; ++i)
- {
- if (TeamBalance_IsTeamAllowed(balance, i))
- {
- number_of_teams = max(i, number_of_teams);
- }
- }
- TeamBalance_Destroy(balance);
-
- int team_index = 0;
- FOREACH_CLIENT_RANDOM(IS_PLAYER(it) || it.caplayer, {
- int target_team_index = team_index + 1;
- if (Entity_GetTeamIndex(it) != target_team_index)
- {
- MoveToTeam(it, target_team_index, 6);
- }
- team_index = (team_index + 1) % number_of_teams;
- });
-
- bprint("Successfully shuffled the players around randomly.\n");
+ else
+ shuffleteams();
return;
}
// Declarations for server side game commands
// =================================================
+bool shuffleteams_on_reset_map;
+void shuffleteams();
+
string GotoMap(string m);
void race_deleteTime(string map, float pos);
round_handler_Reset(game_starttime);
}
+ if (shuffleteams_on_reset_map)
+ {
+ shuffleteams();
+ shuffleteams_on_reset_map = false;
+ }
MUTATOR_CALLHOOK(reset_map_global);
FOREACH_ENTITY_FLOAT_ORDERED(pure_data, false,
#include <common/t_items.qh>
#include <common/mapobjects/triggers.qh>
#include <common/mapobjects/trigger/counter.qh>
+#include <common/mutators/mutator/buffs/buffs.qh>
+#include <common/notifications/all.qh>
#include <common/weapons/_all.qh>
//***********************
{
actor.strength_finished = 0;
actor.invincible_finished = 0;
- STAT(BUFFS, actor) = 0;
+ if(STAT(BUFFS, actor)) // TODO: make a dropbuffs function to handle this
+ {
+ int buffid = buff_FirstFromFlags(STAT(BUFFS, actor)).m_id;
+ Send_Notification(NOTIF_ONE, actor, MSG_MULTI, ITEM_BUFF_DROP, buffid);
+ sound(actor, CH_TRIGGER, SND_BUFF_LOST, VOL_BASE, ATTN_NORM);
+ if(!IS_INDEPENDENT_PLAYER(actor))
+ Send_Notification(NOTIF_ALL_EXCEPT, actor, MSG_INFO, INFO_ITEM_BUFF_LOST, actor.netname, buffid);
+ STAT(BUFFS, actor) = 0;
+ STAT(BUFF_TIME, actor) = 0;
+ }
}
if (!(this.spawnflags & 16))
SetResourceExplicit(this, RES_ARMOR, 100);
else if (it.classname == "item_health_mega")
SetResourceExplicit(this, RES_HEALTH, 200);
+ else if (it.classname == "item_buff") {
+ entity buff = buff_FirstFromFlags(STAT(BUFFS, it));
+ this.netname = cons(this.netname, buff.netname);
+ STAT(BUFF_TIME, this) = it.count;
+ }
+
//remove(it); // removing ents in init functions causes havoc, workaround:
setthink(it, SUB_Remove);
it.nextthink = time;
const int SVC_SETVIEW = 5;
-const int RESPAWN_FORCE = 1;
-const int RESPAWN_SILENT = 2;
-const int RESPAWN_DENY = 4;
+const int RESPAWN_FORCE = BIT(0);
+const int RESPAWN_SILENT = BIT(1);
+const int RESPAWN_DENY = BIT(2);
#define EFMASK_CHEAP (EF_ADDITIVE | EF_DOUBLESIDED | EF_FULLBRIGHT | EF_NODEPTHTEST | EF_NODRAW | EF_NOGUNBOB | EF_NOSHADOW | EF_LOWPRECISION | EF_SELECTABLE | EF_TELEPORT_BIT)
.float cvar_cl_allow_uid2name;
.float cvar_cl_allow_uidtracking;
+.bool cvar_cl_allow_uidranking;
.string stored_netname;
string gamemode_name;
void FixIntermissionClient(entity e);
void FixClientCvars(entity e);
-// WEAPONTODO: remove this
-//WepSet weaponsInMap;
-
.float respawn_countdown; // next number to count
float bot_waypoints_for_items;
bool radar_showennemies;
-#ifdef PROFILING
-float client_cefc_accumulator;
-float client_cefc_accumulatortime;
-#endif
-
.float weapon_load[Weapons_MAX];
.int ammo_none; // used by the reloading system, must always be 0
.int clip_load;
UpdateFrags(attacker, f);
}
-.entity kh_next;
-
string AppendItemcodes(string s, entity player)
{
for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
s = strcat(s, "S");
if(time < player.invincible_finished)
s = strcat(s, "I");
- if(player.flagcarried != NULL)
- s = strcat(s, "F");
if(PHYS_INPUT_BUTTON_CHAT(player))
s = strcat(s, "T");
- if(player.kh_next)
- s = strcat(s, "K");
+ // TODO: include these codes as a flag on the item itself
+ MUTATOR_CALLHOOK(LogDeath_AppendItemCodes, player, s);
+ s = M_ARGV(1, string);
return s;
}
}
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)
+ float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity)
// Returns total damage applies to creatures
{
entity targ;
force = force * (finaldmg / coredamage) * forceintensity;
hitloc = nearest;
- if(deathtype & WEP_BLASTER.m_id)
- force *= WEP_CVAR_BOTH(blaster, !(deathtype & HITTYPE_SECONDARY), force_zscale);
+ // apply special scaling along the z axis if set
+ // NOTE: 0 value is not allowed for compatibility, in the case of weapon cvars not being set
+ if(forcezscale)
+ force.z *= forcezscale;
if(targ != directhitentity)
{
float RadiusDamage(entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity)
{
- return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad, cantbe, mustbe, false, forceintensity, deathtype, weaponentity, directhitentity);
+ return RadiusDamageForSource(inflictor, (inflictor.origin + (inflictor.mins + inflictor.maxs) * 0.5), inflictor.velocity, attacker, coredamage, edgedamage, rad,
+ cantbe, mustbe, false, forceintensity, 1, deathtype, weaponentity, directhitentity);
}
bool Heal(entity targ, entity inflictor, float amount, float limit)
void Damage (entity targ, entity inflictor, entity attacker, float damage, int deathtype, .entity weaponentity, vector hitloc, vector force);
float RadiusDamage_running;
-float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity);
+float RadiusDamageForSource (entity inflictor, vector inflictororigin, vector inflictorvelocity, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float inflictorselfdamage, float forceintensity, float forcezscale, int deathtype, .entity weaponentity, entity directhitentity);
// Returns total damage applies to creatures
float RadiusDamage (entity inflictor, entity attacker, float coredamage, float edgedamage, float rad, entity cantbe, entity mustbe, float forceintensity, int deathtype, .entity weaponentity, entity directhitentity);
#include "../lib/warpzone/common.qh"
#include "../lib/warpzone/server.qh"
-.int state;
-
/*============================================
Wazat's Xonotic Grappling Hook
============================================*/
-.float hook_length;
-
void RemoveGrapplingHooks(entity pl)
{
if(pl.move_movetype == MOVETYPE_FLY)
// (note: you can change the hook impulse #'s to whatever you please)
.float hook_time;
+.float hook_length;
+
const float HOOK_FIRING = BIT(0);
const float HOOK_REMOVING = BIT(1);
const float HOOK_PULLING = BIT(2);
const float HOOK_RELEASING = BIT(3);
const float HOOK_WAITING_FOR_RELEASE = BIT(4);
.float hook_state;
+.int state;
void GrappleHookInit();
vector hook_shotorigin[4];
+
BADCVAR("g_race_qualifying_timelimit");
BADCVAR("g_race_qualifying_timelimit_override");
BADCVAR("g_runematch");
+ BADCVAR("g_shootfromeye");
BADCVAR("g_snafu");
BADCVAR("g_tdm");
BADCVAR("g_tdm_teams");
BADCVAR("g_physics_predictall");
BADCVAR("g_piggyback");
BADCVAR("g_playerclip_collisions");
+ BADCVAR("g_spawn_alloweffects");
BADCVAR("g_tdm_point_leadlimit");
BADCVAR("g_tdm_point_limit");
BADCVAR("leadlimit_and_fraglimit");
BADCVAR("g_grappling_hook");
BADCVAR("g_jetpack");
+ // temporary for testing
+ // TODO remove before 0.8.3 release
+ BADCVAR("g_ca_weaponarena");
+ BADCVAR("g_freezetag_weaponarena");
+ BADCVAR("g_lms_weaponarena");
+
#undef BADPRESUFFIX
#undef BADPREFIX
#undef BADCVAR
continue;
if(argv(0) == "cd")
{
+ string trackname = argv(2);
LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:");
- LOG_INFO(" cdtrack ", argv(2));
+ LOG_INFO(" cdtrack ", trackname);
+ if (cvar_value_issafe(trackname))
+ {
+ string newstuff = strcat(clientstuff, "cd loop \"", trackname, "\"\n");
+ strcpy(clientstuff, newstuff);
+ }
}
else if(argv(0) == "fog")
{
string Map_Current_Name;
// NOTE: this now expects the map list to be already tokenized and the count in Map_Count
-float GetMaplistPosition()
+int GetMaplistPosition()
{
- float pos, idx;
- string map;
-
- map = GetMapname();
- idx = autocvar_g_maplist_index;
+ string map = GetMapname();
+ int idx = autocvar_g_maplist_index;
if(idx >= 0)
+ {
if(idx < Map_Count)
+ {
if(map == argv(idx))
+ {
return idx;
+ }
+ }
+ }
- for(pos = 0; pos < Map_Count; ++pos)
+ for(int pos = 0; pos < Map_Count; ++pos)
+ {
if(map == argv(pos))
return pos;
+ }
// resume normal maplist rotation if current map is not in g_maplist
return idx;
LOG_TRACE(checkwp_msg, ": has waypoints");
}
+ if(autocvar_g_maplist_ignore_sizes)
+ return true;
+
// open map size restriction file
string opensize_msg = strcat("opensize ", map);
float fh = fopen(strcat("maps/", map, ".sizes"), FILE_READ);
void Maplist_Init()
{
- Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
- float i;
- for (i = 0; i < Map_Count; ++i)
- if (Map_Check(i, 2))
- break;
+ float i = Map_Count = 0;
+ if(autocvar_g_maplist != "")
+ {
+ Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
+ for (i = 0; i < Map_Count; ++i)
+ {
+ if (Map_Check(i, 2))
+ break;
+ }
+ }
+
if (i == Map_Count)
{
bprint( "Maplist contains no usable maps! Resetting it to default map list.\n" );
cvar_set("g_maplist", MapInfo_ListAllAllowedMaps(MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags() | MAPINFO_FLAG_NOAUTOMAPLIST));
if(autocvar_g_maplist_shuffle)
ShuffleMaplist();
- localcmd("\nmenu_cmd sync\n");
+ if(!server_is_dedicated)
+ localcmd("\nmenu_cmd sync\n");
Map_Count = tokenizebyseparator(autocvar_g_maplist, " ");
}
if(Map_Count == 0)
string GetNextMap()
{
- float nextMap;
-
Maplist_Init();
- nextMap = -1;
+ float nextMap = -1;
if(nextMap == -1)
if(autocvar_g_maplist_shuffle > 0)
return;
alreadychangedlevel = true;
- string nextMap;
-
- nextMap = GetNextMap();
+ string nextMap = GetNextMap();
if(nextMap == "")
error("Everything is broken - cannot find a next map. Please report this to the developers.");
Map_Goto(reinit);
IMPULSE(waypoint_here_crosshair)
{
- WarpZone_crosshair_trace(this);
+ WarpZone_crosshair_trace_plusvisibletriggers(this);
entity wp = WaypointSprite_DeployFixed(WP_Here, false, this, trace_endpos, RADARICON_HERE);
if (wp) WaypointSprite_Ping(wp);
sprint(this, "HERE spawned at crosshair\n");
REPLICATE(cvar_cl_allow_uid2name, bool, "cl_allow_uid2name");
+REPLICATE(cvar_cl_allow_uidranking, bool, "cl_allow_uidranking");
+
REPLICATE(cvar_cl_autoscreenshot, int, "cl_autoscreenshot");
REPLICATE(cvar_cl_autotaunt, float, "cl_autotaunt");
{
string s = string_null;
+ if (f == 0)
+ LOG_INFO("Warning: requesting cvar values is deprecated. Client should send them automatically using REPLICATE.\n");
+
if (f > 0)
s = strcat1(argv(f));
return p.netname;
}
-float want_weapon(entity weaponinfo, float allguns) // WEAPONTODO: what still needs done?
+float want_weapon(entity weaponinfo, float allguns)
{
- int i = weaponinfo.m_id;
int d = 0;
bool allow_mutatorblocked = false;
- if(!i)
+ if(!weaponinfo.m_id)
return 0;
bool mutator_returnvalue = MUTATOR_CALLHOOK(WantWeapon, weaponinfo, d, allguns, allow_mutatorblocked);
allow_mutatorblocked = M_ARGV(3, bool);
if(allguns)
- d = boolean(weaponinfo.spawnflags & WEP_FLAG_NORMAL);
+ d = boolean((weaponinfo.spawnflags & WEP_FLAG_NORMAL) && !(weaponinfo.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK)));
else if(!mutator_returnvalue)
d = !(!weaponinfo.weaponstart);
float t = weaponinfo.weaponstartoverride;
- //print(strcat("want_weapon: ", weaponinfo.netname, " - d: ", ftos(d), ", t: ", ftos(t), ". \n"));
+ //LOG_INFOF("want_weapon: %s - d: %d t: %d\n", weaponinfo.netname, d, t);
// bit order in t:
// 1: want or not
return t;
}
+/// Weapons the player normally starts with outside weapon arena.
+WepSet weapons_start()
+{
+ WepSet ret = '0 0 0';
+ FOREACH(Weapons, it != WEP_Null, {
+ int w = want_weapon(it, false);
+ if (w & 1)
+ ret |= it.m_wepset;
+ });
+ return ret;
+}
+
+WepSet weapons_all()
+{
+ WepSet ret = '0 0 0';
+ FOREACH(Weapons, it != WEP_Null, {
+ if (!(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)))
+ ret |= it.m_wepset;
+ });
+ return ret;
+}
+
+WepSet weapons_devall()
+{
+ WepSet ret = '0 0 0';
+ FOREACH(Weapons, it != WEP_Null,
+ {
+ ret |= it.m_wepset;
+ });
+ return ret;
+}
+
+WepSet weapons_most()
+{
+ WepSet ret = '0 0 0';
+ FOREACH(Weapons, it != WEP_Null, {
+ if ((it.spawnflags & WEP_FLAG_NORMAL) && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK)))
+ ret |= it.m_wepset;
+ });
+ return ret;
+}
+
+void weaponarena_available_all_update(entity this)
+{
+ if (weaponsInMapAll)
+ {
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_start() | (weaponsInMapAll & weapons_all());
+ }
+ else
+ {
+ // if no weapons are available on the map, just fall back to all weapons arena
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_all();
+ }
+}
+
+void weaponarena_available_devall_update(entity this)
+{
+ if (weaponsInMapAll)
+ {
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_start() | weaponsInMapAll;
+ }
+ else
+ {
+ // if no weapons are available on the map, just fall back to devall weapons arena
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_devall();
+ }
+}
+
+void weaponarena_available_most_update(entity this)
+{
+ if (weaponsInMapAll)
+ {
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_start() | (weaponsInMapAll & weapons_most());
+ }
+ else
+ {
+ // if no weapons are available on the map, just fall back to most weapons arena
+ start_weapons = warmup_start_weapons = g_weaponarena_weapons = weapons_most();
+ }
+}
+
void readplayerstartcvars()
{
float i, t;
- string s;
// initialize starting values for players
start_weapons = '0 0 0';
g_weaponarena = 0;
g_weaponarena_weapons = '0 0 0';
- s = cvar_string("g_weaponarena");
+ string s = cvar_string("g_weaponarena");
MUTATOR_CALLHOOK(SetWeaponArena, s);
s = M_ARGV(0, string);
{
g_weaponarena = 1;
g_weaponarena_list = "All Weapons";
- FOREACH(Weapons, it != WEP_Null, {
- if(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED))
- g_weaponarena_weapons |= (it.m_wepset);
- });
+ g_weaponarena_weapons = weapons_all();
}
else if (s == "devall")
{
g_weaponarena = 1;
- g_weaponarena_list = "All Weapons"; // TODO: report as more than just all weapons?
- FOREACH(Weapons, it != WEP_Null,
- {
- g_weaponarena_weapons |= (it.m_wepset);
- });
+ g_weaponarena_list = "Dev All Weapons";
+ g_weaponarena_weapons = weapons_devall();
}
else if (s == "most")
{
g_weaponarena = 1;
g_weaponarena_list = "Most Weapons";
- FOREACH(Weapons, it != WEP_Null, {
- if(!(it.spawnflags & WEP_FLAG_MUTATORBLOCKED) && (it.spawnflags & WEP_FLAG_NORMAL) && !(it.spawnflags & WEP_FLAG_HIDDEN))
- g_weaponarena_weapons |= (it.m_wepset);
- });
+ g_weaponarena_weapons = weapons_most();
+ }
+ else if (s == "all_available")
+ {
+ g_weaponarena = 1;
+ g_weaponarena_list = "All Available Weapons";
+
+ // this needs to run after weaponsInMapAll is initialized
+ InitializeEntity(NULL, weaponarena_available_all_update, INITPRIO_FINDTARGET);
+ }
+ else if (s == "devall_available")
+ {
+ g_weaponarena = 1;
+ g_weaponarena_list = "Dev All Available Weapons";
+
+ // this needs to run after weaponsInMapAll is initialized
+ InitializeEntity(NULL, weaponarena_available_devall_update, INITPRIO_FINDTARGET);
+ }
+ else if (s == "most_available")
+ {
+ g_weaponarena = 1;
+ g_weaponarena_list = "Most Available Weapons";
+
+ // this needs to run after weaponsInMapAll is initialized
+ InitializeEntity(NULL, weaponarena_available_most_update, INITPRIO_FINDTARGET);
}
else if (s == "none")
{
start_ammo_plasma = cvar("g_start_ammo_plasma");
start_ammo_fuel = cvar("g_start_ammo_fuel");
random_start_weapons_count = cvar("g_random_start_weapons_count");
- SetResource(random_start_ammo, RES_SHELLS, cvar(
- "g_random_start_shells"));
- SetResource(random_start_ammo, RES_BULLETS, cvar(
- "g_random_start_bullets"));
- SetResource(random_start_ammo, RES_ROCKETS,
- cvar("g_random_start_rockets"));
- SetResource(random_start_ammo, RES_CELLS, cvar(
- "g_random_start_cells"));
- SetResource(random_start_ammo, RES_PLASMA, cvar(
- "g_random_start_plasma"));
+ SetResource(random_start_ammo, RES_SHELLS, cvar("g_random_start_shells"));
+ SetResource(random_start_ammo, RES_BULLETS, cvar("g_random_start_bullets"));
+ SetResource(random_start_ammo, RES_ROCKETS,cvar("g_random_start_rockets"));
+ SetResource(random_start_ammo, RES_CELLS, cvar("g_random_start_cells"));
+ SetResource(random_start_ammo, RES_PLASMA, cvar("g_random_start_plasma"));
}
- if (warmup_stage)
+ warmup_start_ammo_shells = start_ammo_shells;
+ warmup_start_ammo_nails = start_ammo_nails;
+ warmup_start_ammo_rockets = start_ammo_rockets;
+ warmup_start_ammo_cells = start_ammo_cells;
+ warmup_start_ammo_plasma = start_ammo_plasma;
+ warmup_start_ammo_fuel = start_ammo_fuel;
+ warmup_start_health = start_health;
+ warmup_start_armorvalue = start_armorvalue;
+ warmup_start_weapons = start_weapons;
+ warmup_start_weapons_default = start_weapons_default;
+ warmup_start_weapons_defaultmask = start_weapons_defaultmask;
+
+ if (!g_weaponarena)
{
- warmup_start_ammo_shells = start_ammo_shells;
- warmup_start_ammo_nails = start_ammo_nails;
- warmup_start_ammo_rockets = start_ammo_rockets;
- warmup_start_ammo_cells = start_ammo_cells;
- warmup_start_ammo_plasma = start_ammo_plasma;
- warmup_start_ammo_fuel = start_ammo_fuel;
- warmup_start_health = start_health;
- warmup_start_armorvalue = start_armorvalue;
- warmup_start_weapons = start_weapons;
- warmup_start_weapons_default = start_weapons_default;
- warmup_start_weapons_defaultmask = start_weapons_defaultmask;
-
- if (!g_weaponarena && !g_ca && !g_freezetag)
- {
- warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
- warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
- warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
- warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
- warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
- warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
- warmup_start_health = cvar("g_warmup_start_health");
- warmup_start_armorvalue = cvar("g_warmup_start_armor");
- warmup_start_weapons = '0 0 0';
- warmup_start_weapons_default = '0 0 0';
- warmup_start_weapons_defaultmask = '0 0 0';
- FOREACH(Weapons, it != WEP_Null, {
- int w = want_weapon(it, g_warmup_allguns);
- WepSet s = (it.m_wepset);
- if(w & 1)
- warmup_start_weapons |= s;
- if(w & 2)
- warmup_start_weapons_default |= s;
- if(w & 4)
- warmup_start_weapons_defaultmask |= s;
- });
- }
+ warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
+ warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
+ warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
+ warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
+ warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
+ warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
+ warmup_start_health = cvar("g_warmup_start_health");
+ warmup_start_armorvalue = cvar("g_warmup_start_armor");
+ warmup_start_weapons = '0 0 0';
+ warmup_start_weapons_default = '0 0 0';
+ warmup_start_weapons_defaultmask = '0 0 0';
+ FOREACH(Weapons, it != WEP_Null, {
+ int w = want_weapon(it, g_warmup_allguns);
+ WepSet s = it.m_wepset;
+ if(w & 1)
+ warmup_start_weapons |= s;
+ if(w & 2)
+ warmup_start_weapons_default |= s;
+ if(w & 4)
+ warmup_start_weapons_defaultmask |= s;
+ });
}
if (g_jetpack)
warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
}
- WepSet precache_weapons = start_weapons;
- if (g_warmup_allguns != 1)
- precache_weapons |= warmup_start_weapons;
- FOREACH(Weapons, it != WEP_Null, {
- if(precache_weapons & (it.m_wepset))
- it.wr_init(it);
- });
-
start_ammo_shells = max(0, start_ammo_shells);
start_ammo_nails = max(0, start_ammo_nails);
start_ammo_rockets = max(0, start_ammo_rockets);
start_ammo_cells = max(0, start_ammo_cells);
start_ammo_plasma = max(0, start_ammo_plasma);
start_ammo_fuel = max(0, start_ammo_fuel);
- SetResource(random_start_ammo, RES_SHELLS, max(0,
- GetResource(random_start_ammo, RES_SHELLS)));
- SetResource(random_start_ammo, RES_BULLETS, max(0,
- GetResource(random_start_ammo, RES_BULLETS)));
- SetResource(random_start_ammo, RES_ROCKETS, max(0,
- GetResource(random_start_ammo, RES_ROCKETS)));
- SetResource(random_start_ammo, RES_CELLS, max(0,
- GetResource(random_start_ammo, RES_CELLS)));
- SetResource(random_start_ammo, RES_PLASMA, max(0,
- GetResource(random_start_ammo, RES_PLASMA)));
+ SetResource(random_start_ammo, RES_SHELLS,
+ max(0, GetResource(random_start_ammo, RES_SHELLS)));
+ SetResource(random_start_ammo, RES_BULLETS,
+ max(0, GetResource(random_start_ammo, RES_BULLETS)));
+ SetResource(random_start_ammo, RES_ROCKETS,
+ max(0, GetResource(random_start_ammo, RES_ROCKETS)));
+ SetResource(random_start_ammo, RES_CELLS,
+ max(0, GetResource(random_start_ammo, RES_CELLS)));
+ SetResource(random_start_ammo, RES_PLASMA,
+ max(0, GetResource(random_start_ammo, RES_PLASMA)));
warmup_start_ammo_shells = max(0, warmup_start_ammo_shells);
warmup_start_ammo_nails = max(0, warmup_start_ammo_nails);
float globhandle, i, n;
string f;
- if(substring(m, -9,5) == "_lod1")
+ if(substring(m, -9, 5) == "_lod1")
return;
- if(substring(m, -9,5) == "_lod2")
+ if(substring(m, -9, 5) == "_lod2")
return;
precache_model(m);
f = strcat(substring(m, 0, -5), "_lod1", substring(m, -4, -1));
MUTATOR_HOOKABLE(GetPressedKeys, EV_GetPressedKeys);
/** is meant to call GetCvars_handle*(get_cvars_s, get_cvars_f, cvarfield, "cvarname") for cvars this mutator needs from the client */
+// NOTE: requesting cvar values (get_cvars_f 0) is deprecated
#define EV_GetCvars(i, o) \
/**/ i(float, get_cvars_f) \
/**/ i(string, get_cvars_s) \
/**/ o(int, MUTATOR_ARGV_0_int) \
/**/
MUTATOR_HOOKABLE(GetPlayerLimit, EV_GetPlayerLimit);
+
+/** include special item codes for a death to the game log */
+#define EV_LogDeath_AppendItemCodes(i, o) \
+ /** player */ i(entity, MUTATOR_ARGV_0_entity) \
+ /** item codes */ i(string, MUTATOR_ARGV_1_string) \
+ /**/ o(string, MUTATOR_ARGV_1_string) \
+ /**/
+MUTATOR_HOOKABLE(LogDeath_AppendItemCodes, EV_LogDeath_AppendItemCodes);
if (time < this.spawnshieldtime && autocvar_g_spawnshield_blockdamage < 1)
damage *= 1 - max(0, autocvar_g_spawnshield_blockdamage);
- if(DEATH_ISWEAPON(deathtype, WEP_TUBA))
+ if(deathtype & HITTYPE_SOUND) // sound based attacks cause bleeding from the ears
{
- // tuba causes blood to come out of the ears
vector ear1, ear2;
vector d;
float f;
#include "../common/mutators/mutator/waypoints/waypointsprites.qh"
IntrusiveList g_race_targets;
-STATIC_INIT(g_race_targets) { g_race_targets = IL_NEW(); }
+IntrusiveList g_racecheckpoints;
+STATIC_INIT(g_race)
+{
+ g_race_targets = IL_NEW();
+ g_racecheckpoints = IL_NEW();
+}
void race_InitSpectator()
{
.float race_respawn_checkpoint;
.entity race_respawn_spotref; // try THIS spawn in case you respawn
-IntrusiveList g_racecheckpoints;
-STATIC_INIT(g_racecheckpoints) { g_racecheckpoints = IL_NEW(); }
-
// definitions for functions used outside race.qc
float race_PreviousCheckpoint(float f);
float race_NextCheckpoint(float f);
#include "../common/constants.qh"
#include <common/net_linked.qh>
#include "../common/teams.qh"
+#include <common/mapinfo.qh>
#include "../common/mapobjects/subs.qh"
#include "../common/mapobjects/target/spawnpoint.qh"
#include "../common/util.qh"
}
}
- if(!found)
+ if(!found && !g_cts)
{
LOG_TRACE("WARNING: spawnpoint at ", vtos(spot.origin), " could not find its target ", spot.target);
return '-1 0 0';
/**
Uniform push from a point
**/
-#define steerlib_push(ent,point) normalize(ent.origin - point)
+#define steerlib_push(ent,point) normalize((ent).origin - point)
/*
vector steerlib_push(entity this, vector point)
{
**/
vector steerlib_arrive(entity this, vector point, float maximal_distance)
{
- float distance = bound(0.001,vlen(this.origin - point),maximal_distance);
+ 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 = bound(0.001,vlen(this.origin - point),maximal_distance);
+ float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
vector direction = normalize(point - this.origin);
- return direction * (1-(distance / maximal_distance));
+ return direction * (1 - (distance / maximal_distance));
}
-vector steerlib_attract2(entity this, vector point, float min_influense,float max_distance,float max_influense)
+vector steerlib_attract2(entity this, vector point, float min_influense, float max_distance, float max_influense)
{
- float distance = bound(0.00001,vlen(this.origin - point),max_distance);
+ float distance = bound(0.00001, vlen(this.origin - point), max_distance);
vector direction = normalize(point - this.origin);
float influense = 1 - (distance / max_distance);
influense = min_influense + (influense * (max_influense - min_influense));
- return direction * influense;
+ return direction * influense;
}
/*
/**
Move away from a point.
**/
-vector steerlib_repell(entity this, vector point,float maximal_distance)
+vector steerlib_repel(entity this, vector point, float maximal_distance)
{
- float distance;
- vector direction;
-
- distance = bound(0.001,vlen(this.origin - point),maximal_distance);
- direction = normalize(this.origin - point);
+ float distance = bound(0.001, vlen(this.origin - point), maximal_distance);
+ vector direction = normalize(this.origin - point);
- return direction * (1-(distance / maximal_distance));
+ return direction * (1 - (distance / maximal_distance));
}
/**
Try to keep at ideal_distance away from point
**/
-vector steerlib_standoff(entity this, vector point,float ideal_distance)
+vector steerlib_standoff(entity this, vector point, float ideal_distance)
{
- float distance;
vector direction;
-
- distance = vlen(this.origin - point);
-
+ float distance = vlen(this.origin - point);
if(distance < ideal_distance)
{
}
/**
- A random heading in a forward halfcicrle
+ A random heading in a forward semicircle
- use like:
- this.target = steerlib_wander(256,32,this.target)
+ usage:
+ this.target = steerlib_wander(256, 32, this.target)
- where range is the cicrle radius and tresh is how close we need to be to pick a new heading.
+ where range is the circle radius and threshold is how close we need to be to pick a new heading.
+ Assumes v_forward is set by makevectors
**/
-vector steerlib_wander(entity this, float range, float tresh, vector oldpoint)
+vector steerlib_wander(entity this, float range, float threshold, vector oldpoint)
{
- vector wander_point;
- wander_point = v_forward - oldpoint;
+ vector wander_point = v_forward - oldpoint;
- if (vdist(wander_point, >, tresh))
+ if (vdist(wander_point, >, threshold))
return oldpoint;
- range = bound(0,range,1);
+ range = bound(0, range, 1);
wander_point = this.origin + v_forward * 128;
wander_point = wander_point + randomvec() * (range * 128) - randomvec() * (range * 128);
}
/**
- Dodge a point. dont work to well.
+ Dodge a point NOTE: doesn't work well
**/
vector steerlib_dodge(entity this, vector point, vector dodge_dir, float min_distance)
{
- float distance;
-
- distance = max(vlen(this.origin - point),min_distance);
+ float distance = max(vlen(this.origin - point), min_distance);
if (min_distance < distance)
return '0 0 0';
- return dodge_dir * (min_distance/distance);
+ return dodge_dir * (min_distance / distance);
}
/**
Group will move towards the unified direction while keeping close to eachother.
**/
.float flock_id;
-vector steerlib_flock(entity this, float _radius, float standoff,float separation_force,float flock_force)
+vector steerlib_flock(entity this, float _radius, float standoff, float separation_force, float flock_force)
{
- entity flock_member;
vector push = '0 0 0', pull = '0 0 0';
- float ccount = 0;
+ int ccount = 0;
- flock_member = findradius(this.origin, _radius);
+ entity flock_member = findradius(this.origin, _radius);
while(flock_member)
{
if(flock_member != this)
if(flock_member.flock_id == this.flock_id)
{
++ccount;
- push = push + (steerlib_repell(this, flock_member.origin,standoff) * separation_force);
+ push = push + (steerlib_repel(this, flock_member.origin,standoff) * separation_force);
pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
}
flock_member = flock_member.chain;
Group will move towards the unified direction while keeping close to eachother.
xy only version (for ground movers).
**/
-vector steerlib_flock2d(entity this, float _radius, float standoff,float separation_force,float flock_force)
+vector steerlib_flock2d(entity this, float _radius, float standoff, float separation_force, float flock_force)
{
- entity flock_member;
vector push = '0 0 0', pull = '0 0 0';
- float ccount = 0;
+ int ccount = 0;
- flock_member = findradius(this.origin,_radius);
+ entity flock_member = findradius(this.origin,_radius);
while(flock_member)
{
if(flock_member != this)
if(flock_member.flock_id == this.flock_id)
{
++ccount;
- push = push + (steerlib_repell(this, flock_member.origin, standoff) * separation_force);
+ push = push + (steerlib_repel(this, flock_member.origin, standoff) * separation_force);
pull = pull + (steerlib_arrive(this, flock_member.origin + flock_member.velocity, _radius) * flock_force);
}
flock_member = flock_member.chain;
/**
All members want to be in the center, and keep away from eachother.
- The furtehr form the center the more they want to be there.
+ The further from the center the more they want to be there.
This results in a aligned movement (?!) much like flocking.
**/
-vector steerlib_swarm(entity this, float _radius, float standoff,float separation_force,float swarm_force)
+vector steerlib_swarm(entity this, float _radius, float standoff, float separation_force, float swarm_force)
{
- entity swarm_member;
vector force = '0 0 0', center = '0 0 0';
- float ccount = 0;
-
- swarm_member = findradius(this.origin,_radius);
+ int ccount = 0;
+ entity swarm_member = findradius(this.origin,_radius);
while(swarm_member)
{
if(swarm_member.flock_id == this.flock_id)
{
++ccount;
center = center + swarm_member.origin;
- force = force + (steerlib_repell(this, swarm_member.origin,standoff) * separation_force);
+ force = force + (steerlib_repel(this, swarm_member.origin,standoff) * separation_force);
}
swarm_member = swarm_member.chain;
}
Run four tracelines in a forward funnel, bias each diretion negative if something is found there.
You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
**/
-vector steerlib_traceavoid(entity this, float pitch,float length)
+vector steerlib_traceavoid(entity this, float pitch, float length)
{
- vector vup_left,vup_right,vdown_left,vdown_right;
- float fup_left,fup_right,fdown_left,fdown_right;
- vector upwish,downwish,leftwish,rightwish;
- vector v_left,v_down;
-
+ vector v_left = v_right * -1;
+ vector v_down = v_up * -1;
- v_left = v_right * -1;
- v_down = v_up * -1;
-
- vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
- traceline(this.origin, this.origin + vup_left,MOVE_NOMONSTERS,this);
- fup_left = trace_fraction;
+ vector vup_left = (v_forward + (v_left * pitch + v_up * pitch)) * length;
+ traceline(this.origin, this.origin + vup_left, MOVE_NOMONSTERS, this);
+ float fup_left = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
- traceline(this.origin,this.origin + vup_right ,MOVE_NOMONSTERS,this);
- fup_right = trace_fraction;
+ vector vup_right = (v_forward + (v_right * pitch + v_up * pitch)) * length;
+ traceline(this.origin, this.origin + vup_right, MOVE_NOMONSTERS, this);
+ float fup_right = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
- traceline(this.origin,this.origin + vdown_left,MOVE_NOMONSTERS,this);
- fdown_left = trace_fraction;
+ vector vdown_left = (v_forward + (v_left * pitch + v_down * pitch)) * length;
+ traceline(this.origin, this.origin + vdown_left, MOVE_NOMONSTERS, this);
+ float fdown_left = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
- traceline(this.origin,this.origin + vdown_right,MOVE_NOMONSTERS,this);
- fdown_right = trace_fraction;
+ vector vdown_right = (v_forward + (v_right * pitch + v_down * pitch)) * length;
+ traceline(this.origin, this.origin + vdown_right, MOVE_NOMONSTERS, this);
+ float fdown_right = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- upwish = v_up * (fup_left + fup_right);
- downwish = v_down * (fdown_left + fdown_right);
- leftwish = v_left * (fup_left + fdown_left);
- rightwish = v_right * (fup_right + fdown_right);
+ vector upwish = v_up * (fup_left + fup_right);
+ vector downwish = v_down * (fdown_left + fdown_right);
+ vector leftwish = v_left * (fup_left + fdown_left);
+ vector rightwish = v_right * (fup_right + fdown_right);
- return (upwish+leftwish+downwish+rightwish) * 0.25;
+ return (upwish + leftwish + downwish + rightwish) * 0.25;
}
/**
Steer towards the direction least obstructed.
Run tracelines in a forward trident, bias each direction negative if something is found there.
+ You need to call makevectors() (or equivalent) before this function to set v_forward and v_right
**/
vector steerlib_traceavoid_flat(entity this, float pitch, float length, vector vofs)
{
- vector vt_left, vt_right,vt_front;
- float f_left, f_right,f_front;
- vector leftwish, rightwish,frontwish, v_left;
+ vector v_left = v_right * -1;
- v_left = v_right * -1;
-
-
- vt_front = v_forward * length;
+ vector vt_front = v_forward * length;
traceline(this.origin + vofs, this.origin + vofs + vt_front,MOVE_NOMONSTERS,this);
- f_front = trace_fraction;
+ float f_front = trace_fraction;
- vt_left = (v_forward + (v_left * pitch)) * length;
+ vector vt_left = (v_forward + (v_left * pitch)) * length;
traceline(this.origin + vofs, this.origin + vofs + vt_left,MOVE_NOMONSTERS,this);
- f_left = trace_fraction;
+ float f_left = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- vt_right = (v_forward + (v_right * pitch)) * length;
+ vector vt_right = (v_forward + (v_right * pitch)) * length;
traceline(this.origin + vofs, this.origin + vofs + vt_right ,MOVE_NOMONSTERS,this);
- f_right = trace_fraction;
+ float f_right = trace_fraction;
//te_lightning1(NULL,this.origin, trace_endpos);
- leftwish = v_left * f_left;
- rightwish = v_right * f_right;
- frontwish = v_forward * f_front;
+ vector leftwish = v_left * f_left;
+ vector rightwish = v_right * f_right;
+ vector frontwish = v_forward * f_front;
return normalize(leftwish + rightwish + frontwish);
}
//#define BEAMSTEER_VISUAL
-float beamsweep(entity this, vector from, vector dir,float length, float step,float step_up, float step_down)
+float beamsweep(entity this, vector from, vector dir, float length, float step, float step_up, float step_down)
{
- float i;
- vector a, b, u, d;
-
- u = '0 0 1' * step_up;
- d = '0 0 1' * step_down;
+ vector u = '0 0 1' * step_up;
+ vector d = '0 0 1' * step_down;
traceline(from + u, from - d,MOVE_NORMAL,this);
if(trace_fraction == 1.0)
if(!location_isok(trace_endpos, false, false))
return 0;
- a = trace_endpos;
- for(i = 0; i < length; i += step)
+ vector a = trace_endpos;
+ for(int i = 0; i < length; i += step)
{
- b = a + dir * step;
+ vector b = a + dir * step;
tracebox(a + u,'-4 -4 -4','4 4 4', b + u,MOVE_NORMAL,this);
if(trace_fraction != 1.0)
return i / length;
vector steerlib_beamsteer(entity this, vector dir, float length, float step, float step_up, float step_down)
{
- float bm_forward, bm_right, bm_left,p;
- vector vr,vl;
-
dir.z *= 0.15;
- vr = vectoangles(dir);
- //vr_x *= -1;
+ vector vr = vectoangles(dir);
+ //vr.x *= -1;
tracebox(this.origin + '0 0 1' * step_up, this.mins, this.maxs, ('0 0 1' * step_up) + this.origin + (dir * length), MOVE_NOMONSTERS, this);
if(trace_fraction == 1.0)
{
- //te_lightning1(this,this.origin,this.origin + (dir * length));
+ //te_lightning1(this,this.origin,this.origin + (dir * length));
return dir;
}
makevectors(vr);
- bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
+ float bm_forward = beamsweep(this, this.origin, v_forward, length, step, step_up, step_down);
vr = normalize(v_forward + v_right * 0.125);
- vl = normalize(v_forward - v_right * 0.125);
+ vector vl = normalize(v_forward - v_right * 0.125);
- bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
- bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
+ float bm_right = beamsweep(this, this.origin, vr, length, step, step_up, step_down);
+ float bm_left = beamsweep(this, this.origin, vl, length, step, step_up, step_down);
-
- p = bm_left + bm_right;
+ float p = bm_left + bm_right;
if(p == 2)
{
//te_lightning1(this,this.origin + '0 0 32',this.origin + '0 0 32' + vr * length);
vl = vl * bm_left;
return normalize(vr + vl);
-
}
#include "../lib/warpzone/common.qh"
#include "../lib/warpzone/server.qh"
-.float lastground;
-.int state;
-
void CreatureFrame_hotliquids(entity this)
{
- if (this.dmgtime < time)
+ if (this.dmgtime >= time)
{
- this.dmgtime = time + autocvar_g_balance_contents_damagerate;
+ return;
+ }
- if (this.flags & FL_PROJECTILE)
- {
- if (this.watertype == CONTENT_LAVA)
- Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
- else if (this.watertype == CONTENT_SLIME)
- Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
- }
- else
+ this.dmgtime = time + autocvar_g_balance_contents_damagerate;
+
+ if (this.flags & FL_PROJECTILE)
+ {
+ if (this.watertype == CONTENT_LAVA)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ else if (this.watertype == CONTENT_SLIME)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_projectiledamage * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ }
+ else
+ {
+ if (this.watertype == CONTENT_LAVA)
{
- if (this.watertype == CONTENT_LAVA)
+ if (this.watersound_finished < time)
{
- if (this.watersound_finished < time)
- {
- this.watersound_finished = time + 0.5;
- sound (this, CH_PLAYER_SINGLE, SND_LAVA, VOL_BASE, ATTEN_NORM);
- }
- Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
- if(autocvar_g_balance_contents_playerdamage_lava_burn)
- Fire_AddDamage(this, NULL, autocvar_g_balance_contents_playerdamage_lava_burn * this.waterlevel, autocvar_g_balance_contents_playerdamage_lava_burn_time * this.waterlevel, DEATH_LAVA.m_id);
+ this.watersound_finished = time + 0.5;
+ sound (this, CH_PLAYER_SINGLE, SND_LAVA, VOL_BASE, ATTEN_NORM);
}
- else if (this.watertype == CONTENT_SLIME)
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_lava * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_LAVA.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ if(autocvar_g_balance_contents_playerdamage_lava_burn)
+ Fire_AddDamage(this, NULL, autocvar_g_balance_contents_playerdamage_lava_burn * this.waterlevel, autocvar_g_balance_contents_playerdamage_lava_burn_time * this.waterlevel, DEATH_LAVA.m_id);
+ }
+ else if (this.watertype == CONTENT_SLIME)
+ {
+ if (this.watersound_finished < time)
{
- if (this.watersound_finished < time)
- {
- this.watersound_finished = time + 0.5;
- sound (this, CH_PLAYER_SINGLE, SND_SLIME, VOL_BASE, ATTEN_NORM);
- }
- Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ this.watersound_finished = time + 0.5;
+ sound (this, CH_PLAYER_SINGLE, SND_SLIME, VOL_BASE, ATTEN_NORM);
}
+ Damage (this, NULL, NULL, autocvar_g_balance_contents_playerdamage_slime * autocvar_g_balance_contents_damagerate * this.waterlevel, DEATH_SLIME.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
}
}
void CreatureFrame_FallDamage(entity this)
{
- if(!IS_VEHICLE(this) && !(this.flags & FL_PROJECTILE)) // vehicles don't get falling damage
- if(this.velocity || this.oldvelocity) // moving or has moved
+ if(IS_VEHICLE(this) || (this.flags & FL_PROJECTILE))
+ return; // vehicles and projectiles don't receive fall damage
+ if(!(this.velocity || this.oldvelocity))
+ return; // if the entity hasn't moved and isn't moving, then don't do anything
+
+ // check for falling damage
+ float velocity_len = vlen(this.velocity);
+ bool have_hook = false;
+ for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
{
- // check for falling damage
- float velocity_len = vlen(this.velocity);
- bool have_hook = false;
- for(int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
+ .entity weaponentity = weaponentities[slot];
+ if(this.(weaponentity).hook && this.(weaponentity).hook.state)
{
- .entity weaponentity = weaponentities[slot];
- if(this.(weaponentity).hook && this.(weaponentity).hook.state)
- {
- have_hook = true;
- break;
- }
+ have_hook = true;
+ break;
}
- if(!have_hook)
- {
- float dm = vlen(this.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
- if (IS_DEAD(this))
- dm = (dm - autocvar_g_balance_falldamage_deadminspeed) * autocvar_g_balance_falldamage_factor;
- else
- dm = min((dm - autocvar_g_balance_falldamage_minspeed) * autocvar_g_balance_falldamage_factor, autocvar_g_balance_falldamage_maxdamage);
- if (dm > 0)
- Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
- }
-
- if(autocvar_g_maxspeed > 0 && velocity_len > autocvar_g_maxspeed)
- Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
+ if(!have_hook)
+ {
+ float dm = vlen(this.oldvelocity) - velocity_len; // dm is now the velocity DECREASE. Velocity INCREASE should never cause a sound or any damage.
+ if (IS_DEAD(this))
+ dm = (dm - autocvar_g_balance_falldamage_deadminspeed) * autocvar_g_balance_falldamage_factor;
+ else
+ dm = min((dm - autocvar_g_balance_falldamage_minspeed) * autocvar_g_balance_falldamage_factor, autocvar_g_balance_falldamage_maxdamage);
+ if (dm > 0)
+ Damage (this, NULL, NULL, dm, DEATH_FALL.m_id, DMG_NOWEP, this.origin, '0 0 0');
+ }
+
+ if(autocvar_g_maxspeed > 0 && velocity_len > autocvar_g_maxspeed)
+ Damage (this, NULL, NULL, 100000, DEATH_SHOOTING_STAR.m_id, DMG_NOWEP, this.origin, '0 0 0');
}
void CreatureFrame_All()
bool expr_evaluate(string s);
+#ifdef PROFILING
+float client_cefc_accumulator;
+float client_cefc_accumulatortime;
+#endif
+
/*
==================
main
return out;
}
-void weapon_defaultspawnfunc(entity this, Weapon e)
+void weapon_defaultspawnfunc(entity this, Weapon wpn)
{
- Weapon wpn = e;
- e = wpn = wpn.m_spawnfunc_hookreplace(wpn, this);
+ wpn = wpn.m_spawnfunc_hookreplace(wpn, this);
this.classname = wpn.m_canonical_spawnfunc;
if (!Item_IsLoot(this) && !this.m_isreplaced)
{
- if (e.spawnflags & WEP_FLAG_MUTATORBLOCKED)
+ if (wpn.spawnflags & WEP_FLAG_MUTATORBLOCKED)
{
LOG_WARNF("Attempted to spawn a mutator-blocked weapon rejected: prvm_edict server %i", this);
startitem_failed = true;
return;
}
- string s = W_Apply_Weaponreplace(e.netname);
- MUTATOR_CALLHOOK(SetWeaponreplace, this, e, s);
+ string s = W_Apply_Weaponreplace(wpn.netname);
+ MUTATOR_CALLHOOK(SetWeaponreplace, this, wpn, s);
s = M_ARGV(2, string);
if (s == "")
{
}
}
+ if(!Item_IsLoot(this))
+ weaponsInMapAll |= WepSet_FromWeapon(wpn);
+
if (!Item_IsDefinitionAllowed(wpn.m_pickup))
{
delete(this);
void FireRailgunBullet (entity this, .entity weaponentity, vector start, vector end, float bdamage, float bforce, float mindist, float maxdist, float halflifedist, float forcehalflifedist, int deathtype)
{
- entity pseudoprojectile = NULL;
-
vector dir = normalize(end - start);
- float length = vlen(end - start);
vector force = dir * bforce;
// go a little bit into the wall because we need to hit this wall later
it.solid = it.railgunhitsolidbackup;
});
- // spawn a temporary explosion entity for RadiusDamage calls
- //explosion = spawn();
+ // Find all players the beam passed close by (even those hit)
+ float length = vlen(endpoint - start);
+ entity pseudoprojectile = NULL;
+ FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != this, {
+ // not when spectating the shooter
+ if (IS_SPEC(it) && it.enemy == this) continue;
- // Find all non-hit players the beam passed close by
- if(deathtype == WEP_VAPORIZER.m_id || deathtype == WEP_VORTEX.m_id) // WEAPONTODO
- {
- FOREACH_CLIENT(IS_REAL_CLIENT(it) && it != this, {
- if(!it.railgunhit)
- if(!(IS_SPEC(it) && it.enemy == this))
- {
- msg_entity = it;
- // nearest point on the beam
- vector beampos = start + dir * bound(0, (msg_entity.origin - start) * dir, length);
+ // nearest point on the beam
+ vector beampos = start + dir * bound(0, (it.origin - start) * dir, length);
- float f = bound(0, 1 - vlen(beampos - msg_entity.origin) / 512, 1);
- if(f <= 0)
- continue;
+ if(!pseudoprojectile)
+ pseudoprojectile = spawn(); // we need this so the sound uses the "entchannel4" volume
- if(!pseudoprojectile)
- pseudoprojectile = spawn(); // we need this so the sound uses the "entchannel4" volume
- soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASE * f, ATTEN_NONE);
- }
- });
-
- if(pseudoprojectile)
- delete(pseudoprojectile);
- }
+ msg_entity = it;
+ // we want this to be very loud when close but fall off quickly -> using max base volume and high attenuation
+ soundtoat(MSG_ONE, pseudoprojectile, beampos, CH_SHOTS, SND(NEXWHOOSH_RANDOM()), VOL_BASEVOICE, ATTEN_IDLE);
+ });
+ if(pseudoprojectile)
+ delete(pseudoprojectile);
// find all the entities the railgun hit and hurt them
IL_EACH(g_railgunhit, it.railgunhit,
{
// removal from the list is handled below
- // get the details we need to call the damage function
- vector hitloc = it.railgunhitloc;
-
float foff = ExponentialFalloff(mindist, maxdist, halflifedist, it.railgundistance);
float ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, it.railgundistance);
// apply the damage
if (it.takedamage)
- Damage (it, this, this, bdamage * foff, deathtype, weaponentity, hitloc, it.railgunforce * ffs);
-
- // create a small explosion to throw gibs around (if applicable)
- //setorigin(explosion, hitloc);
- //RadiusDamage (explosion, this, 10, 0, 50, NULL, NULL, 300, deathtype);
+ Damage(it, this, this, bdamage * foff, deathtype, weaponentity, it.railgunhitloc, it.railgunforce * ffs);
it.railgunhitloc = '0 0 0';
it.railgunhitsolidbackup = SOLID_NOT;
Weapon wep = this.owner.(weaponentity).m_weapon;
if (wep) this.glowmod = weaponentity_glowmod(wep, this.owner, this.owner.clientcolors, this.owner.(weaponentity));
this.colormap = this.owner.colormap;
+ this.skin = w_ent.skin;
CSQCMODEL_AUTOUPDATE(this);
}
exec physicsXDF.cfg
// general gameplay
-// set g_jump_grunt 1 // just no
-set g_shootfromcenter 1 // hit where you point at with the crosshair (almost so, no shooteye because it's really ugly)
-set g_balance_kill_antispam 0
-set g_forced_respawn 1
+// g_jump_grunt 1 // just no
+g_shootfromcenter 1 // hit where you point at with the crosshair (almost so, no shooteye because it's really ugly)
+g_balance_kill_antispam 0
+g_forced_respawn 1
// g_playerclip_collisions 0 // do not check playerclips
-set g_powerups 0 // set to -1 or patch xonotic
-set g_spawnpoints_auto_move_out_of_solid 1
-set g_start_delay 3
-set g_use_ammunition 0 "if set to 0 all weapons have unlimited ammunition"
-set g_weapon_stay 1 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
-set teamplay_mode 2 // friendly fire and self damage
-set sv_vote_nospectators 1
-set timelimit_override 20
-set g_buffs_cooldown_respawn 0.1
+g_powerups 0 // set to -1 or patch xonotic
+g_spawnpoints_auto_move_out_of_solid 1
+g_start_delay 3
+g_use_ammunition 0 "if set to 0 all weapons have unlimited ammunition"
+g_weapon_stay 1 "1: ghost weapons can be picked up too but give no ammo, 2: ghost weapons refill ammo to one pickup size, thrown guns have no ammo"
+teamplay_mode 2 // friendly fire and self damage
+sv_vote_nospectators 1
+timelimit_override 20
+g_buffs_cooldown_respawn 0.1
+g_buffs_randomize 0
// game mode settings
-set g_cts_finish_kill_delay 2
-set g_cts_respawn_delay 0
-set g_cts_selfdamage 0
+g_cts_finish_kill_delay 2
+g_cts_selfdamage 0
exec balance-xpm.cfg
// general gameplay
-set g_norecoil 1
-set g_shootfromeye 1 // hit where you point at with the crosshair (promoders don't care about ugliness)
-set g_balance_kill_antispam 0
-set g_forced_respawn 1
-set teamplay_mode 2 // friendly fire and self damage
-set sv_vote_nospectators 1
-set g_chat_nospectators 2
-set g_warmup 1
-set g_warmup_limit 0
-set g_balance_teams 0
-set g_spawnshieldtime 0
-set g_spawn_furthest 1
-set sv_autoscreenshot 1
-set sv_ready_restart 1
-set sv_ready_restart_after_countdown 1
-set g_monsters 0
-set g_turrets 0
-set g_vehicles 0
-set sv_showspectators 0
-set sv_taunt 0
+g_norecoil 1
+g_shootfromeye 1 // hit where you point at with the crosshair (promoders don't care about ugliness)
+g_balance_kill_antispam 0
+g_forced_respawn 1
+teamplay_mode 2 // friendly fire and self damage
+sv_vote_nospectators 1
+g_chat_nospectators 2
+g_warmup 1
+g_warmup_limit 0
+g_balance_teams 0
+g_spawnshieldtime 0
+g_spawn_furthest 1
+sv_autoscreenshot 1
+sv_ready_restart 1
+sv_ready_restart_after_countdown 1
+g_monsters 0
+g_turrets 0
+g_vehicles 0
+sv_showspectators 0
+sv_taunt 0
exec randomitems-overkill.cfg
if_dedicated exec help-overkill.cfg
-// general gameplay
-set g_overkill 1
+g_overkill 1
+
+g_use_ammunition 0
// hack - eventually, we should be able to choose overkill models in menu like for vanilla
-set sv_defaultcharacter 1
-set sv_defaultplayermodel "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-set sv_defaultplayermodel_red "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
-set sv_defaultplayermodel_blue "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-set sv_defaultplayermodel_yellow "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
-set sv_defaultplayermodel_pink "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
-
-set g_respawn_ghosts 0
-
-set g_nades 1
-set g_nades_nade_small 1
-set g_nades_spread 0
-set g_nades_nade_refire 10
-set g_nades_nade_newton_style 2
-
-set g_dodging 1
-set sv_dodging_wall_dodging 1
-
-set g_spawn_near_teammate "!g_assault !g_freezetag"
-set g_spawn_near_teammate_ignore_spawnpoint 1
-set g_spawnshieldtime 0.5
-set g_respawn_delay_forced 2
-
-set g_lms_start_armor 100
+sv_defaultcharacter 1
+sv_defaultplayermodel "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+sv_defaultplayermodel_red "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
+sv_defaultplayermodel_blue "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+sv_defaultplayermodel_yellow "models/ok_player/okrobot1.dpm models/ok_player/okrobot2.dpm models/ok_player/okrobot3.dpm models/ok_player/okrobot4.dpm"
+sv_defaultplayermodel_pink "models/ok_player/okmale1.dpm models/ok_player/okmale2.dpm models/ok_player/okmale3.dpm models/ok_player/okmale4.dpm"
+
+g_fullbrightplayers 1
+g_respawn_ghosts 0
+
+g_nades 1
+g_nades_nade_small 1
+g_nades_spread 0
+g_nades_nade_refire 10
+g_nades_nade_newton_style 2
+
+g_dodging 1
+sv_dodging_wall_dodging 1
+
+g_spawn_near_teammate "!g_assault !g_freezetag"
+g_spawn_near_teammate_ignore_spawnpoint 1
+g_spawnshieldtime 0.5
+g_respawn_delay_forced 2
+
+g_buffs_resistance_blockpercent 0.5
--- /dev/null
+// open this quick menu with: quickmenu file "" wpeditor.txt
+"Spawn" "wpeditor spawn"
+"Remove" "wpeditor remove"
+"Save all" "wpeditor saveall"
+"Spawn at crosshair" "wpeditor spawn crosshair"
+"Spawn jump" "wpeditor spawn jump"
+"Spawn crouch" "wpeditor spawn crouch"
+"Spawn support" "wpeditor spawn support"
+"Hardwire/Unhw at crosshair" "wpeditor hardwire crosshair"
+"Hardwire/Unhardwire" "wpeditor hardwire"
+"Lock/Unlock" "wpeditor lock"
+"Relink all" "wpeditor relinkall"
+"Find unreachable" "wpeditor unreachable"
+"Show help in console" "cmd help wpeditor"
+"Settings"
+ "Waypoint editor" "toggle g_waypointeditor"
+ "On screen console messages" "toggle con_notify 4 0"
+ "Bot in map" "toggle bot_number"
+ "Bots can't fire" "toggle bot_nofire"
+ "Show bot's path to goal" "toggle bot_debug_goalstack"
+ "Show tracewalk path" "toggle bot_debug_tracewalk"
+ "No time limit" "timelimit 0"
+ "Cheats" "toggle sv_cheats"
+ "God mode on/off" "god"
+ "Fly mode on/off" "fly"
+"Settings"
\ No newline at end of file
// if you want to reset your client to defaults, it's probably a better idea to delete (parts of) config.cfg and restart
-// changes a cvar and reports it to the server (for the menu to notify the
-// server about changes)
+// changes a cvar and reports it to the server (for the client to notify the server about changes)
+// DEPRECATED, cvars can be set in the client code to be sent automatically (using REPLICATE)
alias setreport "set \"$1\" \"$2\" ; sendcvar \"$1\""
seta cl_firststart "" "how many times the client has been run"
v_gamma 1
viewsize 100
bgmvolume 1
-volume 0.5
// fullscreen 1024x768x32bit
vid_bitsperpixel 32
vid_fullscreen 1
cl_movement_track_canjump 0
cl_stairsmoothspeed 200
+alias wpeditor_menu "quickmenu file \"\" wpeditor.txt"
+
alias g_waypointeditor_spawn "wpeditor spawn"
alias g_waypointeditor_remove "wpeditor remove"
alias g_waypointeditor_relinkall "wpeditor relinkall"
r_glsl_offsetmapping_reliefmapping 0
r_glsl_offsetmapping_scale 0.02
-scr_conalpha 1
-scr_conbrightness 0.2
scr_screenshot_jpeg 1
scr_screenshot_jpeg_quality 0.9
seta g_waypointsprite_turrets 1 "disable turret waypoints"
seta g_waypointsprite_turrets_maxdist 5000 "max distance for turret waypoints"
seta g_waypointsprite_turrets_text 0 "show the turret's name in the waypoint"
+seta g_waypointsprite_turrets_onlyhurt 0 "only show the turret waypoint for a short period after being hurt"
seta g_waypointsprite_uppercase 1
seta g_waypointsprite_text 0 "Always show text instead of icons, setting this to 0 will still use text if the icon is unavailable"
seta g_waypointsprite_iconsize 32
alias _gl_flashblend_update_11 "gl_flashblend 0"
alias gl_flashblend_update "_gl_flashblend_update_$r_shadow_realtime_dlight$r_showsurfaces"
-set cl_handicap 1 "multiplies damage received and divides damage dealt NOTE: reconnect or use 'sendcvar cl_handicap' to update the choice."
+set cl_handicap 1 "multiplies damage received and divides damage dealt"
-seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such. (client setting) NOTE: reconnect or use sendcvar command to update the choice."
+seta cl_clippedspectating 1 "movement collision for spectators so that you can't pass through walls and such"
seta cl_autoscreenshot 1 "Take a screenshot upon the end of a match... 0 = Disable completely, 1 = Allow sv_autoscreenshot to take a screenshot when requested, 2 = Always take an autoscreenshot anyway."
scr_conalpha3factor 1
scr_conalphafactor 0.8
scr_conbrightness 0.35
-scr_conforcewhiledisconnected 1
scr_conscroll2_x 0.11
scr_conscroll2_y 0.2
scr_conscroll3_x 0
// uid2name
seta cl_allow_uid2name -1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid2name (allows showing your name in race rankings for instance)"
seta cl_allow_uidtracking 1 "-1 = ask if the player wants to disable/enable this feature, 0 = disable, 1 = enable uid tracking (allows associating your data with your player ID)"
-// FIXME set to -1 before release, once we have a dialog for this!
+seta cl_allow_uidranking 1 "0 = disable, 1 = enable uid ranking (allows statistics like elo to rank you in leaderboards)"
// polygonoffset for submodel SUCKS SUCKS SUCKS (only a hack for quake1, we don't need that)
r_polygonoffset_submodel_offset 0
+// most common prefixes (currently not used consistently - especially g_ and sv_):
+// cl_ client
+// g_ gameplay
+// r_ renderer
+// sv_ server administration, should not affect gameplay
+// _ temporary, private or internal cvar - should not be changed manually, sometimes used in scripts
+
// Xonotic version (formatted for machines)
// used to determine if a client version is compatible
// this doesn't have to be bumped with every release
// note that it doesn't reset all server cvars,
// some are shared with the client and so are left in xonotic-common.cfg
-set name_maxlength 64 "max player name length (not counting color codes) allowed by the server"
+set sv_name_maxlength 64 "max player name length (not counting color codes) allowed by the server"
// taunts and voices
set sv_taunt 1 "allow taunts on the server"
set g_pickup_respawntime_scaling_reciprocal 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `reciprocal` (with `offset` and `linear` set to 0) can be used to achieve a constant number of items spawned *per player*"
set g_pickup_respawntime_scaling_offset 0 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `offset` offsets the curve left or right - the results are not intuitive and I recommend plotting the respawn time and the number of items per player to see what's happening"
set g_pickup_respawntime_scaling_linear 1 "Multiply respawn time by `reciprocal / (p + offset) + linear` where `p` is the current number of players, takes effect with 2 or more players present, `linear` can be used to simply scale the respawn time linearly"
-set g_weaponarena "0" "put in a list of weapons to enable a weapon arena mode, or try \"all\" or \"most\""
+set g_weaponarena "0" "put in a list of weapons to enable a weapon arena mode, or try \"all\", \"most\", \"all_available\" or \"most_available\" (available only gives the weapon if the map normally has it as a pickup item)"
set g_weaponarena_random "0" "if set to a number, only that weapon count is given on every spawn (randomly)"
set g_weaponarena_random_with_blaster "1" "additionally, always provide the blaster in random weapon arena games"
set g_spawnpoints_auto_move_out_of_solid 0 "if set to 1 you will see a warning if a spawn point was placed inside a solid"
set g_maplist_selectrandom 0 "if 1, a random map will be chosen as next map - DEPRECATED in favor of g_maplist_shuffle"
set g_maplist_shuffle 1 "new randomization method: like selectrandom, but avoid playing the same maps in short succession. This works by taking out the first element and inserting it into g_maplist with a bias to the end of the list"
set g_maplist_check_waypoints 0 "when 1, maps are skipped if there currently are bots, but the map has no waypoints"
+set g_maplist_ignore_sizes 0 "when 1, all maps are shown in the map list regardless of player count"
set g_items_mindist 4000 "starting distance for the fading of items"
set g_items_maxdist 4500 "maximum distance at which an item can be viewed, after which it will be invisible"
set g_cloaked 0 "display all players mostly invisible"
set g_player_alpha 1 "default opacity of players"
set g_player_brightness 0 "set to 2 for brighter players"
+set g_player_damageforcescale 2 "push multiplier of attacks against players"
set g_balance_cloaked_alpha 0.25 "opacity of cloaked players"
set g_playerclip_collisions 1 "0 = disable collision testing against playerclips, might be useful on some defrag maps"